mirror of
https://github.com/apache/superset.git
synced 2024-09-12 00:29:39 -04:00
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 <evan@preset.io> * update styles and svg Co-authored-by: Evan Rusackas <evan@preset.io>
This commit is contained in:
parent
a4f44255aa
commit
0e9898cb96
25
superset-frontend/images/empty-query.svg
Normal file
25
superset-frontend/images/empty-query.svg
Normal file
@ -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>
|
After Width: | Height: | Size: 1.7 KiB |
@ -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;
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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;
|
||||
|
@ -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>;
|
||||
}
|
||||
|
||||
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};
|
||||
export const CardStyles = styled.div`
|
||||
cursor: pointer;
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.holder {
|
||||
margin: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
.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`
|
||||
svg {
|
||||
margin-left: ${({ theme }) => theme.gridUnit * 10}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>
|
||||
|
Loading…
Reference in New Issue
Block a user