diff --git a/Dockerfile b/Dockerfile index dad74716f1..3a62359374 100644 --- a/Dockerfile +++ b/Dockerfile @@ -66,8 +66,9 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* ARG databricks_odbc_driver_url=https://databricks.com/wp-content/uploads/2.6.10.1010-2/SimbaSparkODBC-2.6.10.1010-2-Debian-64bit.zip -ADD $databricks_odbc_driver_url /tmp/simba_odbc.zip -RUN unzip /tmp/simba_odbc.zip -d /tmp/ \ +RUN wget --quiet $databricks_odbc_driver_url -O /tmp/simba_odbc.zip \ + && chmod 600 /tmp/simba_odbc.zip \ + && unzip /tmp/simba_odbc.zip -d /tmp/ \ && dpkg -i /tmp/SimbaSparkODBC-*/*.deb \ && echo "[Simba]\nDriver = /opt/simba/spark/lib/64/libsparkodbc_sb64.so" >> /etc/odbcinst.ini \ && rm /tmp/simba_odbc.zip \ @@ -79,15 +80,19 @@ WORKDIR /app ENV PIP_DISABLE_PIP_VERSION_CHECK=1 ENV PIP_NO_CACHE_DIR=1 -# Use legacy resolver to work around broken build due to resolver changes in pip -ENV PIP_USE_DEPRECATED=legacy-resolver +# rollback pip version to avoid legacy resolver problem +RUN pip install pip==20.2.4; -# We first copy only the requirements file, to avoid rebuilding on every file -# change. -COPY requirements.txt requirements_bundles.txt requirements_dev.txt requirements_all_ds.txt ./ -RUN if [ "x$skip_dev_deps" = "x" ] ; then pip install -r requirements.txt -r requirements_dev.txt; else pip install -r requirements.txt; fi +# We first copy only the requirements file, to avoid rebuilding on every file change. +COPY requirements_all_ds.txt ./ RUN if [ "x$skip_ds_deps" = "x" ] ; then pip install -r requirements_all_ds.txt ; else echo "Skipping pip install -r requirements_all_ds.txt" ; fi +COPY requirements_bundles.txt requirements_dev.txt ./ +RUN if [ "x$skip_dev_deps" = "x" ] ; then pip install -r requirements_dev.txt ; fi + +COPY requirements.txt ./ +RUN pip install -r requirements.txt + COPY . /app COPY --from=frontend-builder /frontend/client/dist /app/client/dist RUN chown -R redash /app diff --git a/README.md b/README.md index ff63f476d1..46d44d203d 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Redash supports more than 35 SQL and NoSQL [data sources](https://redash.io/help - Shell Scripts - Snowflake - SQLite +- TiDB - TreasureData - Vertica - Yandex AppMetrrica diff --git a/client/.eslintrc.js b/client/.eslintrc.js index 45644f6d19..d1bb2599a1 100644 --- a/client/.eslintrc.js +++ b/client/.eslintrc.js @@ -5,10 +5,11 @@ module.exports = { "react-app", "plugin:compat/recommended", "prettier", + "plugin:jsx-a11y/recommended", // Remove any typescript-eslint rules that would conflict with prettier "prettier/@typescript-eslint", ], - plugins: ["jest", "compat", "no-only-tests", "@typescript-eslint"], + plugins: ["jest", "compat", "no-only-tests", "@typescript-eslint", "jsx-a11y"], settings: { "import/resolver": "webpack", }, @@ -19,7 +20,19 @@ module.exports = { rules: { // allow debugger during development "no-debugger": process.env.NODE_ENV === "production" ? 2 : 0, - "jsx-a11y/anchor-is-valid": "off", + "jsx-a11y/anchor-is-valid": [ + // TMP + "off", + { + components: ["Link"], + aspects: ["noHref", "invalidHref", "preferButton"], + }, + ], + "jsx-a11y/no-redundant-roles": "error", + "jsx-a11y/no-autofocus": "off", + "jsx-a11y/click-events-have-key-events": "off", // TMP + "jsx-a11y/no-static-element-interactions": "off", // TMP + "jsx-a11y/no-noninteractive-element-interactions": "off", // TMP "no-console": ["warn", { allow: ["warn", "error"] }], "no-restricted-imports": [ "error", diff --git a/client/app/assets/images/db-logos/corporate_memory.png b/client/app/assets/images/db-logos/corporate_memory.png new file mode 100644 index 0000000000..f168b02ecd Binary files /dev/null and b/client/app/assets/images/db-logos/corporate_memory.png differ diff --git a/client/app/assets/images/db-logos/sparql_endpoint.png b/client/app/assets/images/db-logos/sparql_endpoint.png new file mode 100644 index 0000000000..31ac155d44 Binary files /dev/null and b/client/app/assets/images/db-logos/sparql_endpoint.png differ diff --git a/client/app/assets/less/inc/schema-browser.less b/client/app/assets/less/inc/schema-browser.less index 3f2e66f28d..f005239758 100644 --- a/client/app/assets/less/inc/schema-browser.less +++ b/client/app/assets/less/inc/schema-browser.less @@ -1,102 +1,107 @@ -div.table-name { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - cursor: pointer; - padding: 2px 22px 2px 10px; - border-radius: @redash-radius; - position: relative; - height: 22px; - - .copy-to-editor { - display: none; - } - - &:hover { - background: fade(@redash-gray, 10%); - - .copy-to-editor { - display: flex; - } - } -} - .schema-container { height: 100%; z-index: 10; background-color: white; -} -.schema-browser { - overflow: hidden; - border: none; - padding-top: 10px; - position: relative; - height: 100%; - - .schema-loading-state { - display: flex; - align-items: center; - justify-content: center; - height: 100%; - } - - .collapse.in { - background: transparent; - } - - .copy-to-editor { - color: fade(@redash-gray, 90%); - cursor: pointer; - position: absolute; - top: 0; - right: 0; - bottom: 0; - width: 20px; - display: flex; - align-items: center; - justify-content: center; - } - - .table-open { - padding: 0 22px 0 26px; + .schema-browser { overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + border: none; + padding-top: 10px; position: relative; - height: 18px; + height: 100%; - .column-type { - color: fade(@text-color, 80%); - font-size: 10px; - margin-left: 2px; - text-transform: uppercase; + .schema-loading-state { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + } + + .collapse.in { + background: transparent; } .copy-to-editor { - display: none; + visibility: hidden; + color: fade(@redash-gray, 90%); + width: 20px; + display: flex; + align-items: center; + justify-content: center; + transition: none; } - &:hover { - background: fade(@redash-gray, 10%); + .schema-list-item { + display: flex; + border-radius: @redash-radius; + height: 22px; + + .table-name { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + cursor: pointer; + padding: 2px 22px 2px 10px; + } + + &:hover, + &:focus, + &:focus-within { + background: fade(@redash-gray, 10%); - .copy-to-editor { + .copy-to-editor { + visibility: visible; + } + } + } + + .table-open { + .table-open-item { display: flex; + height: 18px; + width: calc(100% - 22px); + padding-left: 22px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + transition: none; + + div:first-child { + flex: 1; + } + + .column-type { + color: fade(@text-color, 80%); + font-size: 10px; + margin-left: 2px; + text-transform: uppercase; + } + + &:hover, + &:focus, + &:focus-within { + background: fade(@redash-gray, 10%); + + .copy-to-editor { + visibility: visible; + } + } } } } -} -.schema-control { - display: flex; - flex-wrap: nowrap; - padding: 0; + .schema-control { + display: flex; + flex-wrap: nowrap; + padding: 0; - .ant-btn { - height: auto; + .ant-btn { + height: auto; + } } -} -.parameter-label { - display: block; + .parameter-label { + display: block; + } } diff --git a/client/app/components/ApplicationArea/ApplicationLayout/DesktopNavbar.jsx b/client/app/components/ApplicationArea/ApplicationLayout/DesktopNavbar.jsx index bc131c09f0..a1550f60dc 100644 --- a/client/app/components/ApplicationArea/ApplicationLayout/DesktopNavbar.jsx +++ b/client/app/components/ApplicationArea/ApplicationLayout/DesktopNavbar.jsx @@ -2,6 +2,7 @@ import React, { useMemo } from "react"; import { first, includes } from "lodash"; import Menu from "antd/lib/menu"; import Link from "@/components/Link"; +import PlainButton from "@/components/PlainButton"; import HelpTrigger from "@/components/HelpTrigger"; import CreateDashboardDialog from "@/components/dashboards/CreateDashboardDialog"; import { useCurrentRoute } from "@/components/ApplicationArea/Router"; @@ -15,8 +16,8 @@ import AlertOutlinedIcon from "@ant-design/icons/AlertOutlined"; import PlusOutlinedIcon from "@ant-design/icons/PlusOutlined"; import QuestionCircleOutlinedIcon from "@ant-design/icons/QuestionCircleOutlined"; import SettingOutlinedIcon from "@ant-design/icons/SettingOutlined"; - import VersionInfo from "./VersionInfo"; + import "./DesktopNavbar.less"; function NavbarSection({ children, ...props }) { @@ -129,9 +130,9 @@ export default function DesktopNavbar() { )} {canCreateDashboard && (
({ bodyClass, currentRoute, render }: UserS
{/* @ts-expect-error FIXME */}
["onError"] } FIXME bring back type */) =>
- render({ ...currentRoute.routeParams, pageTitle: currentRoute.title, onError: handleError })
- }
+ {(
+ {
+ handleError,
+ } /* : { handleError: UserSessionWrapperRenderChildrenProps ["onError"] } FIXME bring back type */
+ ) => render({ ...currentRoute.routeParams, pageTitle: currentRoute.title, onError: handleError })}