From fa7ecca485b0a69887509711c3997cde5a3fc955 Mon Sep 17 00:00:00 2001 From: Gabriel Dutra Date: Tue, 10 Nov 2020 09:59:15 -0300 Subject: [PATCH] Frontend updates from internal fork (#5259) * DynamicComponent for QuerySourceAlerts * General Settings updates * Dynamic Date[Range] updates * EmptyState updates * Query and SchemaBrowser updates * Adjust page headers and add disablePublish * Policy updates * Separate Home FavoritesList component * Update FormatQuery * Autolimit frontend fixes * Misc updates * Keep registering of QuerySourceDropdown * Undo changes in DynamicComponent * Change sql-formatter package.json syntax * Allow opening help trigger in new tab * Don't run npm commands as root in Dockerfile * Cypress: Remove extra execute query --- Dockerfile | 11 +- client/.eslintrc.js | 12 ++- .../app/assets/images/db-logos/databricks.png | Bin 2562 -> 2884 bytes client/app/assets/less/redash/query.less | 1 + .../ApplicationLayout/index.jsx | 26 ++--- .../ApplicationArea/ErrorMessage.jsx | 2 +- client/app/components/HelpTrigger.jsx | 29 +++--- client/app/components/Link.jsx | 2 +- .../users => }/components/UserGroups.jsx | 14 +-- client/app/components/UserGroups.less | 7 ++ .../dynamic-parameters/DynamicButton.less | 6 ++ .../DynamicDateRangePicker.jsx | 4 +- .../dynamic-parameters/DynamicParameters.less | 3 +- .../components/empty-state/EmptyState.d.ts | 7 +- .../app/components/empty-state/EmptyState.jsx | 66 +++++++----- .../components/empty-state/empty-state.less | 21 ++++ .../items-list/components/ItemsTable.jsx | 20 +++- .../components/queries/ApiKeyDialog/index.jsx | 3 +- .../app/components/queries/SchemaBrowser.jsx | 29 ++++-- .../databricks/DatabricksSchemaBrowser.jsx | 4 - .../databricks/useDatabricksSchema.js | 42 ++++++-- client/app/lib/queryFormat.test.js | 56 +++++++++++ client/app/lib/queryFormat.ts | 23 +++++ client/app/lib/utils.js | 52 ++++++++-- client/app/pages/alert/AlertEdit.jsx | 2 + client/app/pages/alert/AlertView.jsx | 2 + .../dashboards/components/DashboardHeader.jsx | 2 +- .../pages/dashboards/hooks/useDashboard.js | 3 +- client/app/pages/home/Home.jsx | 95 +----------------- .../pages/home/components/FavoritesList.jsx | 94 +++++++++++++++++ client/app/pages/queries/QuerySource.jsx | 24 ++++- client/app/pages/queries/QueryView.jsx | 40 ++++---- .../queries/components/QueryPageHeader.jsx | 6 +- .../queries/components/QuerySourceAlerts.jsx | 11 +- .../components/QueryVisualizationTabs.jsx | 9 +- .../pages/queries/hooks/useAutoLimitFlags.js | 8 +- .../app/pages/queries/hooks/useFormatQuery.js | 19 ---- client/app/pages/queries/hooks/useQuery.js | 9 +- .../app/pages/queries/hooks/useQueryFlags.js | 4 +- .../pages/queries/hooks/useUpdateQuery.jsx | 4 +- .../pages/settings/OrganizationSettings.jsx | 80 +++------------ .../AuthSettings/PasswordLoginSettings.jsx | 33 +++--- .../components/AuthSettings/SAMLSettings.jsx | 21 ++-- .../GeneralSettings/BeaconConsentSettings.jsx | 21 ++-- .../GeneralSettings/FeatureFlagsSettings.jsx | 65 +++++++----- .../GeneralSettings/FormatSettings.jsx | 43 ++++---- .../GeneralSettings/PlotlySettings.jsx | 19 ++-- .../pages/settings/components/prop-types.js | 2 + .../settings/hooks/useOrganizationSettings.js | 59 +++++++++++ .../users/components/ReadOnlyUserProfile.jsx | 2 +- .../pages/users/components/UserInfoForm.jsx | 2 +- client/app/services/dashboard.js | 4 +- client/app/services/policy/DefaultPolicy.js | 10 +- client/app/services/query.js | 19 +--- .../integration/embed/share_embed_spec.js | 1 - package-lock.json | 13 +++ package.json | 2 + .../chart/Renderer/initChart.js | 2 + 58 files changed, 746 insertions(+), 424 deletions(-) rename client/app/{pages/users => }/components/UserGroups.jsx (50%) create mode 100644 client/app/components/UserGroups.less create mode 100644 client/app/lib/queryFormat.test.js create mode 100644 client/app/lib/queryFormat.ts create mode 100644 client/app/pages/home/components/FavoritesList.jsx delete mode 100644 client/app/pages/queries/hooks/useFormatQuery.js create mode 100644 client/app/pages/settings/hooks/useOrganizationSettings.js diff --git a/Dockerfile b/Dockerfile index af53138cc..f213d86e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,9 +6,12 @@ ARG skip_frontend_build ENV CYPRESS_INSTALL_BINARY=0 ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 +RUN useradd -m -d /frontend redash +USER redash + WORKDIR /frontend -COPY package.json package-lock.json /frontend/ -COPY viz-lib /frontend/viz-lib +COPY --chown=redash package.json package-lock.json /frontend/ +COPY --chown=redash viz-lib /frontend/viz-lib # Controls whether to instrument code for coverage information ARG code_coverage @@ -16,8 +19,8 @@ ENV BABEL_ENV=${code_coverage:+test} RUN if [ "x$skip_frontend_build" = "x" ] ; then npm ci --unsafe-perm; fi -COPY client /frontend/client -COPY webpack.config.js /frontend/ +COPY --chown=redash client /frontend/client +COPY --chown=redash webpack.config.js /frontend/ RUN if [ "x$skip_frontend_build" = "x" ] ; then npm run build; else mkdir -p /frontend/client/dist && touch /frontend/client/dist/multi_org.html && touch /frontend/client/dist/index.html; fi FROM python:3.7-slim diff --git a/client/.eslintrc.js b/client/.eslintrc.js index 5ace51067..c0e54dcb7 100644 --- a/client/.eslintrc.js +++ b/client/.eslintrc.js @@ -23,8 +23,16 @@ module.exports = { "no-restricted-imports": [ "error", { - name: "antd", - message: "Please use antd/lib instead.", + paths: [ + { + name: "antd", + message: "Please use 'import XXX from antd/lib/XXX' import instead.", + }, + { + name: "antd/lib", + message: "Please use 'import XXX from antd/lib/XXX' import instead.", + }, + ], }, ], }, diff --git a/client/app/assets/images/db-logos/databricks.png b/client/app/assets/images/db-logos/databricks.png index 7624f2adcff64f262f72c71a4fe8cbecbf29ba05..e28eb9212fc417d78926ada2ab8053f8d9586092 100644 GIT binary patch literal 2884 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 GE%tv<)o)z@ literal 2562 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 W*UnH)#O|pB?5{Z5ys^6Z*Z%+pZck+Z diff --git a/client/app/assets/less/redash/query.less b/client/app/assets/less/redash/query.less index f65d3bbc7..03f740040 100644 --- a/client/app/assets/less/redash/query.less +++ b/client/app/assets/less/redash/query.less @@ -141,6 +141,7 @@ a.label-tag { display: flex; flex-direction: column; flex-grow: 1; + position: relative; } .query-fullscreen { diff --git a/client/app/components/ApplicationArea/ApplicationLayout/index.jsx b/client/app/components/ApplicationArea/ApplicationLayout/index.jsx index c89806d3d..78f5663c0 100644 --- a/client/app/components/ApplicationArea/ApplicationLayout/index.jsx +++ b/client/app/components/ApplicationArea/ApplicationLayout/index.jsx @@ -13,19 +13,21 @@ export default function ApplicationLayout({ children }) { return ( -
- - - -
-
- - {children} -
+ +
+ + {children} +
+
); } diff --git a/client/app/components/ApplicationArea/ErrorMessage.jsx b/client/app/components/ApplicationArea/ErrorMessage.jsx index f31cb2f93..733444f4b 100644 --- a/client/app/components/ApplicationArea/ErrorMessage.jsx +++ b/client/app/components/ApplicationArea/ErrorMessage.jsx @@ -46,7 +46,7 @@ export default function ErrorMessage({ error, message }) { }; return ( -
+
diff --git a/client/app/components/HelpTrigger.jsx b/client/app/components/HelpTrigger.jsx index a991b1a3d..c2d4c642c 100644 --- a/client/app/components/HelpTrigger.jsx +++ b/client/app/components/HelpTrigger.jsx @@ -133,10 +133,14 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName return helpTriggerType ? helpTriggerType[0] : this.props.href; }; - openDrawer = () => { - this.setState({ visible: true }); - // wait for drawer animation to complete so there's no animation jank - setTimeout(() => this.loadIframe(this.getUrl()), 300); + openDrawer = e => { + // keep "open in new tab" behavior + if (!e.shiftKey && !e.ctrlKey && !e.metaKey) { + e.preventDefault(); + this.setState({ visible: true }); + // wait for drawer animation to complete so there's no animation jank + setTimeout(() => this.loadIframe(this.getUrl()), 300); + } }; closeDrawer = event => { @@ -170,15 +174,14 @@ export function helpTriggerWithTypes(types, allowedDomains = [], drawerClassName ) : null }> - {shouldRenderAsLink ? ( - - {this.props.children} - - ) : ( - - {this.props.children} - - )} + {} : this.openDrawer}> + {this.props.children} + ; + return