You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2020/11/30 19:54:06 UTC
[incubator-superset] branch master updated: feat(welcome): add SQL
snippets to saved queries card (#11678)
This is an automated email from the ASF dual-hosted git repository.
rusackas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new 0e9898c feat(welcome): add SQL snippets to saved queries card (#11678)
0e9898c is described below
commit 0e9898cb96d1b16ac666e0f83433e02ba01dda18
Author: Phillip Kelley-Dotson <pk...@yahoo.com>
AuthorDate: Mon Nov 30 11:53:12 2020 -0800
feat(welcome): add SQL snippets to saved queries card (#11678)
* update savedqueries card to new layout
* update card
* update card to latest mock
* update empty state
* remove fallback
* fix query statement
* update card styles
* remove double import
* use fallbackurl prop for emptystate
* update line lenth
* Update superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
Co-authored-by: Evan Rusackas <ev...@preset.io>
* update styles and svg
Co-authored-by: Evan Rusackas <ev...@preset.io>
---
superset-frontend/images/empty-query.svg | 25 +++++
.../src/components/ListViewCard/index.tsx | 4 +-
.../src/views/CRUD/data/query/QueryList.tsx | 15 +--
superset-frontend/src/views/CRUD/utils.tsx | 17 ++-
.../src/views/CRUD/welcome/SavedQueries.tsx | 120 +++++++++++++++------
5 files changed, 131 insertions(+), 50 deletions(-)
diff --git a/superset-frontend/images/empty-query.svg b/superset-frontend/images/empty-query.svg
new file mode 100644
index 0000000..be72857
--- /dev/null
+++ b/superset-frontend/images/empty-query.svg
@@ -0,0 +1,25 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<svg width="458" height="146" viewBox="0 0 458 146" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M17 21C17 18.7909 18.7909 17 21 17H125C127.209 17 129 18.7909 129 21V29C129 31.2091 127.209 33 125 33H21C18.7909 33 17 31.2091 17 29V21Z" fill="#ECEEF2"/>
+<path d="M17 45C17 42.7909 18.7909 41 21 41H223C225.209 41 227 42.7909 227 45V53C227 55.2091 225.209 57 223 57H21C18.7909 57 17 55.2091 17 53V45Z" fill="#ECEEF2"/>
+<path d="M21 65C18.7909 65 17 66.7909 17 69V77C17 79.2091 18.7909 81 21 81H172C174.209 81 176 79.2091 176 77V69C176 66.7909 174.209 65 172 65H21Z" fill="#ECEEF2"/>
+<path d="M17 93C17 90.7909 18.7909 89 21 89H286C288.209 89 290 90.7909 290 93V101C290 103.209 288.209 105 286 105H21C18.7909 105 17 103.209 17 101V93Z" fill="#ECEEF2"/>
+<path d="M21 113C18.7909 113 17 114.791 17 117V125C17 127.209 18.7909 129 21 129H73C75.2091 129 77 127.209 77 125V117C77 114.791 75.2091 113 73 113H21Z" fill="#ECEEF2"/>
+</svg>
diff --git a/superset-frontend/src/components/ListViewCard/index.tsx b/superset-frontend/src/components/ListViewCard/index.tsx
index 26030e0..94f14a8 100644
--- a/superset-frontend/src/components/ListViewCard/index.tsx
+++ b/superset-frontend/src/components/ListViewCard/index.tsx
@@ -145,7 +145,7 @@ const SkeletonActions = styled(Skeleton.Button)`
const paragraphConfig = { rows: 1, width: 150 };
interface CardProps {
- title: React.ReactNode;
+ title?: React.ReactNode;
url?: string;
imgURL?: string;
imgFallbackURL?: string;
@@ -155,7 +155,7 @@ interface CardProps {
titleRight?: React.ReactNode;
coverLeft?: React.ReactNode;
coverRight?: React.ReactNode;
- actions: React.ReactNode | null;
+ actions?: React.ReactNode | null;
rows?: number | string;
avatar?: string;
cover?: React.ReactNode | null;
diff --git a/superset-frontend/src/views/CRUD/data/query/QueryList.tsx b/superset-frontend/src/views/CRUD/data/query/QueryList.tsx
index 4ed20de..ed9329fd 100644
--- a/superset-frontend/src/views/CRUD/data/query/QueryList.tsx
+++ b/superset-frontend/src/views/CRUD/data/query/QueryList.tsx
@@ -20,7 +20,7 @@ import React, { useMemo, useState, useCallback } from 'react';
import { SupersetClient, t, styled } from '@superset-ui/core';
import moment from 'moment';
-import { createErrorHandler } from 'src/views/CRUD/utils';
+import { createErrorHandler, shortenSQL } from 'src/views/CRUD/utils';
import withToasts from 'src/messageToasts/enhancers/withToasts';
import { useListViewResource } from 'src/views/CRUD/hooks';
import SubMenu, { SubMenuProps } from 'src/components/Menu/SubMenu';
@@ -38,6 +38,7 @@ import { QueryObject } from 'src/views/CRUD/types';
import QueryPreviewModal from './QueryPreviewModal';
const PAGE_SIZE = 25;
+const SQL_PREVIEW_MAX_LINES = 4;
const TopAlignedListView = styled(ListView)<ListViewProps<QueryObject>>`
table .table-cell {
@@ -52,15 +53,7 @@ const StyledSyntaxHighlighter = styled(SyntaxHighlighter)`
text-overflow: ellipsis;
white-space: nowrap;
`;
-const SQL_PREVIEW_MAX_LINES = 4;
-function shortenSQL(sql: string) {
- let lines: string[] = sql.split('\n');
- if (lines.length >= SQL_PREVIEW_MAX_LINES) {
- lines = lines.slice(0, SQL_PREVIEW_MAX_LINES);
- lines.push('...');
- }
- return lines.join('\n');
-}
+
interface QueryListProps {
addDangerToast: (msg: string, config?: any) => any;
addSuccessToast: (msg: string, config?: any) => any;
@@ -298,7 +291,7 @@ function QueryList({ addDangerToast, addSuccessToast }: QueryListProps) {
onClick={() => setQueryCurrentlyPreviewing(original)}
>
<StyledSyntaxHighlighter language="sql" style={github}>
- {shortenSQL(original.sql)}
+ {shortenSQL(original.sql, SQL_PREVIEW_MAX_LINES)}
</StyledSyntaxHighlighter>
</div>
);
diff --git a/superset-frontend/src/views/CRUD/utils.tsx b/superset-frontend/src/views/CRUD/utils.tsx
index 2cc9999..e22310d 100644
--- a/superset-frontend/src/views/CRUD/utils.tsx
+++ b/superset-frontend/src/views/CRUD/utils.tsx
@@ -264,22 +264,31 @@ export function handleDashboardDelete(
);
}
+export function shortenSQL(sql: string, maxLines: number) {
+ let lines: string[] = sql.split('\n');
+ if (lines.length >= maxLines) {
+ lines = lines.slice(0, maxLines);
+ lines.push('...');
+ }
+ return lines.join('\n');
+}
+
const breakpoints = [576, 768, 992, 1200];
export const mq = breakpoints.map(bp => `@media (max-width: ${bp}px)`);
export const CardContainer = styled.div`
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(31%, max-content));
+ grid-template-columns: repeat(auto-fit, minmax(31%, 31%));
${[mq[3]]} {
- grid-template-columns: repeat(auto-fit, minmax(31%, max-content));
+ grid-template-columns: repeat(auto-fit, minmax(31%, 31%));
}
${[mq[2]]} {
- grid-template-columns: repeat(auto-fit, minmax(48%, max-content));
+ grid-template-columns: repeat(auto-fit, minmax(48%, 48%));
}
${[mq[1]]} {
- grid-template-columns: repeat(auto-fit, minmax(50%, max-content));
+ grid-template-columns: repeat(auto-fit, minmax(50%, 80%));
}
grid-gap: ${({ theme }) => theme.gridUnit * 8}px;
justify-content: left;
diff --git a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
index 6de2f3c..6232ec1 100644
--- a/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
+++ b/superset-frontend/src/views/CRUD/welcome/SavedQueries.tsx
@@ -18,6 +18,9 @@
*/
import React, { useState } from 'react';
import { t, SupersetClient, styled } from '@superset-ui/core';
+import SyntaxHighlighter from 'react-syntax-highlighter/dist/cjs/light';
+import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql';
+import github from 'react-syntax-highlighter/dist/cjs/styles/hljs/github';
import withToasts from 'src/messageToasts/enhancers/withToasts';
import { Dropdown, Menu } from 'src/common/components';
import { useListViewResource, copyQueryLink } from 'src/views/CRUD/hooks';
@@ -30,9 +33,11 @@ import {
IconContainer,
CardContainer,
createErrorHandler,
- CardStyles,
+ shortenSQL,
} from '../utils';
+SyntaxHighlighter.registerLanguage('sql', sql);
+
const PAGE_SIZE = 3;
interface Query {
@@ -45,6 +50,8 @@ interface Query {
description?: string;
end_time?: string;
label?: string;
+ changed_on_delta_humanized?: string;
+ sql?: string | null;
}
interface SavedQueriesProps {
@@ -57,19 +64,51 @@ interface SavedQueriesProps {
mine: Array<Query>;
}
+export const CardStyles = styled.div`
+ cursor: pointer;
+ a {
+ text-decoration: none;
+ }
+ .ant-card-cover {
+ border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
+ & > div {
+ height: 171px;
+ }
+ }
+ .gradient-container > div {
+ background-size: contain;
+ background-repeat: no-repeat;
+ background-position: center;
+ background-color: ${({ theme }) => theme.colors.secondary.light3};
+ display: inline-block;
+ width: 100%;
+ height: 179px;
+ background-repeat: no-repeat;
+ vertical-align: middle;
+ }
+`;
+
const QueryData = styled.div`
- display: flex;
- flex-direction: row;
- justify-content: flex-start;
- border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
- .title {
- font-weight: ${({ theme }) => theme.typography.weights.normal};
- color: ${({ theme }) => theme.colors.grayscale.light1};
+ svg {
+ margin-left: ${({ theme }) => theme.gridUnit * 10}px;
}
- .holder {
- margin: ${({ theme }) => theme.gridUnit * 2}px;
+ .query-title {
+ padding: ${({ theme }) => theme.gridUnit * 2 + 2}px;
+ font-size: ${({ theme }) => theme.typography.sizes.l}px;
}
`;
+
+const QueryContainer = styled.div`
+ pre {
+ height: ${({ theme }) => theme.gridUnit * 40}px;
+ border: none !important;
+ background-color: ${({ theme }) =>
+ theme.colors.grayscale.light5} !important;
+ overflow: hidden;
+ padding: ${({ theme }) => theme.gridUnit * 4}px !important;
+ }
+`;
+
const SavedQueries = ({
user,
addDangerToast,
@@ -259,35 +298,50 @@ const SavedQueries = ({
key={q.id}
>
<ListViewCard
- imgFallbackURL=""
imgURL=""
url={`/superset/sqllab?savedQueryId=${q.id}`}
title={q.label}
- rows={q.rows}
- description={t('Last run ', q.end_time)}
+ imgFallbackURL="/static/assets/images/empty-query.svg"
+ description={t('Last run %s', q.changed_on_delta_humanized)}
cover={
- <QueryData>
- <div className="holder">
- <div className="title">{t('Tables')}</div>
- <div>{q?.sql_tables?.length}</div>
- </div>
- <div className="holder">
- <div className="title">{t('Datasource Name')}</div>
- <div>{q?.sql_tables && q.sql_tables[0]?.table}</div>
- </div>
- </QueryData>
+ q?.sql?.length ? (
+ <QueryContainer>
+ <SyntaxHighlighter
+ language="sql"
+ lineProps={{
+ style: {
+ color: 'black',
+ wordBreak: 'break-all',
+ whiteSpace: 'pre-wrap',
+ },
+ }}
+ style={github}
+ wrapLines
+ lineNumberStyle={{
+ display: 'none',
+ }}
+ showLineNumbers={false}
+ >
+ {shortenSQL(q.sql, 25)}
+ </SyntaxHighlighter>
+ </QueryContainer>
+ ) : (
+ false
+ )
}
actions={
- <ListViewCard.Actions
- onClick={e => {
- e.stopPropagation();
- e.preventDefault();
- }}
- >
- <Dropdown overlay={renderMenu(q)}>
- <Icon name="more-horiz" />
- </Dropdown>
- </ListViewCard.Actions>
+ <QueryData>
+ <ListViewCard.Actions
+ onClick={e => {
+ e.stopPropagation();
+ e.preventDefault();
+ }}
+ >
+ <Dropdown overlay={renderMenu(q)}>
+ <Icon name="more-horiz" />
+ </Dropdown>
+ </ListViewCard.Actions>
+ </QueryData>
}
/>
</CardStyles>