From a0f0803966ea6dae3dbdb1e68d5aea79d643e989 Mon Sep 17 00:00:00 2001 From: Yunus A M Date: Mon, 15 Apr 2024 16:18:36 +0530 Subject: [PATCH 01/42] feat: dashboard list view --- .../src/assets/CustomIcons/GrafanaIcon.tsx | 18 + .../src/assets/CustomIcons/JuiceBoxIcon.tsx | 82 ++++ .../src/assets/CustomIcons/MagicBallIcon.tsx | 38 ++ frontend/src/assets/CustomIcons/TentIcon.tsx | 110 +++++ .../ListOfDashboard/DashboardList.styles.scss | 374 +++++++++++++++ .../ListOfDashboard/DashboardsList.tsx | 444 +++++++++++++----- .../src/pages/SaveView/SaveView.styles.scss | 2 +- 7 files changed, 941 insertions(+), 127 deletions(-) create mode 100644 frontend/src/assets/CustomIcons/GrafanaIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/JuiceBoxIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/MagicBallIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/TentIcon.tsx create mode 100644 frontend/src/container/ListOfDashboard/DashboardList.styles.scss diff --git a/frontend/src/assets/CustomIcons/GrafanaIcon.tsx b/frontend/src/assets/CustomIcons/GrafanaIcon.tsx new file mode 100644 index 0000000000..c1949dbb95 --- /dev/null +++ b/frontend/src/assets/CustomIcons/GrafanaIcon.tsx @@ -0,0 +1,18 @@ +function GrafanaIcon(): JSX.Element { + return ( + + + + ); +} + +export default GrafanaIcon; diff --git a/frontend/src/assets/CustomIcons/JuiceBoxIcon.tsx b/frontend/src/assets/CustomIcons/JuiceBoxIcon.tsx new file mode 100644 index 0000000000..103a48b493 --- /dev/null +++ b/frontend/src/assets/CustomIcons/JuiceBoxIcon.tsx @@ -0,0 +1,82 @@ +function JuiceBoxIcon(): JSX.Element { + return ( + + + + + + + + + + + + + + + + + + + + ); +} + +export default JuiceBoxIcon; diff --git a/frontend/src/assets/CustomIcons/MagicBallIcon.tsx b/frontend/src/assets/CustomIcons/MagicBallIcon.tsx new file mode 100644 index 0000000000..e37e4bb540 --- /dev/null +++ b/frontend/src/assets/CustomIcons/MagicBallIcon.tsx @@ -0,0 +1,38 @@ +function MagicBallIcon(): JSX.Element { + return ( + + + + + + + + + ); +} + +export default MagicBallIcon; diff --git a/frontend/src/assets/CustomIcons/TentIcon.tsx b/frontend/src/assets/CustomIcons/TentIcon.tsx new file mode 100644 index 0000000000..9271324fae --- /dev/null +++ b/frontend/src/assets/CustomIcons/TentIcon.tsx @@ -0,0 +1,110 @@ +function TentIcon(): JSX.Element { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} + +export default TentIcon; diff --git a/frontend/src/container/ListOfDashboard/DashboardList.styles.scss b/frontend/src/container/ListOfDashboard/DashboardList.styles.scss new file mode 100644 index 0000000000..48f56770ab --- /dev/null +++ b/frontend/src/container/ListOfDashboard/DashboardList.styles.scss @@ -0,0 +1,374 @@ +.dashboards-list-container { + margin-top: 70px; + display: flex; + justify-content: center; + width: 100%; + + .dashboards-list-view-content { + width: calc(100% - 30px); + max-width: 736px; + + .dashboards-list-title-container { + .title { + color: var(--bg-vanilla-100); + font-size: var(--font-size-lg); + font-style: normal; + font-weight: var(--font-weight-normal); + line-height: 28px; /* 155.556% */ + letter-spacing: -0.09px; + } + + .subtitle { + color: var(--bg-vanilla-400); + font-size: var(--font-size-sm); + font-style: normal; + font-weight: var(--font-weight-normal); + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + } + + .ant-table-row { + .ant-table-cell { + padding: 0; + border: none; + background: var(--bg-ink-500); + } + + .dashboard-list-item { + margin: 8px 0 !important; + padding: 16px; + border-radius: 6px; + border: 1px solid var(--bg-slate-500); + background: var(--bg-ink-400); + cursor: pointer; + + .title-with-action { + display: flex; + justify-content: space-between; + align-items: center; + + min-height: 24px; + + .dashboard-title { + display: flex; + align-items: center; + gap: 6px; + line-height: 20px; + + .dot { + min-height: 6px; + min-width: 6px; + border-radius: 50%; + } + + .ant-typography { + color: var(--bg-vanilla-100); + font-size: var(--font-size-sm); + font-style: normal; + font-weight: var(--font-weight-medium); + line-height: 20px; + letter-spacing: -0.07px; + } + } + + .action-btn { + display: flex; + align-items: center; + gap: 20px; + cursor: pointer; + + .hidden { + display: none; + } + } + } + + .dashboard-details { + margin-top: 8px; + display: flex; + align-items: center; + + .dashboard-tag { + width: 14px; + height: 14px; + border-radius: 50px; + background: var(--bg-slate-300); + display: flex; + justify-content: center; + align-items: center; + + .tag-text { + color: var(--bg-vanilla-400); + leading-trim: both; + text-edge: cap; + font-size: 8px; + font-style: normal; + font-weight: var(--font-weight-normal); + line-height: normal; + letter-spacing: -0.05px; + } + } + + .dashboard-created-by { + margin-left: 8px; + } + + .dashboard-created-at { + display: flex; + align-items: center; + margin-right: 16px; + + .ant-typography { + margin-left: 6px; + color: var(--bg-vanilla-400); + font-size: var(--font-size-xs); + font-style: normal; + font-weight: var(--font-weight-normal); + line-height: 18px; /* 128.571% */ + letter-spacing: -0.07px; + } + } + } + } + } + + .ant-pagination-item { + display: flex; + justify-content: center; + align-items: center; + + > a { + color: var(--bg-vanilla-400); + font-variant-numeric: lining-nums tabular-nums slashed-zero; + font-feature-settings: 'dlig' on, 'salt' on, 'case' on, 'cpsp' on; + font-size: var(--font-size-sm); + font-style: normal; + font-weight: var(--font-weight-normal); + line-height: 20px; /* 142.857% */ + } + } + + .ant-pagination-item-active { + background-color: var(--bg-robin-500); + > a { + color: var(--bg-ink-500) !important; + font-size: var(--font-size-sm); + font-style: normal; + font-weight: var(--font-weight-medium); + line-height: 20px; + } + } + } + + .dashboards-list-header-container { + display: flex; + align-items: center; + gap: 8px; + + margin: 16px 0; + } + + .dashboard-tags { + .ant-tag { + border-radius: 20px; + } + } +} + +.new-dashboard-menu { + .create-dashboard-menu-item { + display: flex; + align-items: center; + gap: 8px; + } +} + +.delete-view-modal { + width: calc(100% - 30px) !important; /* Adjust the 20px as needed */ + max-width: 384px; + .ant-modal-content { + padding: 0; + border-radius: 4px; + border: 1px solid var(--bg-slate-500); + background: var(--bg-ink-400); + box-shadow: 0px -4px 16px 2px rgba(0, 0, 0, 0.2); + + .ant-modal-header { + padding: 16px; + background: var(--bg-ink-400); + } + + .ant-modal-body { + padding: 0px 16px 28px 16px; + + .ant-typography { + color: var(--bg-vanilla-400); + font-size: var(--font-size-sm); + font-style: normal; + font-weight: var(--font-weight-normal); + line-height: 20px; + letter-spacing: -0.07px; + } + + .save-view-input { + margin-top: 8px; + display: flex; + gap: 8px; + } + + .ant-color-picker-trigger { + padding: 6px; + border-radius: 2px; + border: 1px solid var(--bg-slate-400); + background: var(--bg-ink-300); + width: 32px; + height: 32px; + + .ant-color-picker-color-block { + border-radius: 50px; + width: 16px; + height: 16px; + flex-shrink: 0; + + .ant-color-picker-color-block-inner { + display: flex; + justify-content: center; + align-items: center; + } + } + } + } + + .ant-modal-footer { + display: flex; + justify-content: flex-end; + padding: 16px 16px; + margin: 0; + + .cancel-btn { + display: flex; + align-items: center; + border: none; + border-radius: 2px; + background: var(--bg-slate-500); + } + + .delete-btn { + display: flex; + align-items: center; + border: none; + border-radius: 2px; + background: var(--bg-cherry-500); + margin-left: 12px; + } + + .delete-btn:hover { + color: var(--bg-vanilla-100); + background: var(--bg-cherry-600); + } + } + } + .title { + color: var(--bg-vanilla-100); + font-size: var(--font-size-sm); + font-style: normal; + font-weight: var(--font-weight-medium); + line-height: 20px; /* 142.857% */ + } +} + +.lightMode { + .dashboards-list-container { + .dashboards-list-view-content { + .title { + color: var(--bg-ink-500); + } + + .ant-table-row { + .ant-table-cell { + background: var(--bg-vanilla-200); + } + + &:hover { + .ant-table-cell { + background: var(--bg-vanilla-200) !important; + } + } + + .dashboard-list-item { + border: 1px solid var(--bg-vanilla-200); + background: var(--bg-vanilla-100); + + .title-with-action { + .dashboard-title { + .ant-typography { + color: var(--bg-ink-500); + } + } + + .action-btn { + .ant-typography { + color: var(--bg-ink-500); + } + } + } + + .dashboard-details { + .dashboard-tag { + background: var(--bg-vanilla-200); + .tag-text { + color: var(--bg-ink-500); + } + } + + .dashboard-created-by { + color: var(--bg-ink-500); + } + + .dashboard-created-at { + .ant-typography { + color: var(--bg-ink-500); + } + } + } + } + } + } + } + + .delete-view-modal { + .ant-modal-content { + border: 1px solid var(--bg-vanilla-200); + background: var(--bg-vanilla-100); + + .ant-modal-header { + background: var(--bg-vanilla-100); + + .title { + color: var(--bg-ink-500); + } + } + + .ant-modal-body { + .ant-typography { + color: var(--bg-ink-500); + } + + .save-view-input { + .ant-input { + background: var(--bg-vanilla-200); + color: var(--bg-ink-500); + } + } + } + + .ant-modal-footer { + .cancel-btn { + background: var(--bg-vanilla-300); + color: var(--bg-ink-400); + } + } + } + } +} diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index a0a31c3142..fcb6e51164 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -1,7 +1,29 @@ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +import './DashboardList.styles.scss'; + import { PlusOutlined } from '@ant-design/icons'; -import { Card, Col, Dropdown, Input, Row, TableColumnProps } from 'antd'; +import { Color } from '@signozhq/design-tokens'; +import { + Button, + Col, + ColorPicker, + Dropdown, + Input, + MenuProps, + Modal, + Row, + Table, + TableColumnProps, + Tag, + Typography, +} from 'antd'; import { ItemType } from 'antd/es/menu/hooks/useItems'; +import { TableProps } from 'antd/lib'; import createDashboard from 'api/dashboard/create'; +import GrafanaIcon from 'assets/CustomIcons/GrafanaIcon'; +import JuiceBoxIcon from 'assets/CustomIcons/JuiceBoxIcon'; +import TentIcon from 'assets/CustomIcons/TentIcon'; import { AxiosError } from 'axios'; import { dashboardListMessage } from 'components/facingIssueBtn/util'; import { @@ -16,14 +38,38 @@ import ROUTES from 'constants/routes'; import { useGetAllDashboard } from 'hooks/dashboard/useGetAllDashboard'; import useComponentPermission from 'hooks/useComponentPermission'; import useDebouncedFn from 'hooks/useDebouncedFunction'; +import getRandomColor from 'lib/getRandomColor'; import history from 'lib/history'; -import { Key, useCallback, useEffect, useMemo, useState } from 'react'; +import { + CalendarClock, + Check, + Compass, + LayoutGrid, + PenLine, + Plus, + Radius, + Search, + SortDesc, + TentTree, + Trash2, + X, +} from 'lucide-react'; +import { + ChangeEvent, + Key, + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { generatePath } from 'react-router-dom'; import { AppState } from 'store/reducers'; import { Dashboard } from 'types/api/dashboard/getAll'; +import { ViewProps } from 'types/api/saveViews/types'; import AppReducer from 'types/reducer/app'; +import { USER_ROLES } from 'types/roles'; import DateComponent from '../../components/ResizeTable/TableComponent/DateComponent'; import useSortableTable from '../../hooks/ResizeTable/useSortableTable'; @@ -35,7 +81,9 @@ import DeleteButton from './TableComponents/DeleteButton'; import Name from './TableComponents/Name'; import { filterDashboard } from './utils'; -const { Search } = Input; +// const { Search } = Input; + +const allowedRoles = [USER_ROLES.ADMIN, USER_ROLES.AUTHOR, USER_ROLES.EDITOR]; function DashboardsList(): JSX.Element { const { @@ -51,6 +99,8 @@ function DashboardsList(): JSX.Element { role, ); + const [searchValue, setSearchValue] = useState(''); + const { t } = useTranslation('dashboard'); const [ @@ -153,39 +203,6 @@ function DashboardsList(): JSX.Element { }, ]; - const columns = useMemo(() => { - const tableColumns: TableColumnProps[] = [ - { - title: 'Name', - dataIndex: 'name', - width: 40, - render: Name, - }, - { - title: 'Description', - width: 50, - dataIndex: 'description', - }, - { - title: 'Tags', - dataIndex: 'tags', - width: 50, - render: (value): JSX.Element => , - }, - ]; - - if (action) { - tableColumns.push({ - title: 'Action', - dataIndex: '', - width: 40, - render: DeleteButton, - }); - } - - return tableColumns; - }, [action]); - const data: Data[] = dashboards?.map((e) => ({ createdAt: e.created_at, @@ -286,106 +303,278 @@ function DashboardsList(): JSX.Element { return menuItems; }, [createNewDashboard, isDashboardListLoading, onNewDashboardHandler, t]); - const handleSearch = useDebouncedFn((event: unknown): void => { + const handleSearch = (event: ChangeEvent): void => { setIsFilteringDashboards(true); + setSearchValue(event.target.value); const searchText = (event as React.BaseSyntheticEvent)?.target?.value || ''; const filteredDashboards = filterDashboard(searchText, dashboardListResponse); setDashboards(filteredDashboards); setIsFilteringDashboards(false); setSearchString(searchText); - }, 500); - - const GetHeader = useMemo( - () => ( - - - { + // const tableColumns: TableColumnProps[] = [ + // { + // title: 'Name', + // dataIndex: 'name', + // width: 40, + // render: Name, + // }, + // { + // title: 'Description', + // width: 50, + // dataIndex: 'description', + // }, + // { + // title: 'Tags', + // dataIndex: 'tags', + // width: 50, + // render: (value): JSX.Element => , + // }, + // ]; + + // if (action) { + // tableColumns.push({ + // title: 'Action', + // dataIndex: '', + // width: 40, + // render: DeleteButton, + // }); + // } + + // return tableColumns; + // }, [action]); + + const columns: TableProps['columns'] = [ + { + title: 'Dashboards', + key: 'dashboard', + render: (dashboard: Data): JSX.Element => { + const timeOptions: Intl.DateTimeFormatOptions = { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hour12: false, + }; + const formattedTime = new Date(dashboard.createdAt).toLocaleTimeString( + 'en-US', + timeOptions, + ); + + const dateOptions: Intl.DateTimeFormatOptions = { + month: 'short', + day: 'numeric', + year: 'numeric', + }; + + const formattedDate = new Date(dashboard.createdAt).toLocaleDateString( + 'en-US', + dateOptions, + ); + + // Combine time and date + const formattedDateAndTime = `${formattedDate} ⎯ ${formattedTime}`; + + const isEditDeleteSupported = allowedRoles.includes(role as string); + + const getLink = (): string => `${ROUTES.ALL_DASHBOARD}/${dashboard.id}`; + + const onClickHandler = (event: React.MouseEvent): void => { + if (event.metaKey || event.ctrlKey) { + window.open(getLink(), '_blank'); + } else { + history.push(getLink()); + } + }; + + return ( +
+
+
+ {dashboard.name} +
+ {/* +
+ handleEditModelOpen(view, bgColor)} + /> + handleRedirectQuery(view)} /> + handleDeleteMode + lOpen(view.uuid, view.name)} + /> +
*/} + + {dashboard?.tags && dashboard.tags.length > 0 && ( +
+ {dashboard.tags.map((tag) => ( + + {tag} + + ))} +
+ )} +
+
+
+ + {formattedDateAndTime} +
+ + {dashboard.createdBy && ( + <> +
+ + {dashboard.createdBy?.substring(0, 1).toUpperCase()} + +
+ + {dashboard.createdBy} + + + )} +
+
+ ); + }, + }, + ]; + // const GetHeader = useMemo( + // () => ( + // + // + // + // + + // {createNewDashboard && ( + // + // + // + // + + // + // } + // type="primary" + // data-testid="create-new-dashboard" + // loading={newDashboardState.loading} + // danger={newDashboardState.error} + // > + // {getText()} + // + // + // + // )} + // + // ), + // [ + // isDashboardListLoading, + // handleSearch, + // isFilteringDashboards, + // searchString, + // createNewDashboard, + // getMenuItems, + // newDashboardState.loading, + // newDashboardState.error, + // getText, + // ], + // ); + + const items: MenuProps['items'] = [ + { + label: ( +
+ {' '} + Create dashboard{' '} +
+ ), + key: '0', + }, + { + label: ( +
+ {' '} + Import JSON{' '} +
+ ), + key: '1', + }, + { + label: ( +
+ {' '} + Use Grafana JSON{' '} +
+ ), + key: '3', + }, + ]; + + return ( +
+
+
+ Dashboards + + Create and manage dashboards for your workspace. + +
+ +
+ + + } + value={searchValue} onChange={handleSearch} - loading={isFilteringDashboards} - style={{ marginBottom: 16, marginTop: 16 }} - defaultValue={searchString} - autoFocus /> - - - {createNewDashboard && ( - - - - - - - } - type="primary" - data-testid="create-new-dashboard" - loading={newDashboardState.loading} - danger={newDashboardState.error} - > - {getText()} - - - - )} - - ), - [ - isDashboardListLoading, - handleSearch, - isFilteringDashboards, - searchString, - createNewDashboard, - getMenuItems, - newDashboardState.loading, - newDashboardState.error, - getText, - ], - ); + + +
- return ( - - {GetHeader} - - - onModalHandler(false)} - /> - - - +
+
); } diff --git a/frontend/src/pages/SaveView/SaveView.styles.scss b/frontend/src/pages/SaveView/SaveView.styles.scss index 1e4b7bf0f6..e1eb1ab0b0 100644 --- a/frontend/src/pages/SaveView/SaveView.styles.scss +++ b/frontend/src/pages/SaveView/SaveView.styles.scss @@ -18,7 +18,7 @@ } .subtitle { - color: var(---bg-vanilla-400); + color: var(--bg-vanilla-400); font-size: var(--font-size-sm); font-style: normal; font-weight: var(--font-weight-normal); From 272451be1238b56f40248aa0c71ae65401d8ed79 Mon Sep 17 00:00:00 2001 From: Yunus A M Date: Mon, 15 Apr 2024 16:28:43 +0530 Subject: [PATCH 02/42] feat: update sort menu items --- .../ListOfDashboard/DashboardsList.tsx | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index fcb6e51164..6293a5e4cf 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -42,9 +42,12 @@ import getRandomColor from 'lib/getRandomColor'; import history from 'lib/history'; import { CalendarClock, + CalendarClockIcon, Check, Compass, + FolderPen, LayoutGrid, + PencilRuler, PenLine, Plus, Radius, @@ -509,7 +512,37 @@ function DashboardsList(): JSX.Element { // ], // ); - const items: MenuProps['items'] = [ + const sortMenuItems: MenuProps['items'] = [ + { + label: ( +
+ {' '} + Last created +
+ ), + key: '0', + }, + { + label: ( +
+ {' '} + Last updated +
+ ), + key: '1', + }, + { + label: ( +
+ {' '} + Name +
+ ), + key: '3', + }, + ]; + + const createDashboardItems: MenuProps['items'] = [ { label: (
@@ -550,9 +583,19 @@ function DashboardsList(): JSX.Element {
- + + + @@ -630,7 +621,13 @@ function DashboardsList(): JSX.Element { }} loading={isDashboardListLoading} showHeader={false} - pagination={{ pageSize: 5 }} + pagination={{ pageSize: 5, showSizeChanger: false }} + /> + + onModalHandler(false)} />
From 6f901ef31ce6fb202e7935df678f667586d47110 Mon Sep 17 00:00:00 2001 From: Yunus A M Date: Tue, 16 Apr 2024 13:40:30 +0530 Subject: [PATCH 04/42] feat: update import json styles --- frontend/public/locales/en-GB/dashboard.json | 4 +- frontend/public/locales/en/dashboard.json | 4 +- .../ListOfDashboard/DashboardsList.tsx | 252 +----------------- .../ImportJSON/importJSON.styles.scss | 41 +++ .../ListOfDashboard/ImportJSON/index.tsx | 155 +++++++---- .../ListOfDashboard/ImportJSON/styles.ts | 10 - 6 files changed, 163 insertions(+), 303 deletions(-) create mode 100644 frontend/src/container/ListOfDashboard/ImportJSON/importJSON.styles.scss delete mode 100644 frontend/src/container/ListOfDashboard/ImportJSON/styles.ts diff --git a/frontend/public/locales/en-GB/dashboard.json b/frontend/public/locales/en-GB/dashboard.json index 49a0ff39dd..e81a4445dc 100644 --- a/frontend/public/locales/en-GB/dashboard.json +++ b/frontend/public/locales/en-GB/dashboard.json @@ -1,6 +1,6 @@ { "create_dashboard": "Create Dashboard", - "import_json": "Import JSON", + "import_json": "Import Dashboard JSON", "import_grafana_json": "Import Grafana JSON", "copy_to_clipboard": "Copy To ClipBoard", "download_json": "Download JSON", @@ -9,7 +9,7 @@ "upload_json_file": "Upload JSON file", "paste_json_below": "Paste JSON below", "error_upload_json": "Invalid JSON", - "load_json": "Load JSON", + "load_json": "Import and Next", "import_dashboard_by_pasting": "Import dashboard by pasting JSON or importing JSON file", "error_loading_json": "Error loading JSON file", "empty_json_not_allowed": "Empty JSON is not allowed", diff --git a/frontend/public/locales/en/dashboard.json b/frontend/public/locales/en/dashboard.json index c214c027c2..4e3d9e9677 100644 --- a/frontend/public/locales/en/dashboard.json +++ b/frontend/public/locales/en/dashboard.json @@ -1,6 +1,6 @@ { "create_dashboard": "Create Dashboard", - "import_json": "Import JSON", + "import_json": "Import Dashboard JSON", "import_grafana_json": "Import Grafana JSON", "copy_to_clipboard": "Copy To ClipBoard", "download_json": "Download JSON", @@ -9,7 +9,7 @@ "upload_json_file": "Upload JSON file", "paste_json_below": "Paste JSON below", "error_upload_json": "Invalid JSON", - "load_json": "Load JSON", + "load_json": "Import and Next", "import_dashboard_by_pasting": "Import dashboard by pasting JSON or importing JSON file", "error_loading_json": "Error loading JSON file", "empty_json_not_allowed": "Empty JSON is not allowed", diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index 6835d89139..b414a1bee8 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -2,28 +2,26 @@ /* eslint-disable jsx-a11y/no-static-element-interactions */ import './DashboardList.styles.scss'; -import { PlusOutlined } from '@ant-design/icons'; import { Color } from '@signozhq/design-tokens'; import { Button, - Col, - ColorPicker, Dropdown, Input, MenuProps, - Modal, - Row, Table, - TableColumnProps, Tag, Typography, } from 'antd'; import { ItemType } from 'antd/es/menu/hooks/useItems'; import { TableProps } from 'antd/lib'; +import { TableProps } from 'antd/lib'; +import createDashboard from 'api/dashboard/create'; import createDashboard from 'api/dashboard/create'; import GrafanaIcon from 'assets/CustomIcons/GrafanaIcon'; import JuiceBoxIcon from 'assets/CustomIcons/JuiceBoxIcon'; import TentIcon from 'assets/CustomIcons/TentIcon'; +import TentIcon from 'assets/CustomIcons/TentIcon'; +import { AxiosError } from 'axios'; import { AxiosError } from 'axios'; import { dashboardListMessage } from 'components/facingIssueBtn/util'; import { @@ -43,28 +41,14 @@ import history from 'lib/history'; import { CalendarClock, CalendarClockIcon, - Check, - Compass, - FolderPen, LayoutGrid, PencilRuler, - PenLine, Plus, Radius, Search, SortDesc, - TentTree, - Trash2, - X, } from 'lucide-react'; -import { - ChangeEvent, - Key, - useCallback, - useEffect, - useMemo, - useState, -} from 'react'; +import { ChangeEvent, Key, useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { generatePath } from 'react-router-dom'; @@ -74,14 +58,10 @@ import { ViewProps } from 'types/api/saveViews/types'; import AppReducer from 'types/reducer/app'; import { USER_ROLES } from 'types/roles'; -import DateComponent from '../../components/ResizeTable/TableComponent/DateComponent'; import useSortableTable from '../../hooks/ResizeTable/useSortableTable'; import useUrlQuery from '../../hooks/useUrlQuery'; import { GettableAlert } from '../../types/api/alerts/get'; import ImportJSON from './ImportJSON'; -import { ButtonContainer, NewDashboardButton, TableContainer } from './styles'; -import DeleteButton from './TableComponents/DeleteButton'; -import Name from './TableComponents/Name'; import { filterDashboard } from './utils'; // const { Search } = Input; @@ -157,55 +137,6 @@ function DashboardsList(): JSX.Element { errorMessage: '', }); - const dynamicColumns: TableColumnProps[] = [ - { - title: 'Created At', - dataIndex: 'createdAt', - width: 30, - key: DynamicColumnsKey.CreatedAt, - sorter: (a: Data, b: Data): number => { - const prev = new Date(a.createdAt).getTime(); - const next = new Date(b.createdAt).getTime(); - - return prev - next; - }, - render: DateComponent, - sortOrder: - sortedInfo.columnKey === DynamicColumnsKey.CreatedAt - ? sortedInfo.order - : null, - }, - { - title: 'Created By', - dataIndex: 'createdBy', - width: 30, - key: DynamicColumnsKey.CreatedBy, - }, - { - title: 'Last Updated Time', - width: 30, - dataIndex: 'lastUpdatedTime', - key: DynamicColumnsKey.UpdatedAt, - sorter: (a: Data, b: Data): number => { - const prev = new Date(a.lastUpdatedTime).getTime(); - const next = new Date(b.lastUpdatedTime).getTime(); - - return prev - next; - }, - render: DateComponent, - sortOrder: - sortedInfo.columnKey === DynamicColumnsKey.UpdatedAt - ? sortedInfo.order - : null, - }, - { - title: 'Last Updated By', - dataIndex: 'lastUpdatedBy', - width: 30, - key: DynamicColumnsKey.UpdatedBy, - }, - ]; - const data: Data[] = dashboards?.map((e) => ({ createdAt: e.created_at, @@ -258,54 +189,11 @@ function DashboardsList(): JSX.Element { } }, [newDashboardState, t]); - const getText = useCallback(() => { - if (!newDashboardState.error && !newDashboardState.loading) { - return 'New Dashboard'; - } - - if (newDashboardState.loading) { - return 'Loading'; - } - - return newDashboardState.errorMessage; - }, [ - newDashboardState.error, - newDashboardState.errorMessage, - newDashboardState.loading, - ]); - const onModalHandler = (uploadedGrafana: boolean): void => { setIsImportJSONModalVisible((state) => !state); setUploadedGrafana(uploadedGrafana); }; - const getMenuItems = useMemo(() => { - const menuItems: ItemType[] = [ - { - key: t('import_json').toString(), - label: t('import_json'), - onClick: (): void => onModalHandler(false), - }, - { - key: t('import_grafana_json').toString(), - label: t('import_grafana_json'), - onClick: (): void => onModalHandler(true), - disabled: true, - }, - ]; - - if (createNewDashboard) { - menuItems.unshift({ - key: t('create_dashboard').toString(), - label: t('create_dashboard'), - disabled: isDashboardListLoading, - onClick: onNewDashboardHandler, - }); - } - - return menuItems; - }, [createNewDashboard, isDashboardListLoading, onNewDashboardHandler, t]); - const handleSearch = (event: ChangeEvent): void => { setIsFilteringDashboards(true); setSearchValue(event.target.value); @@ -316,39 +204,6 @@ function DashboardsList(): JSX.Element { setSearchString(searchText); }; - // const columns = useMemo(() => { - // const tableColumns: TableColumnProps[] = [ - // { - // title: 'Name', - // dataIndex: 'name', - // width: 40, - // render: Name, - // }, - // { - // title: 'Description', - // width: 50, - // dataIndex: 'description', - // }, - // { - // title: 'Tags', - // dataIndex: 'tags', - // width: 50, - // render: (value): JSX.Element => , - // }, - // ]; - - // if (action) { - // tableColumns.push({ - // title: 'Action', - // dataIndex: '', - // width: 40, - // render: DeleteButton, - // }); - // } - - // return tableColumns; - // }, [action]); - const columns: TableProps['columns'] = [ { title: 'Dashboards', @@ -379,7 +234,7 @@ function DashboardsList(): JSX.Element { // Combine time and date const formattedDateAndTime = `${formattedDate} ⎯ ${formattedTime}`; - const isEditDeleteSupported = allowedRoles.includes(role as string); + // const isEditDeleteSupported = allowedRoles.includes(role as string); const getLink = (): string => `${ROUTES.ALL_DASHBOARD}/${dashboard.id}`; @@ -432,76 +287,13 @@ function DashboardsList(): JSX.Element { }, }, ]; - // const GetHeader = useMemo( - // () => ( - // - // - // - // - - // {createNewDashboard && ( - // - // - // - // - - // - // } - // type="primary" - // data-testid="create-new-dashboard" - // loading={newDashboardState.loading} - // danger={newDashboardState.error} - // > - // {getText()} - // - // - // - // )} - // - // ), - // [ - // isDashboardListLoading, - // handleSearch, - // isFilteringDashboards, - // searchString, - // createNewDashboard, - // getMenuItems, - // newDashboardState.loading, - // newDashboardState.error, - // getText, - // ], - // ); - - const sortMenuItems: MenuProps['items'] = [ + + const filterMenuItems: MenuProps['items'] = [ { label: (
{' '} - Last created + Created by
), key: '0', @@ -510,20 +302,11 @@ function DashboardsList(): JSX.Element { label: (
{' '} - Last updated + Last updated by
), key: '1', }, - { - label: ( -
- {' '} - Name -
- ), - key: '3', - }, ]; const createDashboardItems: MenuProps['items'] = [ @@ -548,15 +331,6 @@ function DashboardsList(): JSX.Element { ), key: '1', }, - // { - // label: ( - //
- // {' '} - // Use Grafana JSON{' '} - //
- // ), - // key: '3', - // }, ]; return ( @@ -572,7 +346,7 @@ function DashboardsList(): JSX.Element {
@@ -619,7 +393,7 @@ function DashboardsList(): JSX.Element { message: dashboardListMessage, onHoverText: 'Click here to get help with dashboards', }} - loading={isDashboardListLoading} + loading={isDashboardListLoading || isFilteringDashboards} showHeader={false} pagination={{ pageSize: 5, showSizeChanger: false }} /> diff --git a/frontend/src/container/ListOfDashboard/ImportJSON/importJSON.styles.scss b/frontend/src/container/ListOfDashboard/ImportJSON/importJSON.styles.scss new file mode 100644 index 0000000000..9b96b4b79b --- /dev/null +++ b/frontend/src/container/ListOfDashboard/ImportJSON/importJSON.styles.scss @@ -0,0 +1,41 @@ +.import-json-modal { + .ant-modal-content { + border-radius: 4px; + border: 1px solid var(--Slate-400, #1d212d); + background: linear-gradient( + 139deg, + rgba(18, 19, 23, 0.8) 0%, + rgba(18, 19, 23, 0.9) 98.68% + ); + box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(20px); + + padding: 0; + } + + .import-json-content-header { + padding: 16px; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid var(--Slate-500, #161922); + } + + .import-json-modal-footer { + .create-dashboard-json-error { + margin-bottom: 8px; + display: flex; + } + + .action-btns-container { + display: flex; + justify-content: space-between; + } + } + + .ant-modal-footer { + margin-top: 0; + padding: 16px; + border-top: 1px solid var(--Slate-500, #161922); + } +} diff --git a/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx b/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx index 9db99c29e8..2aa8bb6e64 100644 --- a/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx +++ b/frontend/src/container/ListOfDashboard/ImportJSON/index.tsx @@ -1,20 +1,23 @@ +import './importJSON.styles.scss'; + import { red } from '@ant-design/colors'; import { ExclamationCircleTwoTone } from '@ant-design/icons'; +import MEditor, { Monaco } from '@monaco-editor/react'; +import { Color } from '@signozhq/design-tokens'; import { Button, Modal, Space, Typography, Upload, UploadProps } from 'antd'; import createDashboard from 'api/dashboard/create'; -import Editor from 'components/Editor'; import ROUTES from 'constants/routes'; +import { useIsDarkMode } from 'hooks/useDarkMode'; import { MESSAGE } from 'hooks/useFeatureFlag'; import { useNotifications } from 'hooks/useNotifications'; import { getUpdatedLayout } from 'lib/dashboard/getUpdatedLayout'; import history from 'lib/history'; +import { MonitorDot, MoveRight, X } from 'lucide-react'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { generatePath } from 'react-router-dom'; import { DashboardData } from 'types/api/dashboard/getAll'; -import { EditorContainer, FooterContainer } from './styles'; - function ImportJSON({ isImportJSONModalVisible, uploadedGrafana, @@ -125,62 +128,114 @@ function ImportJSON({ onModalHandler(); }; + const isDarkMode = useIsDarkMode(); + + function setEditorTheme(monaco: Monaco): void { + monaco.editor.defineTheme('my-theme', { + base: 'vs-dark', + inherit: true, + rules: [ + { token: 'string.key.json', foreground: Color.BG_VANILLA_400 }, + { token: 'string.value.json', foreground: Color.BG_ROBIN_400 }, + ], + colors: { + 'editor.background': Color.BG_INK_300, + }, + fontFamily: 'Space Mono', + fontSize: 20, + fontWeight: 'normal', + lineHeight: 18, + letterSpacing: -0.06, + }); + } + return ( - {t('import_json')} - {t('import_dashboard_by_pasting')} - - } + width="60vw" footer={ - - - {isCreateDashboardError && getErrorNode(t('error_loading_json'))} - {isFeatureAlert && ( - - {MESSAGE.CREATE_DASHBOARD} - +
+ {isCreateDashboardError && ( +
+ {getErrorNode(t('error_loading_json'))} +
)} - + + {isUploadJSONError && ( +
+ {getErrorNode(t('error_upload_json'))} +
+ )} + +
+ false} + action="none" + data={jsonData} + > + + + + + + {isFeatureAlert && ( + + {MESSAGE.CREATE_DASHBOARD} + + )} +
+
} > -
- - false} - action="none" - data={jsonData} - > - - - {isUploadJSONError && <>{getErrorNode(t('error_upload_json'))}} - - - - {t('paste_json_below')} - setEditorValue(newValue)} - value={editorValue} - language="json" - /> - +
+
+ {t('import_json')} + + +
+ + setEditorValue(newValue || '')} + value={editorValue} + options={{ + scrollbar: { + alwaysConsumeMouseWheel: false, + }, + minimap: { + enabled: false, + }, + fontSize: 14, + fontFamily: 'Space Mono', + }} + theme={isDarkMode ? 'my-theme' : 'light'} + // eslint-disable-next-line react/jsx-no-bind + beforeMount={setEditorTheme} + />
); diff --git a/frontend/src/container/ListOfDashboard/ImportJSON/styles.ts b/frontend/src/container/ListOfDashboard/ImportJSON/styles.ts deleted file mode 100644 index 7dd936baef..0000000000 --- a/frontend/src/container/ListOfDashboard/ImportJSON/styles.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Space } from 'antd'; -import styled from 'styled-components'; - -export const EditorContainer = styled.div` - margin-top: 2rem; -`; - -export const FooterContainer = styled(Space)` - display: flex; -`; From 67a360d3e2bfcaa14d81ecd93714b2301ad04103 Mon Sep 17 00:00:00 2001 From: Yunus A M Date: Tue, 16 Apr 2024 16:50:10 +0530 Subject: [PATCH 05/42] feat: new dashboard templates modal --- .../Images/blankDashboardTemplatePreview.svg | 234 ++++++++++++++++++ .../public/Images/redisTemplatePreview.svg | 9 + .../src/assets/CustomIcons/ApacheIcon.tsx | 176 +++++++++++++ .../src/assets/CustomIcons/DockerIcon.tsx | 28 +++ .../assets/CustomIcons/ElasticSearchIcon.tsx | 36 +++ .../src/assets/CustomIcons/HerokuIcon.tsx | 27 ++ .../src/assets/CustomIcons/KubernetesIcon.tsx | 22 ++ .../src/assets/CustomIcons/MongoDBIcon.tsx | 68 +++++ frontend/src/assets/CustomIcons/MySQLIcon.tsx | 28 +++ frontend/src/assets/CustomIcons/NginxIcon.tsx | 22 ++ .../src/assets/CustomIcons/PostgreSQLIcon.tsx | 40 +++ frontend/src/assets/CustomIcons/RedisIcon.tsx | 60 +++++ .../DashboardTemplatesModal.styles.scss | 170 +++++++++++++ .../DashboardTemplatesModal.tsx | 211 ++++++++++++++++ .../ListOfDashboard/DashboardsList.tsx | 23 +- frontend/src/periscope.scss | 2 +- 16 files changed, 1153 insertions(+), 3 deletions(-) create mode 100644 frontend/public/Images/blankDashboardTemplatePreview.svg create mode 100644 frontend/public/Images/redisTemplatePreview.svg create mode 100644 frontend/src/assets/CustomIcons/ApacheIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/DockerIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/ElasticSearchIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/HerokuIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/KubernetesIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/MongoDBIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/MySQLIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/NginxIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/PostgreSQLIcon.tsx create mode 100644 frontend/src/assets/CustomIcons/RedisIcon.tsx create mode 100644 frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.styles.scss create mode 100644 frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx diff --git a/frontend/public/Images/blankDashboardTemplatePreview.svg b/frontend/public/Images/blankDashboardTemplatePreview.svg new file mode 100644 index 0000000000..5c93cf3dfa --- /dev/null +++ b/frontend/public/Images/blankDashboardTemplatePreview.svg @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/Images/redisTemplatePreview.svg b/frontend/public/Images/redisTemplatePreview.svg new file mode 100644 index 0000000000..aed4e97755 --- /dev/null +++ b/frontend/public/Images/redisTemplatePreview.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/CustomIcons/ApacheIcon.tsx b/frontend/src/assets/CustomIcons/ApacheIcon.tsx new file mode 100644 index 0000000000..42deba96bd --- /dev/null +++ b/frontend/src/assets/CustomIcons/ApacheIcon.tsx @@ -0,0 +1,176 @@ +export default function ApacheIcon(): JSX.Element { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/frontend/src/assets/CustomIcons/DockerIcon.tsx b/frontend/src/assets/CustomIcons/DockerIcon.tsx new file mode 100644 index 0000000000..ef91bb7c9d --- /dev/null +++ b/frontend/src/assets/CustomIcons/DockerIcon.tsx @@ -0,0 +1,28 @@ +export default function DockerIcon(): JSX.Element { + return ( + + + + + + + + + + + ); +} diff --git a/frontend/src/assets/CustomIcons/ElasticSearchIcon.tsx b/frontend/src/assets/CustomIcons/ElasticSearchIcon.tsx new file mode 100644 index 0000000000..d251b7d756 --- /dev/null +++ b/frontend/src/assets/CustomIcons/ElasticSearchIcon.tsx @@ -0,0 +1,36 @@ +export default function ElasticSearchIcon(): JSX.Element { + return ( + + + + + + + + + ); +} diff --git a/frontend/src/assets/CustomIcons/HerokuIcon.tsx b/frontend/src/assets/CustomIcons/HerokuIcon.tsx new file mode 100644 index 0000000000..3d68fdb6e4 --- /dev/null +++ b/frontend/src/assets/CustomIcons/HerokuIcon.tsx @@ -0,0 +1,27 @@ +function HerokuIcon(): JSX.Element { + return ( + + + + + + + + + + + ); +} + +export default HerokuIcon; diff --git a/frontend/src/assets/CustomIcons/KubernetesIcon.tsx b/frontend/src/assets/CustomIcons/KubernetesIcon.tsx new file mode 100644 index 0000000000..280febebbe --- /dev/null +++ b/frontend/src/assets/CustomIcons/KubernetesIcon.tsx @@ -0,0 +1,22 @@ +export default function KubernetesIcon(): JSX.Element { + return ( + + + + + ); +} diff --git a/frontend/src/assets/CustomIcons/MongoDBIcon.tsx b/frontend/src/assets/CustomIcons/MongoDBIcon.tsx new file mode 100644 index 0000000000..d0bd3c4680 --- /dev/null +++ b/frontend/src/assets/CustomIcons/MongoDBIcon.tsx @@ -0,0 +1,68 @@ +export default function MongoDBIcon(): JSX.Element { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/frontend/src/assets/CustomIcons/MySQLIcon.tsx b/frontend/src/assets/CustomIcons/MySQLIcon.tsx new file mode 100644 index 0000000000..1cebec32ba --- /dev/null +++ b/frontend/src/assets/CustomIcons/MySQLIcon.tsx @@ -0,0 +1,28 @@ +export default function MySQLIcon(): JSX.Element { + return ( + + + + + + + + + + + ); +} diff --git a/frontend/src/assets/CustomIcons/NginxIcon.tsx b/frontend/src/assets/CustomIcons/NginxIcon.tsx new file mode 100644 index 0000000000..6e93057ab1 --- /dev/null +++ b/frontend/src/assets/CustomIcons/NginxIcon.tsx @@ -0,0 +1,22 @@ +function NginxIcon(): JSX.Element { + return ( + + + + + ); +} + +export default NginxIcon; diff --git a/frontend/src/assets/CustomIcons/PostgreSQLIcon.tsx b/frontend/src/assets/CustomIcons/PostgreSQLIcon.tsx new file mode 100644 index 0000000000..b3c2b1eed2 --- /dev/null +++ b/frontend/src/assets/CustomIcons/PostgreSQLIcon.tsx @@ -0,0 +1,40 @@ +export default function PostgreSQLIcon(): JSX.Element { + return ( + + + + + + + + + + + + + + ); +} diff --git a/frontend/src/assets/CustomIcons/RedisIcon.tsx b/frontend/src/assets/CustomIcons/RedisIcon.tsx new file mode 100644 index 0000000000..714eeb302f --- /dev/null +++ b/frontend/src/assets/CustomIcons/RedisIcon.tsx @@ -0,0 +1,60 @@ +export default function RedisIcon(): JSX.Element { + return ( + + + + + + + + + + + + + + + + + + + ); +} diff --git a/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.styles.scss b/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.styles.scss new file mode 100644 index 0000000000..a6df7ffa68 --- /dev/null +++ b/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.styles.scss @@ -0,0 +1,170 @@ +.new-dashboard-templates-modal { + .ant-modal-content { + border-radius: 4px; + border: 1px solid var(--Slate-400, #1d212d); + background: linear-gradient( + 139deg, + rgba(18, 19, 23, 0.8) 0%, + rgba(18, 19, 23, 0.9) 98.68% + ); + box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(20px); + + padding: 0; + } + + .new-dashboard-templates-content-header { + padding: 16px; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid var(--Slate-500, #161922); + } + + .new-dashboard-templates-content { + overflow: hidden; + display: flex; + position: relative; + + .new-dashboard-templates-list { + padding: 16px 8px; + height: 100%; + width: 25%; + box-sizing: border-box; + border-right: 1px solid var(--Slate-500, #161922); + + .templates-list { + display: flex; + flex-direction: column; + gap: 8px; + padding: 16px 0; + + .template-list-item { + display: flex; + gap: 8px; + padding: 4px 12px; + align-items: center; + cursor: pointer; + height: 32px; + box-sizing: border-box; + + .template-icon { + display: flex; + height: 14px; + width: 14px; + align-items: center; + justify-content: center; + } + + .template-name { + color: #c0c1c3; + font-style: normal; + font-weight: 300; + line-height: 18px; + } + + &:hover { + border-radius: 3px; + background: rgba(171, 189, 255, 0.08); + } + + &.active { + border-radius: 3px; + background: rgba(171, 189, 255, 0.08); + } + } + } + } + + .new-dashboard-template-preview { + flex: 1; + position: relative; + + .template-preview-header { + padding: 16px; + + display: flex; + gap: 8px; + align-items: center; + justify-content: space-between; + + .template-preview-title { + display: flex; + justify-content: center; + align-items: center; + gap: 16px; + + .template-preview-icon { + height: 40px; + width: 40px; + flex-shrink: 0; + border-radius: 2px; + border: 1px solid var(--bg-ink-50); + background: var(--bg-ink-300); + display: flex; + align-items: center; + justify-content: center; + } + + .template-info { + .template-name { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + + .template-description { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 18px; /* 150% */ + } + } + } + } + + .template-preview-image { + display: flex; + justify-content: center; + align-items: center; + margin: 24px; + height: calc(100% - 144px); + position: relative; + + img { + width: 100%; + max-width: 100%; + padding: 24px; + border: 1px solid var(--bg-ink-50); + background: var(--bg-ink-300); + max-height: 440px; + object-fit: contain; + } + } + } + } + + .new-dashboard-templates-modal-footer { + .create-dashboard-json-error { + margin-bottom: 8px; + display: flex; + } + + .action-btns-container { + display: flex; + justify-content: space-between; + } + } + + .ant-modal-footer { + margin-top: 0; + padding: 16px; + border-top: 1px solid var(--Slate-500, #161922); + } +} diff --git a/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx b/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx new file mode 100644 index 0000000000..d2088736bb --- /dev/null +++ b/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx @@ -0,0 +1,211 @@ +/* eslint-disable sonarjs/no-duplicate-string */ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +/* eslint-disable @typescript-eslint/explicit-function-return-type */ +import './DashboardTemplatesModal.styles.scss'; + +import { Button, Input, Modal, Typography } from 'antd'; +import ApacheIcon from 'assets/CustomIcons/ApacheIcon'; +import DockerIcon from 'assets/CustomIcons/DockerIcon'; +import ElasticSearchIcon from 'assets/CustomIcons/ElasticSearchIcon'; +import HerokuIcon from 'assets/CustomIcons/HerokuIcon'; +import KubernetesIcon from 'assets/CustomIcons/KubernetesIcon'; +import MongoDBIcon from 'assets/CustomIcons/MongoDBIcon'; +import MySQLIcon from 'assets/CustomIcons/MySQLIcon'; +import NginxIcon from 'assets/CustomIcons/NginxIcon'; +import PostgreSQLIcon from 'assets/CustomIcons/PostgreSQLIcon'; +import RedisIcon from 'assets/CustomIcons/RedisIcon'; +import cx from 'classnames'; +import { ConciergeBell, DraftingCompass, Drill, Plus, X } from 'lucide-react'; +import { useState } from 'react'; + +const templatesList = [ + { + name: 'Blank dashboard', + icon: , + id: 'blank', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'Alert Manager', + icon: , + id: 'alertManager', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'Apache', + icon: , + id: 'apache', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'Docker', + icon: , + id: 'docker', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'Elasticsearch', + icon: , + id: 'elasticSearch', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'MongoDB', + icon: , + id: 'mongoDB', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'Heroku', + icon: , + id: 'heroku', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'Nginx', + icon: , + id: 'nginx', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'Kubernetes', + icon: , + id: 'kubernetes', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'MySQL', + icon: , + id: 'mySQL', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'PostgreSQL', + icon: , + id: 'postgreSQL', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, + { + name: 'Redis', + icon: , + id: 'redis', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/redisTemplatePreview.svg', + }, + { + name: 'AWS', + icon: , + id: 'aws', + description: 'Create a custom dashboard from scratch.', + previewImage: '/Images/blankDashboardTemplatePreview.svg', + }, +]; + +interface DashboardTemplatesModalProps { + showNewDashboardTemplatesModal: boolean; + onCreateNewDashboard: () => void; + onCancel: () => void; +} + +export default function DashboardTemplatesModal({ + showNewDashboardTemplatesModal, + onCreateNewDashboard, + onCancel, +}: DashboardTemplatesModalProps): JSX.Element { + const [selectedDashboardTemplate, setSelectedDashboardTemplate] = useState( + templatesList[0], + ); + + return ( + +
+
+ New Dashboard + + +
+ +
+
+ + +
+ {templatesList.map((template) => ( +
setSelectedDashboardTemplate(template)} + > +
{template.icon}
+
{template.name}
+
+ ))} +
+
+ +
+
+
+
+ {selectedDashboardTemplate.icon} +
+ +
+
{selectedDashboardTemplate.name}
+ +
+ {selectedDashboardTemplate.description} +
+
+
+ +
+ +
+
+ +
+ {`${selectedDashboardTemplate.name}-preview`} +
+
+
+
+
+ ); +} diff --git a/frontend/src/container/ListOfDashboard/DashboardsList.tsx b/frontend/src/container/ListOfDashboard/DashboardsList.tsx index b414a1bee8..ff032eac8f 100644 --- a/frontend/src/container/ListOfDashboard/DashboardsList.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardsList.tsx @@ -61,6 +61,7 @@ import { USER_ROLES } from 'types/roles'; import useSortableTable from '../../hooks/ResizeTable/useSortableTable'; import useUrlQuery from '../../hooks/useUrlQuery'; import { GettableAlert } from '../../types/api/alerts/get'; +import DashboardTemplatesModal from './DashboardTemplates/DashboardTemplatesModal'; import ImportJSON from './ImportJSON'; import { filterDashboard } from './utils'; @@ -83,6 +84,10 @@ function DashboardsList(): JSX.Element { ); const [searchValue, setSearchValue] = useState(''); + const [ + showNewDashboardTemplatesModal, + setShowNewDashboardTemplatesModal, + ] = useState(false); const { t } = useTranslation('dashboard'); @@ -312,9 +317,14 @@ function DashboardsList(): JSX.Element { const createDashboardItems: MenuProps['items'] = [ { label: ( -
+
{ + setShowNewDashboardTemplatesModal(true); + }} + > {' '} - Create dashboard{' '} + Create dashboard
), key: '0', @@ -369,6 +379,7 @@ function DashboardsList(): JSX.Element { overlayClassName="new-dashboard-menu" menu={{ items: createDashboardItems }} placement="bottomRight" + trigger={['click']} >
); diff --git a/frontend/src/periscope.scss b/frontend/src/periscope.scss index 53c14deb53..423776d4aa 100644 --- a/frontend/src/periscope.scss +++ b/frontend/src/periscope.scss @@ -14,6 +14,7 @@ padding: 6px; border: 1px solid var(--bg-slate-400, #1d212d); + border-radius: 3px; background: var(--bg-ink-400, #121317); box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); color: var(--bg-vanilla-400, #c0c1c3); @@ -31,7 +32,6 @@ box-shadow: 0 2px 0 rgba(62, 86, 245, 0.09); } - &:disabled { opacity: 0.5; } From 5890184f45574fa7b78fd0f567998ec00a41515e Mon Sep 17 00:00:00 2001 From: Yunus A M Date: Thu, 18 Apr 2024 00:21:57 +0530 Subject: [PATCH 06/42] feat: add template filter logic --- .../DashboardTemplatesModal.styles.scss | 32 +++++++++++++++++-- .../DashboardTemplatesModal.tsx | 22 ++++++++++--- .../src/container/ListOfDashboard/utils.ts | 16 +++++++++- frontend/src/types/api/dashboard/getAll.ts | 8 +++++ 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.styles.scss b/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.styles.scss index a6df7ffa68..c75ca53893 100644 --- a/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.styles.scss +++ b/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.styles.scss @@ -11,6 +11,15 @@ backdrop-filter: blur(20px); padding: 0; + height: 72vh; + + .ant-modal-body { + height: 100%; + } + } + + .new-dashboard-templates-content-container { + height: 100%; } .new-dashboard-templates-content-header { @@ -19,6 +28,8 @@ align-items: center; justify-content: space-between; border-bottom: 1px solid var(--Slate-500, #161922); + height: 60px; + box-sizing: border-box; } .new-dashboard-templates-content { @@ -26,18 +37,33 @@ display: flex; position: relative; + height: calc(100% - 60px); + .new-dashboard-templates-list { padding: 16px 8px; height: 100%; width: 25%; - box-sizing: border-box; border-right: 1px solid var(--Slate-500, #161922); + .new-dashboard-templates-search { + height: 32px; + margin-bottom: 16px; + } + .templates-list { display: flex; flex-direction: column; gap: 8px; - padding: 16px 0; + padding-bottom: 16px; + overflow-y: auto; + box-sizing: border-box; + + height: calc(100% - 64px); + + &::-webkit-scrollbar { + height: 1rem; + width: 0.1rem; + } .template-list-item { display: flex; @@ -143,7 +169,7 @@ padding: 24px; border: 1px solid var(--bg-ink-50); background: var(--bg-ink-300); - max-height: 440px; + max-height: 100%; object-fit: contain; } } diff --git a/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx b/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx index d2088736bb..eeb540f929 100644 --- a/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx +++ b/frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx @@ -17,9 +17,12 @@ import PostgreSQLIcon from 'assets/CustomIcons/PostgreSQLIcon'; import RedisIcon from 'assets/CustomIcons/RedisIcon'; import cx from 'classnames'; import { ConciergeBell, DraftingCompass, Drill, Plus, X } from 'lucide-react'; -import { useState } from 'react'; +import { ChangeEvent, useState } from 'react'; +import { DashboardTemplate } from 'types/api/dashboard/getAll'; -const templatesList = [ +import { filterTemplates } from '../utils'; + +const templatesList: DashboardTemplate[] = [ { name: 'Blank dashboard', icon: , @@ -128,6 +131,16 @@ export default function DashboardTemplatesModal({ templatesList[0], ); + const [dashboardTemplates, setDashboardTemplates] = useState(templatesList); + + const handleDashboardTemplateSearch = ( + event: ChangeEvent, + ) => { + const searchText = event.target.value; + const filteredTemplates = filterTemplates(searchText, templatesList); + setDashboardTemplates(filteredTemplates); + }; + return (
@@ -150,10 +163,11 @@ export default function DashboardTemplatesModal({
- {templatesList.map((template) => ( + {dashboardTemplates.map((template) => (
{ + const searchValueLowerCase = searchValue?.toLowerCase(); + + return dashboardList.filter((item: DashboardTemplate) => { + const { name } = item; + + // Check if any property value contains the searchValue + return name.toLowerCase().includes(searchValueLowerCase); + }); +}; diff --git a/frontend/src/types/api/dashboard/getAll.ts b/frontend/src/types/api/dashboard/getAll.ts index e7faf83023..53e2ca31a7 100644 --- a/frontend/src/types/api/dashboard/getAll.ts +++ b/frontend/src/types/api/dashboard/getAll.ts @@ -54,6 +54,14 @@ export interface Dashboard { isLocked?: boolean; } +export interface DashboardTemplate { + name: string; + icon: React.ReactElement; + id: string; + description: string; + previewImage: string; +} + export interface DashboardData { uuid?: string; description?: string; From 9a9a77f45206c6adfc06f3b5cd3436940939cf96 Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Tue, 23 Apr 2024 19:48:37 +0530 Subject: [PATCH 07/42] feat: revamp the overview settings modal (#4894) * feat: revamp the overview settings modal * feat: dashboard settings variable landing page * feat: dashboard add variable button settings * feat: add variable modal changes * feat: handle the unsaved changes for general settings --- .../Description.styles.scss | 37 ++ .../DashboardDescription/SettingsDrawer.tsx | 5 +- .../DashboardDescription/index.tsx | 2 +- .../DashboardSettings.styles.scss | 101 +++++ .../DashboardSettingsContent.styles.scss | 49 +++ .../General/AddTags/AddTags.styles.scss | 4 + .../General/AddTags/index.tsx | 50 +-- .../General/AddTags/styles.ts | 3 + .../General/GeneralSettings.styles.scss | 91 ++++ .../DashboardSettings/General/index.tsx | 151 +++++-- .../VariableItem/VariableItem.styles.scss | 218 ++++++++++ .../Variables/VariableItem/VariableItem.tsx | 401 ++++++++++-------- .../DashboardSettings/Variables/index.tsx | 87 ++-- .../NewDashboard/DashboardSettings/index.tsx | 23 +- 14 files changed, 926 insertions(+), 296 deletions(-) create mode 100644 frontend/src/container/NewDashboard/DashboardSettings/DashboardSettingsContent.styles.scss create mode 100644 frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/AddTags.styles.scss create mode 100644 frontend/src/container/NewDashboard/DashboardSettings/General/GeneralSettings.styles.scss diff --git a/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss b/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss index a5c677c679..79e871c347 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss @@ -1,3 +1,40 @@ +.settings-container-root { + .ant-drawer-wrapper-body { + border-left: 1px solid var(--bg-slate-500); + background: var(--bg-ink-400); + box-shadow: -4px 10px 16px 2px rgba(0, 0, 0, 0.2); + + .ant-drawer-header { + height: 48px; + border-bottom: 1px solid var(--Slate-500, hsl(225, 21%, 11%)); + padding: 14px 14px 14px 15px; + + .ant-drawer-header-title { + gap: 32px; + + .ant-drawer-title { + color: var(--bg-vanilla-400); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + + .ant-drawer-close { + height: 16px; + width: 16px; + } + } + } + + .ant-drawer-body { + padding: 16px; + } + } +} + .dashboard-description-container { box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.25); diff --git a/frontend/src/container/NewDashboard/DashboardDescription/SettingsDrawer.tsx b/frontend/src/container/NewDashboard/DashboardDescription/SettingsDrawer.tsx index c8a13acf0f..b927ed0b91 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/SettingsDrawer.tsx +++ b/frontend/src/container/NewDashboard/DashboardDescription/SettingsDrawer.tsx @@ -1,3 +1,5 @@ +import './Description.styles.scss'; + import { Button, Tooltip } from 'antd'; import { Cog } from 'lucide-react'; import { useState } from 'react'; @@ -31,9 +33,10 @@ function SettingsDrawer({ drawerTitle }: { drawerTitle: string }): JSX.Element { diff --git a/frontend/src/container/NewDashboard/DashboardDescription/index.tsx b/frontend/src/container/NewDashboard/DashboardDescription/index.tsx index c916ec7501..7dfd07e41f 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardDescription/index.tsx @@ -100,7 +100,7 @@ function DashboardDescription(): JSX.Element {
{!isDashboardLocked && editDashboard && ( - + )} diff --git a/frontend/src/container/NewDashboard/DashboardSettings/DashboardSettings.styles.scss b/frontend/src/container/NewDashboard/DashboardSettings/DashboardSettings.styles.scss index d53e8c4070..a4f1cbd92f 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/DashboardSettings.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardSettings/DashboardSettings.styles.scss @@ -3,3 +3,104 @@ color: rgb(207, 19, 34); font-style: italic; } + +.dashboard-variable-settings-table { + .variable-name-drag { + display: flex; + align-items: center; + gap: 10px; + + .ant-table-cell { + padding: 0px !important; + border: none !important; + color: var(--Robin-400, #7190f9); + font-family: 'Space Mono'; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 18px; /* 128.571% */ + letter-spacing: -0.07px; + } + } + + .variable-description-actions { + display: flex; + align-items: center; + gap: 10px; + flex: 1 0 0; + + .variable-description { + color: var(--Sienna-400, #bd9979); + font-family: 'Space Mono'; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 18px; /* 128.571% */ + letter-spacing: -0.07px; + } + + .actions-btns { + position: absolute; + right: 10px; + display: none; + + &:hover { + display: inline-flex; + } + + .edit-variable-button { + width: 26px; + height: 22px; + border-radius: 2px; + display: flex; + padding: 4px 6px; + align-items: center; + gap: 3px; + background: var(--Slate-400, #1d212d); + } + + .delete-variable-button { + width: 26px; + height: 22px; + border-radius: 2px; + background: rgba(229, 72, 77, 0.1); + display: flex; + padding: 4px 6px; + align-items: center; + gap: 3px; + color: red; + } + } + } + + .ant-table-cell-row-hover { + .actions-btns { + display: inline-flex; + } + } + + .ant-table-thead { + .ant-table-cell { + padding: 8px 12px; + border: 1px solid var(--Slate-500, #161922); + background: unset; + } + + .ant-table-cell::before { + display: none; + } + } + + .ant-table-tbody { + .ant-table-cell { + padding: 14px; + border: 1px solid var(--Slate-500, #161922); + } + } + + .ant-table-row { + .ant-table-cell:nth-child(even) { + background: rgba(22, 25, 34, 0.4); + } + } +} diff --git a/frontend/src/container/NewDashboard/DashboardSettings/DashboardSettingsContent.styles.scss b/frontend/src/container/NewDashboard/DashboardSettings/DashboardSettingsContent.styles.scss new file mode 100644 index 0000000000..8c2fe7abaa --- /dev/null +++ b/frontend/src/container/NewDashboard/DashboardSettings/DashboardSettingsContent.styles.scss @@ -0,0 +1,49 @@ +.settings-tabs { + .ant-tabs-nav-list { + width: 228px; + height: 32px; + flex-shrink: 0; + border-radius: 2px; + border: 1px solid var(--bg-slate-400); + background: var(--bg-ink-400); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + + .ant-tabs-tab + .ant-tabs-tab { + margin: 0px; + } + + .overview-btn { + width: 114px; + display: flex; + align-items: center; + justify-content: center; + } + + .variables-btn { + width: 114px; + display: flex; + align-items: center; + justify-content: center; + } + + .ant-tabs-ink-bar { + display: none; + } + + .ant-tabs-tab-active { + .overview-btn { + border-radius: 2px 0px 0px 2px; + background: var(--bg-slate-400); + } + + .variables-btn { + border-radius: 2px 0px 0px 2px; + background: var(--bg-slate-400); + } + } + } + + .ant-tabs-nav::before { + border-bottom: none; + } +} diff --git a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/AddTags.styles.scss b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/AddTags.styles.scss new file mode 100644 index 0000000000..590df006fd --- /dev/null +++ b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/AddTags.styles.scss @@ -0,0 +1,4 @@ +.tags-input { + border: none; + padding: 0px; +} diff --git a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/index.tsx b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/index.tsx index 82c016aba0..5591750161 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/index.tsx @@ -1,5 +1,6 @@ -import { PlusOutlined } from '@ant-design/icons'; -import { Col, Tooltip, Typography } from 'antd'; +import './AddTags.styles.scss'; + +import { Col, Tooltip } from 'antd'; import Input from 'components/Input'; import { Dispatch, SetStateAction, useState } from 'react'; @@ -7,7 +8,6 @@ import { InputContainer, NewTagContainer, TagsContainer } from './styles'; function AddTags({ tags, setTags }: AddTagsProps): JSX.Element { const [inputValue, setInputValue] = useState(''); - const [inputVisible, setInputVisible] = useState(false); const [editInputIndex, setEditInputIndex] = useState(-1); const [editInputValue, setEditInputValue] = useState(''); @@ -15,7 +15,6 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element { if (inputValue) { setTags([...tags, inputValue]); } - setInputVisible(false); setInputValue(''); }; @@ -32,10 +31,6 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element { setTags(newTags); }; - const showInput = (): void => { - setInputVisible(true); - }; - const onChangeHandler = ( value: string, func: Dispatch>, @@ -87,32 +82,19 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element { ); })} - {inputVisible && ( - - - onChangeHandler(event.target.value, setInputValue) - } - onBlurHandler={handleInputConfirm} - onPressEnterHandler={handleInputConfirm} - /> - - )} - - {!inputVisible && ( - } onClick={showInput}> - - New Tag - - - )} + + + onChangeHandler(event.target.value, setInputValue) + } + onBlurHandler={handleInputConfirm} + onPressEnterHandler={handleInputConfirm} + /> + ); } diff --git a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/styles.ts b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/styles.ts index f2daefe65e..722cf41bc2 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/styles.ts +++ b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/styles.ts @@ -23,4 +23,7 @@ export const InputContainer = styled(Col)` > div { margin: 0; } + padding-left: 0px !important; + padding-right: 0px !important; + width: 100%; `; diff --git a/frontend/src/container/NewDashboard/DashboardSettings/General/GeneralSettings.styles.scss b/frontend/src/container/NewDashboard/DashboardSettings/General/GeneralSettings.styles.scss new file mode 100644 index 0000000000..ac4ef2e9cc --- /dev/null +++ b/frontend/src/container/NewDashboard/DashboardSettings/General/GeneralSettings.styles.scss @@ -0,0 +1,91 @@ +.overview-content { + display: flex; + flex-direction: column; + + .overview-settings { + border-radius: 3px; + border: 1px solid var(--bg-slate-500); + padding: 16px !important; + + .dashboard-name-input { + border-radius: 0px 2px 2px 0px; + border: 1px solid var(--bg-slate-400); + background: var(--bg-ink-300); + } + .dashboard-name { + color: var(--bg-vanilla-400); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + } + + .description-text-area { + padding: 6px 6px 6px 8px; + border-radius: 2px; + border: 1px solid var(--bg-slate-400); + background: var(--bg-ink-300); + } + } + + .overview-settings-footer { + display: flex; + justify-content: space-between; + align-items: center; + width: -webkit-fill-available; + padding: 12px 16px 12px 0px; + position: fixed; + bottom: 0; + height: 32px; + border-top: 1px solid var(--bg-slate-500); + background: var(--bg-ink-400); + + .unsaved { + display: flex; + align-items: center; + gap: 8px; + + .unsaved-dot { + width: 6px; + height: 6px; + border-radius: 50px; + background: var(--Robin-500, #4e74f8); + box-shadow: 0px 0px 6px 0px rgba(78, 116, 248, 0.4); + } + .unsaved-changes { + color: var(--Robin-400, #7190f9); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; /* 171.429% */ + letter-spacing: -0.07px; + } + } + .footer-action-btns { + display: flex; + gap: 8px; + + .discard-btn { + margin: 0px !important; + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 24px; + } + + .save-btn { + margin: 0px !important; + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 24px; + } + } + } +} diff --git a/frontend/src/container/NewDashboard/DashboardSettings/General/index.tsx b/frontend/src/container/NewDashboard/DashboardSettings/General/index.tsx index 16c98bb54e..d65343d6fc 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/General/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardSettings/General/index.tsx @@ -1,11 +1,14 @@ -import { SaveOutlined } from '@ant-design/icons'; +import './GeneralSettings.styles.scss'; + import { Col, Input, Space, Typography } from 'antd'; import { SOMETHING_WENT_WRONG } from 'constants/api'; import AddTags from 'container/NewDashboard/DashboardSettings/General/AddTags'; import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard'; import { useNotifications } from 'hooks/useNotifications'; +import { isEqual } from 'lodash-es'; +import { Check, X } from 'lucide-react'; import { useDashboard } from 'providers/Dashboard/Dashboard'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Button } from './styles'; @@ -24,6 +27,9 @@ function GeneralDashboardSettings(): JSX.Element { const [updatedDescription, setUpdatedDescription] = useState( description || '', ); + const [numberOfUnsavedChanges, setNumberOfUnsavedChanges] = useState( + 0, + ); const { t } = useTranslation('common'); @@ -57,48 +63,111 @@ function GeneralDashboardSettings(): JSX.Element { ); }; + useEffect(() => { + let numberOfUnsavedChanges = 0; + if (!isEqual(updatedTitle, selectedData?.title)) { + numberOfUnsavedChanges += 1; + } + if (!isEqual(updatedDescription, selectedData?.description)) { + numberOfUnsavedChanges += 1; + } + if (!isEqual(updatedTags, selectedData?.tags)) { + numberOfUnsavedChanges += 1; + } + setNumberOfUnsavedChanges(numberOfUnsavedChanges); + }, [ + selectedData?.description, + selectedData?.tags, + selectedData?.title, + updatedDescription, + updatedTags, + updatedTitle, + ]); + return ( - - -
- Name - setUpdatedTitle(e.target.value)} - /> -
+
+ + +
+ + Dashboard Name + + setUpdatedTitle(e.target.value)} + /> +
-
- Description - setUpdatedDescription(e.target.value)} - /> -
-
- Tags - -
-
- +
+ + Description + + setUpdatedDescription(e.target.value)} + /> +
+
+ + Tags + + +
+ + + {numberOfUnsavedChanges > 0 && ( +
+
+
+ + {numberOfUnsavedChanges} Unsaved change + +
+
+ + +
- - + )} +
); } diff --git a/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.styles.scss b/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.styles.scss index 31b92a4b3e..2e5b5c8a25 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.styles.scss @@ -6,3 +6,221 @@ margin-bottom: 1rem; flex-direction: column; } + +.variable-item-container { + display: flex; + flex-direction: column; + border-radius: 3px; + border: 1px solid var(--Slate-500, #161922); + + .all-variables { + display: flex; + padding: 10px 16px; + align-items: center; + gap: 8px; + border-bottom: 1px solid var(--Slate-500, #161922); + .all-variables-btn { + display: flex; + align-items: center; + height: 24px; + padding: 0px; + color: #c0c1c3; + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 18px; /* 128.571% */ + } + } + + .variable-item-content { + padding: 12px 16px 20px 16px; + display: flex; + flex-direction: column; + gap: 20px; + + .variable-name-section { + flex-direction: column; + gap: 8px; + + .typography-variables { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + } + + .name-input { + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + padding: 6px 6px 6px 8px; + } + } + .variable-description-section { + flex-direction: column; + gap: 8px; + + .typography-variables { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + } + + .description-input { + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + padding: 6px 6px 6px 8px; + } + } + + .variable-type-section { + justify-content: space-between; + margin-bottom: 0px; + + .typography-variables { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + } + + .variable-type-btn-group { + display: flex; + width: 342px; + height: 32px; + flex-shrink: 0; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-400, #121317); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + + .ant-btn { + width: 114px; + height: 32px; + flex-shrink: 0; + border-radius: 2px 0px 0px 2px; + } + + .variable-type-btn { + display: flex; + align-items: center; + justify-content: center; + } + + .variable-type-btn + .variable-type-btn { + border-left: 1px solid #1d212d; + } + .selected { + background: var(--Slate-400, #1d212d); + } + } + } + + .sort-values-section { + justify-content: space-between; + margin-bottom: 0; + + .typography-variables { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + + .typography-sort { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 166.667% */ + letter-spacing: -0.06px; + } + + .sort-input { + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + + .ant-select-selector { + width: 192px; + height: 32px; + padding: 6px 6px 6px 8px; + background: var(--Ink-300, #16181d); + } + } + } + + .multiple-values-section { + justify-content: space-between; + margin-bottom: 0; + + .typography-variables { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + width: 339px; + } + } + + .all-option-section { + justify-content: space-between; + margin-bottom: 0; + + .typography-variables { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + width: 339px; + } + } + } +} + +.variable-item-footer { + margin-top: 12px; + display: flex; + flex-direction: row-reverse; + + .footer-btn-discard { + display: flex; + align-items: center; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d2023); + background: var(--Slate-500, #161922); + height: 34px; + padding: 4px 8px 4px 10px; + box-shadow: none; + } + + .footer-btn-save { + display: flex; + align-items: center; + border-radius: 2px; + border: 1px solid var(--Robin-500, #4e74f8); + background: var(--Robin-500, #4e74f8); + width: 123px; + height: 34px; + padding: 4px 8px 4px 10px; + box-shadow: none; + } +} diff --git a/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.tsx b/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.tsx index a9b0aea09f..fb6c383b5f 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.tsx +++ b/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.tsx @@ -2,20 +2,28 @@ import './VariableItem.styles.scss'; import { orange } from '@ant-design/colors'; -import { Button, Divider, Input, Select, Switch, Tag, Typography } from 'antd'; +import { Button, Input, Select, Switch, Tag, Typography } from 'antd'; import dashboardVariablesQuery from 'api/dashboard/variables/dashboardVariablesQuery'; +import cx from 'classnames'; import Editor from 'components/Editor'; import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; import { commaValuesParser } from 'lib/dashbaordVariables/customCommaValuesParser'; import sortValues from 'lib/dashbaordVariables/sortVariableValues'; import { map } from 'lodash-es'; +import { + ArrowLeft, + Check, + ClipboardType, + DatabaseZap, + LayoutList, + X, +} from 'lucide-react'; import { useCallback, useEffect, useState } from 'react'; import { useQuery } from 'react-query'; import { IDashboardVariable, TSortVariableValuesType, TVariableQueryType, - VariableQueryTypeArr, VariableSortTypeArr, } from 'types/api/dashboard/getAll'; import { v4 as generateUUID } from 'uuid'; @@ -169,219 +177,266 @@ function VariableItem({ }, []); return ( -
-
- - - Name - -
- { - setVariableName(e.target.value); - setErrorName( - !validateName(e.target.value) && e.target.value !== variableData.name, - ); - }} - /> -
- - {errorName ? 'Variable name already exists' : ''} - -
-
-
- - - Description - - - setVariableDescription(e.target.value)} - /> - - - - Type - - - - - - Options - - {queryType === 'QUERY' && ( -
+ All variables + +
+
+ - Query + Name - -
- setVariableQueryValue(e)} - height="240px" - options={{ - fontSize: 13, - wordWrap: 'on', - lineNumbers: 'off', - glyphMargin: false, - folding: false, - lineDecorationsWidth: 0, - lineNumbersMinChars: 0, - minimap: { - enabled: false, - }, +
+ { + setVariableName(e.target.value); + setErrorName( + !validateName(e.target.value) && e.target.value !== variableData.name, + ); }} /> - +
+ + {errorName ? 'Variable name already exists' : ''} + +
-
- )} - {queryType === 'CUSTOM' && ( - + + - Values separated by comma + Description + { - setVariableCustomValue(e.target.value); - setPreviewValues( - sortValues( - commaValuesParser(e.target.value), - variableSortType, - ) as never, - ); - }} + value={variableDescription} + placeholder="Enter a description for the variable" + className="description-input" + rows={3} + onChange={(e): void => setVariableDescription(e.target.value)} /> - )} - {queryType === 'TEXTBOX' && ( - + - Default Value + Variable Type - { - setVariableTextboxValue(e.target.value); - }} - placeholder="Default value if any" - style={{ width: 400 }} - /> + +
+ + + +
- )} - {(queryType === 'QUERY' || queryType === 'CUSTOM') && ( - <> - + {queryType === 'QUERY' && ( +
- Preview of Values + Query -
- {errorPreview ? ( - {errorPreview} - ) : ( - map(previewValues, (value, idx) => ( - {value.toString()} - )) - )} + +
+ setVariableQueryValue(e)} + height="240px" + options={{ + fontSize: 13, + wordWrap: 'on', + lineNumbers: 'off', + glyphMargin: false, + folding: false, + lineDecorationsWidth: 0, + lineNumbersMinChars: 0, + minimap: { + enabled: false, + }, + }} + /> +
- +
+ )} + {queryType === 'CUSTOM' && ( - Sort + Values separated by comma - - + onChange={(e): void => { + setVariableCustomValue(e.target.value); + setPreviewValues( + sortValues( + commaValuesParser(e.target.value), + variableSortType, + ) as never, + ); + }} + /> + )} + {queryType === 'TEXTBOX' && ( - Enable multiple values to be checked + Default Value - { - setVariableMultiSelect(e); - if (!e) { - setVariableShowALLOption(false); - } + setVariableTextboxValue(e.target.value); }} + placeholder="Default value if any" + style={{ width: 400 }} /> - {variableMultiSelect && ( + )} + {(queryType === 'QUERY' || queryType === 'CUSTOM') && ( + <> - Include an option for ALL values + Preview of Values + +
+ {errorPreview ? ( + {errorPreview} + ) : ( + map(previewValues, (value, idx) => ( + {value.toString()} + )) + )} +
+
+ + + Sort Values + + Sort the query output values + + + + + + + + + Enable multiple values to be checked + setVariableShowALLOption(e)} + checked={variableMultiSelect} + onChange={(e): void => { + setVariableMultiSelect(e); + if (!e) { + setVariableShowALLOption(false); + } + }} /> - )} - - )} + {variableMultiSelect && ( + + + + Include an option for ALL values + + + setVariableShowALLOption(e)} + /> + + )} + + )} +
-
- - -
-
+ ); } diff --git a/frontend/src/container/NewDashboard/DashboardSettings/Variables/index.tsx b/frontend/src/container/NewDashboard/DashboardSettings/Variables/index.tsx index 4aa1bf9b22..e68a75a7d1 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/Variables/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardSettings/Variables/index.tsx @@ -1,7 +1,6 @@ import '../DashboardSettings.styles.scss'; -import { blue, red } from '@ant-design/colors'; -import { MenuOutlined, PlusOutlined } from '@ant-design/icons'; +import { HolderOutlined, PlusOutlined } from '@ant-design/icons'; import type { DragEndEvent, UniqueIdentifier } from '@dnd-kit/core'; import { DndContext, @@ -18,7 +17,7 @@ import { RowProps } from 'antd/lib'; import { convertVariablesToDbFormat } from 'container/NewDashboard/DashboardVariablesSelection/util'; import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard'; import { useNotifications } from 'hooks/useNotifications'; -import { PencilIcon, TrashIcon } from 'lucide-react'; +import { PenLine, Trash2 } from 'lucide-react'; import { useDashboard } from 'providers/Dashboard/Dashboard'; import React, { useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -53,18 +52,22 @@ function TableRow({ children, ...props }: RowProps): JSX.Element { // eslint-disable-next-line react/jsx-props-no-spreading {React.Children.map(children, (child) => { - if ((child as React.ReactElement).key === 'sort') { + if ((child as React.ReactElement).key === 'name') { return React.cloneElement(child as React.ReactElement, { children: ( - +
+ + {child} +
), }); } + return child; })} @@ -245,47 +248,42 @@ function VariablesSetting(): JSX.Element { !existingVariableNamesMap[name]; const columns = [ - { - key: 'sort', - width: '10%', - }, { title: 'Variable', dataIndex: 'name', - width: '40%', + width: '50%', key: 'name', }, { title: 'Description', - dataIndex: 'description', - width: '35%', + width: '50%', key: 'description', - }, - { - title: 'Actions', - width: '15%', - key: 'action', render: (variable: IDashboardVariable): JSX.Element => ( - - - - +
+ + {variable.description} + + + + + +
), }, ]; @@ -353,6 +351,10 @@ function VariablesSetting(): JSX.Element { flexDirection: 'row', justifyContent: 'flex-end', padding: '0.5rem 0', + position: 'absolute', + top: '-56px', + right: '0px', + zIndex: '1', }} > + ), key: 'general', children: , }, - { label: 'Variables', key: 'variables', children: }, + { + label: ( + + ), + key: 'variables', + children: , + }, ]; - return ; + return ; } export default DashboardSettingsContent; From f6b9971e617f6944057bf8ff89ff88a3ca824d8f Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Thu, 25 Apr 2024 11:09:00 +0530 Subject: [PATCH 08/42] feat: follow ups for side panel section for dashboards (#4906) * feat: changes for tags input * feat: side panel header styles * feat: changes for textbox variable * feat: handle changes for custom type variable * feat: overflow preview vales * feat: overflow preview vales --- .../Description.styles.scss | 6 +- .../General/AddTags/AddTags.styles.scss | 27 ++++ .../General/AddTags/index.tsx | 11 +- .../General/AddTags/styles.ts | 3 +- .../VariableItem/VariableItem.styles.scss | 133 ++++++++++++++++++ .../Variables/VariableItem/VariableItem.tsx | 61 ++++---- 6 files changed, 211 insertions(+), 30 deletions(-) diff --git a/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss b/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss index 79e871c347..f0fa289ec9 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss @@ -7,10 +7,10 @@ .ant-drawer-header { height: 48px; border-bottom: 1px solid var(--Slate-500, hsl(225, 21%, 11%)); - padding: 14px 14px 14px 15px; + padding: 14px 14px 14px 11px; .ant-drawer-header-title { - gap: 32px; + gap: 16px; .ant-drawer-title { color: var(--bg-vanilla-400); @@ -20,6 +20,8 @@ font-weight: 400; line-height: 20px; /* 142.857% */ letter-spacing: -0.07px; + padding-left: 16px; + border-left: 1px solid #161922; } .ant-drawer-close { diff --git a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/AddTags.styles.scss b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/AddTags.styles.scss index 590df006fd..2e03f20449 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/AddTags.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/AddTags.styles.scss @@ -1,4 +1,31 @@ .tags-input { + display: flex; border: none; padding: 0px; + width: 183px; + height: 24px; + padding: 3px 1px; + flex-shrink: 0; +} + +.tag-container { + color: var(--Sienna-400, #bd9979); + font-family: 'Space Mono'; + font-size: 13px; + font-style: normal; + font-weight: 500; + line-height: 20px; /* 153.846% */ + letter-spacing: 0.52px; + height: 24px; + flex-shrink: 0; + border-radius: 50px; + border: 1px solid rgba(173, 127, 88, 0.2); + background: rgba(173, 127, 88, 0.1); + padding: 2px 8px; +} + +.edit-input { + .ant-form-item { + margin-bottom: 0px; + } } diff --git a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/index.tsx b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/index.tsx index 5591750161..154e4a2ec4 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/index.tsx @@ -43,7 +43,7 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element { {tags.map((tag, index) => { if (editInputIndex === index) { return ( - + 20; const tagElem = ( - handleClose(tag)}> + handleClose(tag)} + className="tag-container" + > { setEditInputIndex(index); @@ -87,7 +92,7 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element { type="text" value={inputValue} rootClassName="tags-input" - placeholder="Start typing your tag name..." + placeholder="Start typing your tag name" onChangeHandler={(event): void => onChangeHandler(event.target.value, setInputValue) } diff --git a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/styles.ts b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/styles.ts index 722cf41bc2..1fbc8a6974 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/styles.ts +++ b/frontend/src/container/NewDashboard/DashboardSettings/General/AddTags/styles.ts @@ -4,6 +4,8 @@ import styled from 'styled-components'; export const TagsContainer = styled.div` display: flex; align-items: center; + flex-flow: wrap; + gap: 6px; `; export const NewTagContainer = styled(Tag)` @@ -25,5 +27,4 @@ export const InputContainer = styled(Col)` } padding-left: 0px !important; padding-right: 0px !important; - width: 100%; `; diff --git a/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.styles.scss b/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.styles.scss index 2e5b5c8a25..6e0b28090b 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.styles.scss @@ -83,6 +83,7 @@ .variable-type-section { justify-content: space-between; margin-bottom: 0px; + align-items: center; .typography-variables { color: var(--Vanilla-400, #c0c1c3); @@ -193,6 +194,138 @@ width: 339px; } } + + .variable-textbox-section { + justify-content: space-between; + margin-bottom: 0; + align-items: center; + + .typography-variables { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + } + + .default-input { + display: flex; + height: 32px; + padding: 6px 6px 6px 8px; + align-items: flex-start; + gap: 4px; + flex: 1 0 0; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + width: 342px; + } + } + + .variable-custom-section { + margin-bottom: 0px; + .custom-collapse { + width: 100%; + border-radius: 3px 3px 0px 0px; + border: 1px solid var(--Slate-500, #161922); + + .ant-collapse-item { + border-bottom: none; + } + + .ant-collapse-header { + height: 38px; + border-radius: 3px 3px 0px 0px; + background: var(--bg-ink-300); + align-items: center; + padding: 12px; + gap: 8px; + + .ant-collapse-expand-icon { + padding-inline-end: 0px; + } + + .ant-collapse-header-text { + color: var(--Robin-400, #7190f9); + font-family: 'Space Mono'; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 18px; /* 128.571% */ + display: flex; + padding: 1px 2px; + align-items: center; + gap: 10px; + border-radius: 2px; + background: rgba(113, 144, 249, 0.08); + } + } + + .ant-collapse-content { + border-top: none; + + .ant-collapse-content-box { + padding: 0px; + } + + .comma-input { + height: 109px; + border: none; + } + } + } + } + + .variables-preview-section { + display: flex; + flex-direction: column; + margin-bottom: 0px; + border-radius: 0px 0px 3px 3px; + border: 1px solid var(--Slate-500, #161922); + height: 70px; + margin-top: -20px; + border-collapse: collapse; + gap: 5px; + + .typography-variables { + color: var(--Robin-400, #7190f9); + font-family: 'Space Mono'; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 18px; /* 128.571% */ + display: inline-flex; + padding: 1px 2px; + align-items: center; + gap: 10px; + border-radius: 0px 0px 2px 0px; + background: rgba(113, 144, 249, 0.08); + } + + .preview-values { + padding: 4.5px 11px; + display: flex; + overflow-y: auto; + flex-flow: wrap; + gap: 8px; + + .ant-tag { + color: var(--bg-vanilla-100); + font-family: 'Space Mono'; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; + display: inline-flex; + letter-spacing: -0.07px; + align-items: center; + border-radius: 2px; + border: 1px solid var(--bg-slate-300); + margin-inline-end: 0px; + } + } + } } } diff --git a/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.tsx b/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.tsx index fb6c383b5f..39fcd627bc 100644 --- a/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.tsx +++ b/frontend/src/container/NewDashboard/DashboardSettings/Variables/VariableItem/VariableItem.tsx @@ -2,7 +2,7 @@ import './VariableItem.styles.scss'; import { orange } from '@ant-design/colors'; -import { Button, Input, Select, Switch, Tag, Typography } from 'antd'; +import { Button, Collapse, Input, Select, Switch, Tag, Typography } from 'antd'; import dashboardVariablesQuery from 'api/dashboard/variables/dashboardVariablesQuery'; import cx from 'classnames'; import Editor from 'components/Editor'; @@ -309,48 +309,61 @@ function VariableItem({
)} {queryType === 'CUSTOM' && ( - - - Values separated by comma - - { - setVariableCustomValue(e.target.value); - setPreviewValues( - sortValues( - commaValuesParser(e.target.value), - variableSortType, - ) as never, - ); - }} + + { + setVariableCustomValue(e.target.value); + setPreviewValues( + sortValues( + commaValuesParser(e.target.value), + variableSortType, + ) as never, + ); + }} + /> + ), + }, + ]} /> )} {queryType === 'TEXTBOX' && ( - + - Default Value + Default Value { setVariableTextboxValue(e.target.value); }} - placeholder="Default value if any" + placeholder="Enter a default value (if any)..." style={{ width: 400 }} /> )} {(queryType === 'QUERY' || queryType === 'CUSTOM') && ( <> - + - Preview of Values + + Preview of Values + -
+
{errorPreview ? ( {errorPreview} ) : ( From 1d5189b6931bc7c4a39318a26d4b554e7d2213f7 Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Sat, 27 Apr 2024 14:28:08 +0530 Subject: [PATCH 09/42] feat: setup for new dashboard landing page (#4921) * feat: setup for new dashboard landing page * feat: added empty state widgets * feat: added functionality to the configure and the add panel button * feat: tag variables changes --- frontend/src/container/AppLayout/index.tsx | 13 +- .../DashboardEmptyState.styles.scss | 174 ++++++++++++++++++ .../DashboardEmptyState.tsx | 93 ++++++++++ .../GridCardLayout/GridCardLayout.tsx | 37 +--- .../src/container/GridCardLayout/index.tsx | 11 +- .../src/container/GridCardLayout/types.ts | 3 - .../Description.styles.scss | 172 ++++++++++++++++- .../DashboardDescription/SettingsDrawer.tsx | 14 +- .../DashboardDescription/index.tsx | 125 +++++++++++-- .../DashboardVariableSelection.styles.scss | 49 ++++- .../DashboardVariableSelection.tsx | 2 +- .../VariableItem.tsx | 10 +- .../TopNav/DateTimeSelectionV2/config.ts | 1 + .../TopNav/DateTimeSelectionV2/index.tsx | 36 ++-- 14 files changed, 641 insertions(+), 99 deletions(-) create mode 100644 frontend/src/container/GridCardLayout/DashboardEmptyState/DashboardEmptyState.styles.scss create mode 100644 frontend/src/container/GridCardLayout/DashboardEmptyState/DashboardEmptyState.tsx delete mode 100644 frontend/src/container/GridCardLayout/types.ts diff --git a/frontend/src/container/AppLayout/index.tsx b/frontend/src/container/AppLayout/index.tsx index 901e2b36d8..cdd026f5da 100644 --- a/frontend/src/container/AppLayout/index.tsx +++ b/frontend/src/container/AppLayout/index.tsx @@ -267,6 +267,16 @@ function AppLayout(props: AppLayoutProps): JSX.Element { const isTracesView = (): boolean => routeKey === 'TRACES_EXPLORER' || routeKey === 'TRACES_SAVE_VIEWS'; + const isDashboardView = (): boolean => { + /** + * need to match using regex here as the getRoute function will not work for + * routes with id + */ + const regex = /^\/dashboard\/[a-zA-Z0-9_-]+$/; + console.log(regex.test(pathname)); + return regex.test(pathname); + }; + useEffect(() => { if (isDarkMode) { document.body.classList.remove('lightMode'); @@ -331,7 +341,8 @@ function AppLayout(props: AppLayoutProps): JSX.Element { {isToDisplayLayout && !renderFullScreen && } diff --git a/frontend/src/container/GridCardLayout/DashboardEmptyState/DashboardEmptyState.styles.scss b/frontend/src/container/GridCardLayout/DashboardEmptyState/DashboardEmptyState.styles.scss new file mode 100644 index 0000000000..81e1c21e12 --- /dev/null +++ b/frontend/src/container/GridCardLayout/DashboardEmptyState/DashboardEmptyState.styles.scss @@ -0,0 +1,174 @@ +.dashboard-empty-state { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 500px; + + .dashboard-content { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 12px; + + .heading { + display: flex; + flex-direction: column; + gap: 4px; + + .icons { + color: white; + } + + .welcome { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; /* 171.429% */ + letter-spacing: -0.07px; + } + + .welcome-info { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 24px; + letter-spacing: -0.07px; + } + } + + .actions { + display: flex; + flex-direction: column; + + .actions-1 { + display: flex; + width: 560px; + padding: 12px; + justify-content: space-between; + align-items: flex-start; + border-radius: 4px 4px 0px 0px; + border: 1px solid var(--Slate-500, #161922); + background: var(--Ink-400, #121317); + + .configure-button { + display: flex; + width: 113px; + height: 32px; + padding: 6px; + justify-content: center; + align-items: center; + flex-shrink: 0; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 10px; /* 83.333% */ + letter-spacing: 0.12px; + } + + .actions-configure { + display: flex; + flex-direction: column; + gap: 6px; + + .actions-configure-text { + display: flex; + gap: 8px; + align-items: center; + + .icons { + color: white; + } + + .configure { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + } + .configure-info { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 166.667% */ + letter-spacing: -0.06px; + padding-left: 22px; + } + } + + .add-panel-btn { + display: flex; + width: 113px; + height: 32px; + padding: 6px; + justify-content: center; + align-items: center; + flex-shrink: 0; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + box-shadow: none; + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 10px; /* 83.333% */ + letter-spacing: 0.12px; + } + + .actions-add-panel { + display: flex; + flex-direction: column; + gap: 6px; + + .actions-panel-text { + display: flex; + gap: 8px; + align-items: center; + + .icons { + color: white; + } + + .panel { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + } + + .panel-info { + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 166.667% */ + letter-spacing: -0.06px; + padding-left: 22px; + } + } + } + } + } +} diff --git a/frontend/src/container/GridCardLayout/DashboardEmptyState/DashboardEmptyState.tsx b/frontend/src/container/GridCardLayout/DashboardEmptyState/DashboardEmptyState.tsx new file mode 100644 index 0000000000..2d758fe83a --- /dev/null +++ b/frontend/src/container/GridCardLayout/DashboardEmptyState/DashboardEmptyState.tsx @@ -0,0 +1,93 @@ +import './DashboardEmptyState.styles.scss'; + +import { PlusOutlined } from '@ant-design/icons'; +import { Button, Typography } from 'antd'; +import SettingsDrawer from 'container/NewDashboard/DashboardDescription/SettingsDrawer'; +import useComponentPermission from 'hooks/useComponentPermission'; +import { Tent } from 'lucide-react'; +import { useDashboard } from 'providers/Dashboard/Dashboard'; +import { useCallback } from 'react'; +import { useSelector } from 'react-redux'; +import { AppState } from 'store/reducers'; +import AppReducer from 'types/reducer/app'; +import { ROLES, USER_ROLES } from 'types/roles'; +import { ComponentTypes } from 'utils/permission'; + +export default function DashboardEmptyState(): JSX.Element { + const { + selectedDashboard, + isDashboardLocked, + handleToggleDashboardSlider, + } = useDashboard(); + + const { user, role } = useSelector((state) => state.app); + let permissions: ComponentTypes[] = ['add_panel']; + + if (isDashboardLocked) { + permissions = ['add_panel_locked_dashboard']; + } + + const userRole: ROLES | null = + selectedDashboard?.created_by === user?.email + ? (USER_ROLES.AUTHOR as ROLES) + : role; + + const [addPanelPermission] = useComponentPermission(permissions, userRole); + + const onEmptyWidgetHandler = useCallback(() => { + handleToggleDashboardSlider(true); + }, [handleToggleDashboardSlider]); + return ( +
+
+
+ + + Welcome to your new dashboard + + + Follow the steps to populate it with data and share with your teammates + +
+
+
+
+
+ + + Configure your new dashboard + +
+ + Give it a name, add description, tags and variables + +
+ +
+
+
+
+ + Add panels +
+ + Add panels to visualize your data + +
+ {!isDashboardLocked && addPanelPermission && ( + + )} +
+
+
+
+ ); +} diff --git a/frontend/src/container/GridCardLayout/GridCardLayout.tsx b/frontend/src/container/GridCardLayout/GridCardLayout.tsx index 867410744c..ae21cd68cc 100644 --- a/frontend/src/container/GridCardLayout/GridCardLayout.tsx +++ b/frontend/src/container/GridCardLayout/GridCardLayout.tsx @@ -1,11 +1,11 @@ import './GridCardLayout.styles.scss'; -import { PlusOutlined } from '@ant-design/icons'; -import { Flex, Form, Input, Modal, Tooltip, Typography } from 'antd'; +import { Button, Flex, Form, Input, Modal, Tooltip, Typography } from 'antd'; import { useForm } from 'antd/es/form/Form'; import cx from 'classnames'; import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn'; import { dashboardHelpMessage } from 'components/facingIssueBtn/util'; +// import { Tooltip } from 'antd'; import { SOMETHING_WENT_WRONG } from 'constants/api'; import { QueryParams } from 'constants/query'; import { PANEL_GROUP_TYPES, PANEL_TYPES } from 'constants/queryBuilder'; @@ -26,12 +26,12 @@ import { Settings, Trash2, } from 'lucide-react'; +// import { FullscreenIcon } from 'lucide-react'; import { useDashboard } from 'providers/Dashboard/Dashboard'; import { sortLayout } from 'providers/Dashboard/util'; import { useCallback, useEffect, useState } from 'react'; import { FullScreen, useFullScreenHandle } from 'react-full-screen'; import { ItemCallback, Layout } from 'react-grid-layout'; -import { useTranslation } from 'react-i18next'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; import { UpdateTimeInterval } from 'store/actions'; @@ -43,18 +43,19 @@ import { ComponentTypes } from 'utils/permission'; import { v4 as uuid } from 'uuid'; import { EditMenuAction, ViewMenuAction } from './config'; +// import DashboardEmptyState from './DashboardEmptyState/DashboardEmptyState'; import GridCard from './GridCard'; import { - Button, ButtonContainer, + // Button, + // ButtonContainer, Card, CardContainer, ReactGridLayout, } from './styles'; -import { GraphLayoutProps } from './types'; import { removeUndefinedValuesFromLayout } from './utils'; -function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element { +function GraphLayout(): JSX.Element { const { selectedDashboard, layouts, @@ -71,8 +72,6 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element { const { widgets, variables } = data || {}; - const { t } = useTranslation(['dashboard']); - const { featureResponse, role, user } = useSelector( (state) => state.app, ); @@ -483,6 +482,7 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element { }, }); }; + // TOOD add dashboard empty state back return ( <> @@ -507,27 +507,6 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element { disabled={updateDashboardMutation.isLoading} /> - - {!isDashboardLocked && addPanelPermission && ( - - )} - {!isDashboardLocked && addPanelPermission && ( - - )} diff --git a/frontend/src/container/GridCardLayout/index.tsx b/frontend/src/container/GridCardLayout/index.tsx index a2a82dc8ad..27ecd24a70 100644 --- a/frontend/src/container/GridCardLayout/index.tsx +++ b/frontend/src/container/GridCardLayout/index.tsx @@ -1,16 +1,7 @@ -import { useDashboard } from 'providers/Dashboard/Dashboard'; -import { useCallback } from 'react'; - import GraphLayoutContainer from './GridCardLayout'; function GridGraph(): JSX.Element { - const { handleToggleDashboardSlider } = useDashboard(); - - const onEmptyWidgetHandler = useCallback(() => { - handleToggleDashboardSlider(true); - }, [handleToggleDashboardSlider]); - - return ; + return ; } export default GridGraph; diff --git a/frontend/src/container/GridCardLayout/types.ts b/frontend/src/container/GridCardLayout/types.ts deleted file mode 100644 index a0e8e9aa13..0000000000 --- a/frontend/src/container/GridCardLayout/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface GraphLayoutProps { - onAddPanelHandler: VoidFunction; -} diff --git a/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss b/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss index f0fa289ec9..988ec8ac26 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss @@ -38,15 +38,175 @@ } .dashboard-description-container { - box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.25); - - border: 1px solid var(--bg-slate-400, #1d212d); - background: var(--bg-ink-400, #121317); - box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + box-shadow: none; + border: none; + background: unset; + box-shadow: none; color: var(--bg-vanilla-400, #c0c1c3); .ant-card-body { - padding: 12px 16px; + padding: 0px; + } + + .dashboard-breadcrumbs { + height: 48px; + padding: 16px; + border-bottom: 1px solid var(--bg-slate-400); + display: flex; + gap: 6px; + align-items: center; + + .dashboard-btn { + display: flex; + align-items: center; + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + padding: 0px; + height: 20px; + } + + .dashboard-btn:hover { + background-color: unset; + } + + .id-btn { + display: flex; + align-items: center; + padding: 0px 2px; + border-radius: 2px; + background: rgba(113, 144, 249, 0.1); + color: var(--Robin-400, #7190f9); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + height: 20px; + + .ant-btn-icon { + margin-inline-end: 4px; + } + } + .id-btn:hover { + background: rgba(113, 144, 249, 0.1); + color: var(--bg-robin-300); + } + } + + .dashbord-details { + display: flex; + justify-content: space-between; + .left-section { + display: flex; + padding: 10px 0px 0px 16px; + align-items: center; + gap: 8px; + + .dashboard-title { + color: #fff; + font-family: Inter; + font-size: 16px; + font-style: normal; + font-weight: 500; + line-height: 24px; /* 150% */ + letter-spacing: -0.08px; + flex-shrink: 0; + } + } + + .right-section { + display: flex; + align-items: center; + padding: 16px 16px 0px 0px; + gap: 14px; + + .icons { + display: flex; + align-items: center; + width: auto; + } + + .icons:hover { + background-color: unset; + } + .configure-button { + display: flex; + align-items: center; + width: 93px; + height: 34px; + padding: 6px; + justify-content: center; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 10px; /* 83.333% */ + letter-spacing: 0.12px; + } + + .add-panel-btn { + display: flex; + width: 119px; + height: 34px; + padding: 5.937px 11.875px; + justify-content: center; + align-items: center; + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 11.875px; + font-style: normal; + font-weight: 500; + line-height: 17.812px; /* 150% */ + } + } + } + + .dashboard-tags { + display: flex; + gap: 6px; + padding: 16px 16px 0px 16px; + .tag { + display: flex; + padding: 4px 8px; + justify-content: center; + align-items: center; + border-radius: 20px; + border: 1px solid rgba(173, 127, 88, 0.2); + background: rgba(173, 127, 88, 0.1); + color: var(--Sienna-400, #bd9979); + text-align: center; + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + margin-inline-end: 0px; + } + } + .dashboard-description-section { + max-width: 957px; + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; /* 157.143% */ + letter-spacing: -0.07px; + padding: 20px 16px 0px 16px; + } + + .dashboard-variables { + padding: 16px 16px 18px 16px; } } diff --git a/frontend/src/container/NewDashboard/DashboardDescription/SettingsDrawer.tsx b/frontend/src/container/NewDashboard/DashboardDescription/SettingsDrawer.tsx index b927ed0b91..817fb733ee 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/SettingsDrawer.tsx +++ b/frontend/src/container/NewDashboard/DashboardDescription/SettingsDrawer.tsx @@ -1,7 +1,7 @@ import './Description.styles.scss'; import { Button, Tooltip } from 'antd'; -import { Cog } from 'lucide-react'; +import ConfigureIcon from 'assets/Integrations/ConfigureIcon'; import { useState } from 'react'; import DashboardSettingsContent from '../DashboardSettings'; @@ -22,12 +22,14 @@ function SettingsDrawer({ drawerTitle }: { drawerTitle: string }): JSX.Element { <> (false); const { user, role } = useSelector((state) => state.app); const [editDashboard] = useComponentPermission(['edit_dashboard'], role); - let isAuthor = false; + // let isAuthor = false; - if (selectedDashboard && user && user.email) { - isAuthor = selectedDashboard?.created_by === user?.email; + // if (selectedDashboard && user && user.email) { + // isAuthor = selectedDashboard?.created_by === user?.email; + // } + + let permissions: ComponentTypes[] = ['add_panel']; + + if (isDashboardLocked) { + permissions = ['add_panel_locked_dashboard']; } + const userRole: ROLES | null = + selectedDashboard?.created_by === user?.email + ? (USER_ROLES.AUTHOR as ROLES) + : role; + + const [addPanelPermission] = useComponentPermission(permissions, userRole); + const onToggleHandler = (): void => { setOpenDashboardJSON((state) => !state); }; - const handleLockDashboardToggle = (): void => { - handleDashboardLockToggle(!isDashboardLocked); - }; + const onEmptyWidgetHandler = useCallback(() => { + handleToggleDashboardSlider(true); + }, [handleToggleDashboardSlider]); + + // const handleLockDashboardToggle = (): void => { + // handleDashboardLockToggle(!isDashboardLocked); + // }; return ( - +
+ + +
+
+
+ + {title} +
+
+ + + )} + {selectedData && ( + + )} +
+
+
+ {tags?.map((tag) => ( + + {tag} + + ))} +
+
{description}
+
+ +
+ + {/* - +
*/}
); } diff --git a/frontend/src/container/NewDashboard/DashboardVariablesSelection/DashboardVariableSelection.styles.scss b/frontend/src/container/NewDashboard/DashboardVariablesSelection/DashboardVariableSelection.styles.scss index 9767c183c3..3b3bd2dd65 100644 --- a/frontend/src/container/NewDashboard/DashboardVariablesSelection/DashboardVariableSelection.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardVariablesSelection/DashboardVariableSelection.styles.scss @@ -1,13 +1,44 @@ -.variable-name { - font-size: 0.8rem; - min-width: 100px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - color: gray; -} - .variable-item { + display: flex; + align-items: center; + + .variable-name { + display: flex; + width: 56px; + height: 32px; + padding: 6px 6px 6px 8px; + align-items: center; + gap: 4px; + border-radius: 2px 0px 0px 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + color: var(--Robin-300, #95acfb); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; /* 133.333% */ + } + + .variable-value { + display: flex; + min-width: 120px; + height: 32px; + padding: 6px 6px 6px 8px; + align-items: center; + gap: 4px; + border-radius: 0px 2px 2px 0px; + border: 1px solid var(--Slate-400, #1d212d); + border-left: none; + background: var(--Ink-400, #121317); + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; /* 133.333% */ + } + .variable-select { .ant-select-dropdown { max-width: 300px; diff --git a/frontend/src/container/NewDashboard/DashboardVariablesSelection/DashboardVariableSelection.tsx b/frontend/src/container/NewDashboard/DashboardVariablesSelection/DashboardVariableSelection.tsx index 1eed8f351f..0572196fbf 100644 --- a/frontend/src/container/NewDashboard/DashboardVariablesSelection/DashboardVariableSelection.tsx +++ b/frontend/src/container/NewDashboard/DashboardVariablesSelection/DashboardVariableSelection.tsx @@ -124,7 +124,7 @@ function DashboardVariableSelection(): JSX.Element | null { ); return ( - + {orderBasedSortedVariables && Array.isArray(orderBasedSortedVariables) && orderBasedSortedVariables.length > 0 && diff --git a/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.tsx b/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.tsx index fdfb821267..94b3450034 100644 --- a/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.tsx +++ b/frontend/src/container/NewDashboard/DashboardVariablesSelection/VariableItem.tsx @@ -16,7 +16,7 @@ import { VariableResponseProps } from 'types/api/dashboard/variables/query'; import { popupContainer } from 'utils/selectPopupContainer'; import { variablePropsToPayloadVariables } from '../utils'; -import { SelectItemStyle, VariableContainer, VariableValue } from './styles'; +import { SelectItemStyle } from './styles'; import { areArraysEqual } from './util'; const ALL_SELECT_VALUE = '__ALL__'; @@ -214,11 +214,11 @@ function VariableItem({ }, [variableData.type, variableData.customValue]); return ( - +
${variableData.name} - +
{variableData.type === 'TEXTBOX' ? ( )} - - +
+
); } diff --git a/frontend/src/container/TopNav/DateTimeSelectionV2/config.ts b/frontend/src/container/TopNav/DateTimeSelectionV2/config.ts index eefa31475c..54432a355a 100644 --- a/frontend/src/container/TopNav/DateTimeSelectionV2/config.ts +++ b/frontend/src/container/TopNav/DateTimeSelectionV2/config.ts @@ -200,6 +200,7 @@ export const routesToSkip = [ ROUTES.TRACES_SAVE_VIEWS, ROUTES.SHORTCUTS, ROUTES.INTEGRATIONS, + ROUTES.DASHBOARD, ]; export const routesToDisable = [ROUTES.LOGS_EXPLORER, ROUTES.LIVE_LOGS]; diff --git a/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx b/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx index f306c5be4a..42cc97ce62 100644 --- a/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx +++ b/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx @@ -59,6 +59,7 @@ import { Form, FormContainer, FormItem } from './styles'; function DateTimeSelection({ showAutoRefresh, + hideShareModal = false, location, updateTimeInterval, globalTimeLoading, @@ -619,21 +620,23 @@ function DateTimeSelection({
)} - - - + + + )}
@@ -642,7 +645,12 @@ function DateTimeSelection({ interface DateTimeSelectionV2Props { showAutoRefresh: boolean; + hideShareModal?: boolean; } + +DateTimeSelection.defaultProps = { + hideShareModal: false, +}; interface DispatchProps { updateTimeInterval: ( interval: Time | CustomTimeType, From 178ffc187ea35151b2b00f5640988615bf8bcfdf Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Tue, 30 Apr 2024 00:54:15 +0530 Subject: [PATCH 10/42] feat: dashboard revamp changes follow ups (#4929) * feat: changes for new panel type modal * fix: added missing / in the breadcrumbs * feat: added dashboard settings menu items * feat: added dashboard rename modal * feat: move full screen handle a few components up * feat: handle rename and copy export changes * feat: minor cleanup * feat: delete button changes --- .../GridCardLayout/GridCardLayout.tsx | 11 +- .../src/container/GridCardLayout/index.tsx | 10 +- .../TableComponents/DeleteButton.tsx | 25 +- .../ComponentSlider.styles.scss | 114 ++++++++ .../NewDashboard/ComponentsSlider/index.tsx | 62 +++- .../ComponentsSlider/menuItems.tsx | 12 +- .../Description.styles.scss | 199 +++++++++++++ .../DashboardDescription/index.tsx | 276 +++++++++++++++--- .../NewDashboard/GridGraphs/index.tsx | 14 +- frontend/src/container/NewDashboard/index.tsx | 7 +- 10 files changed, 659 insertions(+), 71 deletions(-) create mode 100644 frontend/src/container/NewDashboard/ComponentsSlider/ComponentSlider.styles.scss diff --git a/frontend/src/container/GridCardLayout/GridCardLayout.tsx b/frontend/src/container/GridCardLayout/GridCardLayout.tsx index ae21cd68cc..c0f3775e4b 100644 --- a/frontend/src/container/GridCardLayout/GridCardLayout.tsx +++ b/frontend/src/container/GridCardLayout/GridCardLayout.tsx @@ -30,7 +30,7 @@ import { import { useDashboard } from 'providers/Dashboard/Dashboard'; import { sortLayout } from 'providers/Dashboard/util'; import { useCallback, useEffect, useState } from 'react'; -import { FullScreen, useFullScreenHandle } from 'react-full-screen'; +import { FullScreen, FullScreenHandle } from 'react-full-screen'; import { ItemCallback, Layout } from 'react-grid-layout'; import { useDispatch, useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; @@ -55,7 +55,13 @@ import { } from './styles'; import { removeUndefinedValuesFromLayout } from './utils'; -function GraphLayout(): JSX.Element { +interface GraphLayoutProps { + handle: FullScreenHandle; +} + +// eslint-disable-next-line sonarjs/cognitive-complexity +function GraphLayout(props: GraphLayoutProps): JSX.Element { + const { handle } = props; const { selectedDashboard, layouts, @@ -66,7 +72,6 @@ function GraphLayout(): JSX.Element { isDashboardLocked, } = useDashboard(); const { data } = selectedDashboard || {}; - const handle = useFullScreenHandle(); const { pathname } = useLocation(); const dispatch = useDispatch(); diff --git a/frontend/src/container/GridCardLayout/index.tsx b/frontend/src/container/GridCardLayout/index.tsx index 27ecd24a70..9ef053491f 100644 --- a/frontend/src/container/GridCardLayout/index.tsx +++ b/frontend/src/container/GridCardLayout/index.tsx @@ -1,7 +1,13 @@ +import { FullScreenHandle } from 'react-full-screen'; + import GraphLayoutContainer from './GridCardLayout'; -function GridGraph(): JSX.Element { - return ; +interface GridGraphProps { + handle: FullScreenHandle; +} +function GridGraph(props: GridGraphProps): JSX.Element { + const { handle } = props; + return ; } export default GridGraph; diff --git a/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx b/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx index 2791d365b8..c7dd8c86e9 100644 --- a/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx +++ b/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx @@ -3,8 +3,10 @@ import './DeleteButton.styles.scss'; import { DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; import { Modal, Tooltip, Typography } from 'antd'; import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; +import ROUTES from 'constants/routes'; import { useDeleteDashboard } from 'hooks/dashboard/useDeleteDashboard'; import { useNotifications } from 'hooks/useNotifications'; +import history from 'lib/history'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; import { useQueryClient } from 'react-query'; @@ -21,13 +23,15 @@ interface DeleteButtonProps { name: string; id: string; isLocked: boolean; + routeToListPage?: boolean; } -function DeleteButton({ +export function DeleteButton({ createdBy, name, id, isLocked, + routeToListPage, }: DeleteButtonProps): JSX.Element { const [modal, contextHolder] = Modal.useModal(); const { role, user } = useSelector((state) => state.app); @@ -60,6 +64,9 @@ function DeleteButton({ }), }); queryClient.invalidateQueries([REACT_QUERY_KEY.GET_ALL_DASHBOARDS]); + if (routeToListPage) { + history.replace(ROUTES.ALL_DASHBOARD); + } }, }); }, @@ -68,7 +75,15 @@ function DeleteButton({ centered: true, className: 'delete-modal', }); - }, [modal, name, deleteDashboardMutation, notifications, t, queryClient]); + }, [ + modal, + name, + deleteDashboardMutation, + notifications, + t, + queryClient, + routeToListPage, + ]); const getDeleteTooltipContent = (): string => { if (isLocked) { @@ -94,7 +109,7 @@ function DeleteButton({ }} disabled={isLocked} > - Delete + Delete dashboard @@ -103,6 +118,10 @@ function DeleteButton({ ); } +DeleteButton.defaultProps = { + routeToListPage: false, +}; + // This is to avoid the type collision function Wrapper(props: Data): JSX.Element { const { diff --git a/frontend/src/container/NewDashboard/ComponentsSlider/ComponentSlider.styles.scss b/frontend/src/container/NewDashboard/ComponentsSlider/ComponentSlider.styles.scss new file mode 100644 index 0000000000..0e9a26db41 --- /dev/null +++ b/frontend/src/container/NewDashboard/ComponentsSlider/ComponentSlider.styles.scss @@ -0,0 +1,114 @@ +.graph-selection { + .ant-modal-content { + width: 515px; + max-height: 646px; + overflow-y: auto; + flex-shrink: 0; + border-radius: 4px; + border: 1px solid var(--Slate-500, #161922); + background: var(--Ink-400, #121317); + box-shadow: 0px -4px 16px 2px rgba(0, 0, 0, 0.2); + padding: 0px; + + .ant-modal-header { + height: 52px; + padding: 16px; + background: var(--Ink-400, #121317); + border-bottom: 1px solid var(--Slate-500, #161922); + margin-bottom: 0px; + + .ant-modal-title { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + } + } + + .ant-modal-body { + .panel-selection { + display: flex; + flex-flow: wrap; + padding: 16px; + gap: 16px; + + .selected { + background: var(--Slate-400, #1d212d); + } + + .ant-card { + display: flex; + height: 80px; + width: 232px; + padding: 19px 0px; + justify-content: center; + align-items: center; + border-radius: 4px; + cursor: pointer; + border: 1px solid var(--Slate-400, #1d212d); + + .ant-card-body { + padding: 0px; + border-radius: 0px; + display: flex; + flex-direction: column; + gap: 6px; + align-items: center; + + .ant-typography { + margin-top: 0px; + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + letter-spacing: -0.07px; + } + } + + .ant-card-body::before { + content: none; + } + .ant-card-body::after { + content: none; + } + } + } + } + + .ant-modal-footer { + border-radius: 0px 0px 4px 4px; + border-top: 1px solid var(--Slate-500, #161922); + background: var(--Ink-400, #121317); + padding: 12px 15px; + margin-top: 0px; + + .ant-btn { + width: 100%; + display: flex; + align-items: center; + flex-direction: row-reverse; + justify-content: center; + color: var(--Vanilla-100, #fff); + + /* button/ small */ + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 500; + line-height: 24px; /* 200% */ + border-radius: 2px; + background: var(--Robin-500, #4e74f8); + padding: 4px 8px; + gap: 4px; + } + } + + &::-webkit-scrollbar { + width: 0.1rem; + } + } +} diff --git a/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx b/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx index a61255705a..41b0b3e584 100644 --- a/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx +++ b/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx @@ -1,17 +1,26 @@ +import './ComponentSlider.styles.scss'; + +import { Card, Modal } from 'antd'; +import { Button } from 'antd/lib'; import { QueryParams } from 'constants/query'; import { PANEL_TYPES } from 'constants/queryBuilder'; import createQueryParams from 'lib/createQueryParams'; import history from 'lib/history'; +import { isEqual } from 'lodash-es'; +import { ArrowRight } from 'lucide-react'; import { useDashboard } from 'providers/Dashboard/Dashboard'; +import { useState } from 'react'; import { LogsAggregatorOperator } from 'types/common/queryBuilder'; import { v4 as uuid } from 'uuid'; import { PANEL_TYPES_INITIAL_QUERY } from './constants'; import menuItems from './menuItems'; -import { Card, Container, Text } from './styles'; +import { Text } from './styles'; function DashboardGraphSlider(): JSX.Element { - const { handleToggleDashboardSlider } = useDashboard(); + const { handleToggleDashboardSlider, isDashboardSliderOpen } = useDashboard(); + + const [selectedPanelType, setSelectedPanelType] = useState(); // eslint-disable-next-line sonarjs/cognitive-complexity const onClickHandler = (name: PANEL_TYPES) => (): void => { @@ -56,15 +65,48 @@ function DashboardGraphSlider(): JSX.Element { } }; + const handleCardClick = (panelType: PANEL_TYPES): void => { + if (!isEqual(panelType, selectedPanelType)) setSelectedPanelType(panelType); + }; + return ( - - {menuItems.map(({ name, icon, display }) => ( - - {icon} - {display} - - ))} - + { + handleToggleDashboardSlider(false); + setSelectedPanelType(undefined); + }} + rootClassName="graph-selection" + footer={ + + } + title="New Panel" + > +
+ {menuItems.map(({ name, icon, display }) => ( + handleCardClick(name)} + id={name} + key={name} + className={selectedPanelType === name ? 'selected' : ''} + > + {icon} + {display} + + ))} +
+
); } diff --git a/frontend/src/container/NewDashboard/ComponentsSlider/menuItems.tsx b/frontend/src/container/NewDashboard/ComponentsSlider/menuItems.tsx index 28493441a0..d25d8a3e8a 100644 --- a/frontend/src/container/NewDashboard/ComponentsSlider/menuItems.tsx +++ b/frontend/src/container/NewDashboard/ComponentsSlider/menuItems.tsx @@ -12,32 +12,32 @@ import { const Items: ItemsProps[] = [ { name: PANEL_TYPES.TIME_SERIES, - icon: , + icon: , display: 'Time Series', }, { name: PANEL_TYPES.VALUE, - icon: , + icon: , display: 'Value', }, { name: PANEL_TYPES.TABLE, - icon: , + icon:
, display: 'Table', }, { name: PANEL_TYPES.LIST, - icon: , + icon: , display: 'List', }, { name: PANEL_TYPES.BAR, - icon: , + icon: , display: 'Bar', }, { name: PANEL_TYPES.PIE, - icon: , + icon: , display: 'Pie', }, ]; diff --git a/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss b/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss index 988ec8ac26..0fdc965ef2 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss +++ b/frontend/src/container/NewDashboard/DashboardDescription/Description.styles.scss @@ -224,6 +224,205 @@ gap: 8px; } +.dashboard-settings { + width: 191px; + height: 302px; + flex-shrink: 0; + + .ant-popover-inner { + padding: 0px; + border-radius: 4px; + border: 1px solid var(--Slate-400, #1d212d); + background: linear-gradient( + 139deg, + rgba(18, 19, 23, 0.8) 0%, + rgba(18, 19, 23, 0.9) 98.68% + ) !important; + box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2); + backdrop-filter: blur(20px); + } + + .menu-content { + display: flex; + flex-direction: column; + + .section-1 { + display: flex; + flex-direction: column; + align-items: start; + border-bottom: 1px solid #1d212d; + + .ant-btn { + display: flex; + width: 100%; + height: 20px; + padding: 16px 18px 18px 14px; + align-items: center; + gap: 6px; + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; + letter-spacing: 0.14px; + .ant-btn-icon { + margin-inline-end: 0px; + } + } + } + .section-2 { + display: flex; + flex-direction: column; + align-items: start; + border-bottom: 1px solid #1d212d; + + .ant-btn { + display: flex; + width: 100%; + height: 20px; + padding: 16px 18px 18px 14px; + align-items: center; + gap: 6px; + color: var(--Vanilla-400, #c0c1c3); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; + letter-spacing: 0.14px; + + .ant-btn-icon { + margin-inline-end: 0px; + } + } + } + .delete-dashboard { + display: flex; + flex-direction: column; + align-items: start; + + .ant-typography { + display: flex; + width: 100%; + height: 20px; + padding: 16px 18px 18px 14px; + align-items: center; + gap: 6px; + color: var(--Cherry-400, #ea6d71) !important; + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; + letter-spacing: 0.14px; + } + } + } +} + +.rename-dashboard { + .ant-modal-content { + width: 384px; + flex-shrink: 0; + border-radius: 4px; + border: 1px solid var(--Slate-500, #161922); + background: var(--Ink-400, #121317); + box-shadow: 0px -4px 16px 2px rgba(0, 0, 0, 0.2); + padding: 0px; + + .ant-modal-header { + height: 52px; + padding: 16px; + background: var(--Ink-400, #121317); + border-bottom: 1px solid var(--Slate-500, #161922); + margin-bottom: 0px; + .ant-modal-title { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 20px; /* 142.857% */ + width: 349px; + height: 20px; + } + } + + .ant-modal-body { + padding: 16px; + + .dashboard-content { + display: flex; + flex-direction: column; + gap: 8px; + + .name-text { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 500; + line-height: 20px; /* 142.857% */ + } + + .dashboard-name-input { + display: flex; + width: 320px; + padding: 6px 6px 6px 8px; + align-items: center; + gap: 4px; + align-self: stretch; + border-radius: 0px 2px 2px 0px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + } + } + } + + .ant-modal-footer { + padding: 16px; + margin-top: 0px; + .dashboard-rename { + display: flex; + flex-direction: row-reverse; + gap: 12px; + + .cancel-btn { + display: flex; + padding: 4px 8px; + justify-content: center; + align-items: center; + gap: 4px; + border-radius: 2px; + background: var(--Slate-500, #161922); + + .ant-btn-icon { + margin-inline-end: 0px; + } + } + + .rename-btn { + display: flex; + align-items: center; + display: flex; + width: 169px; + padding: 4px 8px; + justify-content: center; + align-items: center; + gap: 4px; + border-radius: 2px; + background: var(--Robin-500, #4e74f8); + + .ant-btn-icon { + margin-inline-end: 0px; + } + } + } + } + } +} + .lightMode { .dashboard-description-container { box-shadow: none; diff --git a/frontend/src/container/NewDashboard/DashboardDescription/index.tsx b/frontend/src/container/NewDashboard/DashboardDescription/index.tsx index cc3ef21e53..d1f0aefd1b 100644 --- a/frontend/src/container/NewDashboard/DashboardDescription/index.tsx +++ b/frontend/src/container/NewDashboard/DashboardDescription/index.tsx @@ -1,31 +1,58 @@ import './Description.styles.scss'; import { PlusOutlined } from '@ant-design/icons'; -import { Button, Card, Tag, Tooltip, Typography } from 'antd'; +import { Button, Card, Input, Modal, Popover, Tag, Typography } from 'antd'; +import { SOMETHING_WENT_WRONG } from 'constants/api'; import ROUTES from 'constants/routes'; +import { DeleteButton } from 'container/ListOfDashboard/TableComponents/DeleteButton'; import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2'; +import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard'; import useComponentPermission from 'hooks/useComponentPermission'; +import { useNotifications } from 'hooks/useNotifications'; import history from 'lib/history'; -import { CircleEllipsis, LayoutGrid, Link2, Tent, Zap } from 'lucide-react'; +import { + Check, + CircleEllipsis, + ClipboardCopy, + FileJson, + FolderKanban, + Fullscreen, + LayoutGrid, + LockKeyhole, + PenLine, + Tent, + X, +} from 'lucide-react'; import { useDashboard } from 'providers/Dashboard/Dashboard'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; +import { FullScreenHandle } from 'react-full-screen'; +import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; +import { useCopyToClipboard } from 'react-use'; import { AppState } from 'store/reducers'; import { DashboardData } from 'types/api/dashboard/getAll'; import AppReducer from 'types/reducer/app'; import { ROLES, USER_ROLES } from 'types/roles'; import { ComponentTypes } from 'utils/permission'; +import DashboardGraphSlider from '../ComponentsSlider'; import DashboardVariableSelection from '../DashboardVariablesSelection'; import SettingsDrawer from './SettingsDrawer'; -import ShareModal from './ShareModal'; +import { downloadObjectAsJson } from './utils'; -function DashboardDescription(): JSX.Element { +interface DashboardDescriptionProps { + handle: FullScreenHandle; +} + +// eslint-disable-next-line sonarjs/cognitive-complexity +function DashboardDescription(props: DashboardDescriptionProps): JSX.Element { + const { handle } = props; const { selectedDashboard, isDashboardLocked, + setSelectedDashboard, handleToggleDashboardSlider, - // handleDashboardLockToggle, + handleDashboardLockToggle, } = useDashboard(); const selectedData = selectedDashboard @@ -37,16 +64,25 @@ function DashboardDescription(): JSX.Element { const { title = '', description, tags } = selectedData || {}; - const [openDashboardJSON, setOpenDashboardJSON] = useState(false); + const [updatedTitle, setUpdatedTitle] = useState(title); + + const updateDashboardMutation = useUpdateDashboard(); const { user, role } = useSelector((state) => state.app); const [editDashboard] = useComponentPermission(['edit_dashboard'], role); + const [isDashboardSettingsOpen, setIsDashbordSettingsOpen] = useState( + false, + ); - // let isAuthor = false; + const [isRenameDashboardOpen, setIsRenameDashboardOpen] = useState( + false, + ); - // if (selectedDashboard && user && user.email) { - // isAuthor = selectedDashboard?.created_by === user?.email; - // } + let isAuthor = false; + + if (selectedDashboard && user && user.email) { + isAuthor = selectedDashboard?.created_by === user?.email; + } let permissions: ComponentTypes[] = ['add_panel']; @@ -54,6 +90,8 @@ function DashboardDescription(): JSX.Element { permissions = ['add_panel_locked_dashboard']; } + const { notifications } = useNotifications(); + const userRole: ROLES | null = selectedDashboard?.created_by === user?.email ? (USER_ROLES.AUTHOR as ROLES) @@ -61,17 +99,65 @@ function DashboardDescription(): JSX.Element { const [addPanelPermission] = useComponentPermission(permissions, userRole); - const onToggleHandler = (): void => { - setOpenDashboardJSON((state) => !state); - }; - const onEmptyWidgetHandler = useCallback(() => { handleToggleDashboardSlider(true); }, [handleToggleDashboardSlider]); - // const handleLockDashboardToggle = (): void => { - // handleDashboardLockToggle(!isDashboardLocked); - // }; + const handleLockDashboardToggle = (): void => { + setIsDashbordSettingsOpen(false); + handleDashboardLockToggle(!isDashboardLocked); + }; + + const onNameChangeHandler = (): void => { + if (!selectedDashboard) { + return; + } + const updatedDashboard = { + ...selectedDashboard, + data: { + ...selectedDashboard.data, + title: updatedTitle, + }, + }; + updateDashboardMutation.mutate(updatedDashboard, { + onSuccess: (updatedDashboard) => { + notifications.success({ + message: 'Dashboard renamed successfully', + }); + setIsRenameDashboardOpen(false); + if (updatedDashboard.payload) + setSelectedDashboard(updatedDashboard.payload); + }, + onError: () => { + notifications.error({ + message: SOMETHING_WENT_WRONG, + }); + setIsRenameDashboardOpen(true); + }, + }); + }; + + const [state, setCopy] = useCopyToClipboard(); + + const { t } = useTranslation(['dashboard', 'common']); + + useEffect(() => { + if (state.error) { + notifications.error({ + message: t('something_went_wrong', { + ns: 'common', + }), + }); + } + + if (state.value) { + notifications.success({ + message: t('success', { + ns: 'common', + }), + }); + } + }, [state.error, state.value, t, notifications]); return ( @@ -82,7 +168,7 @@ function DashboardDescription(): JSX.Element { className="dashboard-btn" onClick={(): void => history.push(ROUTES.ALL_DASHBOARD)} > - Dashboard + Dashboard / + )} + + {!isDashboardLocked && editDashboard && ( + + )} + + + +
+ {/* */} + {!isDashboardLocked && editDashboard && ( + + )} + + + +
+
+ +
+ + } + trigger="click" + placement="bottomRight" + > )} - {selectedData && ( - - )}
@@ -147,7 +304,50 @@ function DashboardDescription(): JSX.Element {
+ + { + // handle update dashboard here + }} + onCancel={(): void => { + setIsRenameDashboardOpen(false); + }} + rootClassName="rename-dashboard" + footer={ +
+ + +
+ } + > +
+ Enter a new name + setUpdatedTitle(e.target.value)} + /> +
+
{/*
- {isDashboardSliderOpen && } - - + ); } diff --git a/frontend/src/container/NewDashboard/index.tsx b/frontend/src/container/NewDashboard/index.tsx index ca10b6f89b..801cc14c77 100644 --- a/frontend/src/container/NewDashboard/index.tsx +++ b/frontend/src/container/NewDashboard/index.tsx @@ -1,11 +1,14 @@ +import { useFullScreenHandle } from 'react-full-screen'; + import Description from './DashboardDescription'; import GridGraphs from './GridGraphs'; function NewDashboard(): JSX.Element { + const handle = useFullScreenHandle(); return ( <> - - + + ); } From f991197255db97a7319c995769a38a538ebcbd24 Mon Sep 17 00:00:00 2001 From: Vikrant Gupta Date: Mon, 13 May 2024 11:42:22 +0530 Subject: [PATCH 11/42] feat: dashboard widget edit page design revamp (#4946) * feat: dashboard edit page base setup * feat: right container design revamp * feat: alerts and thresholds changes right container * feat: right container * feat: fix graph styles * fix: some edits for dashboard edit page --- .../TimePreference.styles.scss | 31 ++ .../TimePreferenceDropDown/index.tsx | 28 +- frontend/src/container/AppLayout/index.tsx | 13 +- .../LeftContainer/LeftContainer.styles.scss | 9 + .../QuerySection/QuerySection.styles.scss | 26 +- .../LeftContainer/QuerySection/index.tsx | 27 +- .../NewWidget/LeftContainer/QueryTypeTag.tsx | 20 +- .../LeftContainer/WidgetGraph/PlotTag.tsx | 7 +- .../WidgetGraph/WidgetGraph.styles.scss | 24 ++ .../WidgetGraph/WidgetGraphs.tsx | 13 +- .../LeftContainer/WidgetGraph/index.tsx | 10 +- .../LeftContainer/WidgetGraph/styles.ts | 5 +- .../NewWidget/LeftContainer/index.tsx | 4 +- .../NewWidget/LeftContainer/styles.ts | 5 - .../container/NewWidget/NewWidget.styles.scss | 57 ++++ .../RightContainer/RightContainer.styles.scss | 295 ++++++++++++++++++ .../Threshold/ColorSelector.styles.scss | 22 +- .../Threshold/ColorSelector.tsx | 2 +- .../Threshold/CustomColor.styles.scss | 39 ++- .../Threshold/Threshold.styles.scss | 207 ++++++++---- .../RightContainer/Threshold/Threshold.tsx | 256 +++++++-------- .../Threshold/ThresholdSelector.styles.scss | 49 ++- .../Threshold/ThresholdSelector.tsx | 14 +- .../RightContainer/YAxisUnitSelector.tsx | 11 +- .../NewWidget/RightContainer/index.tsx | 203 ++++++------ frontend/src/container/NewWidget/index.tsx | 59 ++-- frontend/src/container/NewWidget/styles.ts | 5 +- .../TopNav/DateTimeSelectionV2/config.ts | 1 + 28 files changed, 1013 insertions(+), 429 deletions(-) create mode 100644 frontend/src/components/TimePreferenceDropDown/TimePreference.styles.scss create mode 100644 frontend/src/container/NewWidget/LeftContainer/LeftContainer.styles.scss create mode 100644 frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraph.styles.scss create mode 100644 frontend/src/container/NewWidget/RightContainer/RightContainer.styles.scss diff --git a/frontend/src/components/TimePreferenceDropDown/TimePreference.styles.scss b/frontend/src/components/TimePreferenceDropDown/TimePreference.styles.scss new file mode 100644 index 0000000000..eeddb99224 --- /dev/null +++ b/frontend/src/components/TimePreferenceDropDown/TimePreference.styles.scss @@ -0,0 +1,31 @@ +.time-selection-menu { +} + +.time-selection-target { + display: flex; + height: 32px; + padding: 6px 6px 6px 8px; + justify-content: space-between; + align-items: center; + gap: 4px; + align-self: stretch; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-300, #16181d); + box-shadow: none; + + .button-selected-text { + display: flex; + align-items: center; + gap: 6px; + } + + .selected-value { + color: var(--Vanilla-100, #fff); + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; /* 133.333% */ + } +} diff --git a/frontend/src/components/TimePreferenceDropDown/index.tsx b/frontend/src/components/TimePreferenceDropDown/index.tsx index 572593af7c..c61d9c59b7 100644 --- a/frontend/src/components/TimePreferenceDropDown/index.tsx +++ b/frontend/src/components/TimePreferenceDropDown/index.tsx @@ -1,13 +1,15 @@ +import './TimePreference.styles.scss'; + import { DownOutlined } from '@ant-design/icons'; -import { Button, Dropdown } from 'antd'; +import { Button, Dropdown, Typography } from 'antd'; import TimeItems, { timePreferance, timePreferenceType, } from 'container/NewWidget/RightContainer/timeItems'; +import { Globe } from 'lucide-react'; import { Dispatch, SetStateAction, useCallback, useMemo } from 'react'; import { menuItems } from './config'; -import { TextContainer } from './styles'; function TimePreference({ setSelectedTime, @@ -32,13 +34,21 @@ function TimePreference({ ); return ( - - - - - + + + ); } diff --git a/frontend/src/container/AppLayout/index.tsx b/frontend/src/container/AppLayout/index.tsx index cdd026f5da..7ead0a00f4 100644 --- a/frontend/src/container/AppLayout/index.tsx +++ b/frontend/src/container/AppLayout/index.tsx @@ -273,7 +273,11 @@ function AppLayout(props: AppLayoutProps): JSX.Element { * routes with id */ const regex = /^\/dashboard\/[a-zA-Z0-9_-]+$/; - console.log(regex.test(pathname)); + return regex.test(pathname); + }; + + const isDashboardWidgetView = (): boolean => { + const regex = /^\/dashboard\/[a-zA-Z0-9_-]+\/new$/; return regex.test(pathname); }; @@ -342,7 +346,12 @@ function AppLayout(props: AppLayoutProps): JSX.Element { {isToDisplayLayout && !renderFullScreen && } diff --git a/frontend/src/container/NewWidget/LeftContainer/LeftContainer.styles.scss b/frontend/src/container/NewWidget/LeftContainer/LeftContainer.styles.scss new file mode 100644 index 0000000000..bce46374d5 --- /dev/null +++ b/frontend/src/container/NewWidget/LeftContainer/LeftContainer.styles.scss @@ -0,0 +1,9 @@ +.query-section-left-container { + border: none; + border-top: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-500, #0b0c0e); + + .ant-card-body { + padding: 0px; + } +} diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/QuerySection.styles.scss b/frontend/src/container/NewWidget/LeftContainer/QuerySection/QuerySection.styles.scss index d6ae43ac9a..d1574319d9 100644 --- a/frontend/src/container/NewWidget/LeftContainer/QuerySection/QuerySection.styles.scss +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/QuerySection.styles.scss @@ -8,6 +8,15 @@ display: flex; align-items: center; justify-content: center; + gap: 4px; + color: #fff; + font-family: Inter; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 18px; /* 150% */ + letter-spacing: -0.06px; + padding: 7px 23px; .prom-ql-icon { height: 14px; @@ -17,6 +26,7 @@ } .ant-btn-default { border-color: transparent; + box-shadow: none; } } .ant-tabs-tab-active { @@ -27,16 +37,26 @@ .ant-tabs-nav { margin: 0px; - margin-bottom: 0.5rem; + + .ant-tabs-nav-wrap { + padding: 8px 16px; + } + + .ant-tabs-extra-content { + padding-right: 8px; + } } .ant-tabs-nav::before { border-bottom: none !important; } .ant-tabs-nav-list { - border: 1px solid var(--bg-slate-200); + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-400, #121317); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); } .ant-tabs-tab + .ant-tabs-tab { - border-left: 1px solid var(--bg-slate-200) !important; + border-left: 1px solid var(--Slate-400, #1d212d) !important; } .stage-run-query { display: flex; diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx b/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx index 11f01b402f..205f386d82 100644 --- a/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx @@ -147,11 +147,10 @@ function QuerySection({ { key: EQueryType.QUERY_BUILDER, label: ( - - - + ), tab: Query Builder, children: ( @@ -169,11 +168,10 @@ function QuerySection({ { key: EQueryType.QUERY_BUILDER, label: ( - - - + ), tab: Query Builder, children: ( @@ -187,11 +185,10 @@ function QuerySection({ { key: EQueryType.CLICKHOUSE, label: ( - - - + ), tab: ClickHouse Query, children: , diff --git a/frontend/src/container/NewWidget/LeftContainer/QueryTypeTag.tsx b/frontend/src/container/NewWidget/LeftContainer/QueryTypeTag.tsx index d119bb7c27..e21fc9c4a4 100644 --- a/frontend/src/container/NewWidget/LeftContainer/QueryTypeTag.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/QueryTypeTag.tsx @@ -1,28 +1,14 @@ import { EQueryType } from 'types/common/dashboard'; -import { Tag } from '../styles'; - function QueryTypeTag({ queryType }: IQueryTypeTagProps): JSX.Element { switch (queryType) { case EQueryType.QUERY_BUILDER: - return ( - - Query Builder - - ); + return Query Builder; case EQueryType.CLICKHOUSE: - return ( - - ClickHouse Query - - ); + return ClickHouse Query; case EQueryType.PROM: - return ( - - PromQL - - ); + return PromQL; default: return ; } diff --git a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/PlotTag.tsx b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/PlotTag.tsx index 99da2e517e..77e2061a35 100644 --- a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/PlotTag.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/PlotTag.tsx @@ -2,7 +2,6 @@ import { PANEL_TYPES } from 'constants/queryBuilder'; import { EQueryType } from 'types/common/dashboard'; import QueryTypeTag from '../QueryTypeTag'; -import { PlotTagWrapperStyled } from './styles'; interface IPlotTagProps { queryType: EQueryType; @@ -15,9 +14,9 @@ function PlotTag({ queryType, panelType }: IPlotTagProps): JSX.Element | null { } return ( - - Plotted using - +
+ Plotted with +
); } diff --git a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraph.styles.scss b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraph.styles.scss new file mode 100644 index 0000000000..f7d106d9a1 --- /dev/null +++ b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraph.styles.scss @@ -0,0 +1,24 @@ +.widget-graph { + border: none; + background-color: unset; + background-image: radial-gradient(var(--bg-slate-400) 1px, transparent 0); + background-size: 20px 20px; + padding: 16px; + + .header { + display: flex; + align-items: center; + justify-content: space-between; + + .plot-tag { + display: inline-flex; + padding: 4px 4px 4px 6px; + align-items: center; + gap: 4px; + border-radius: 4px; + background: var(--Slate-400, #1d212d); + backdrop-filter: blur(6px); + width: fit-content; + } + } +} diff --git a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraphs.tsx b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraphs.tsx index 72440014f1..206a877408 100644 --- a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraphs.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraphs.tsx @@ -85,7 +85,18 @@ function WidgetGraph({ }, []); return ( -
+
- + +
+ + +
{queryResponse.error && ( diff --git a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/styles.ts b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/styles.ts index a5d030e27c..e671187eac 100644 --- a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/styles.ts +++ b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/styles.ts @@ -12,13 +12,10 @@ export const Container = styled(Card)` } .ant-card-body { - padding: ${({ $panelType }): string => - $panelType === PANEL_TYPES.TABLE || $panelType === PANEL_TYPES.LIST - ? '0 0' - : '1.5rem 0'}; height: 60vh; display: flex; flex-direction: column; + padding: 0px; } `; diff --git a/frontend/src/container/NewWidget/LeftContainer/index.tsx b/frontend/src/container/NewWidget/LeftContainer/index.tsx index 66d91b7544..e7c149c246 100644 --- a/frontend/src/container/NewWidget/LeftContainer/index.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/index.tsx @@ -1,3 +1,5 @@ +import './LeftContainer.styles.scss'; + import { DEFAULT_ENTITY_VERSION } from 'constants/app'; import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; import { REACT_QUERY_KEY } from 'constants/reactQueryKeys'; @@ -97,7 +99,7 @@ function LeftContainer({ setRequestData={setRequestData} selectedWidget={selectedWidget} /> - + {selectedGraph === PANEL_TYPES.LIST && ( - + diff --git a/frontend/src/container/NewWidget/RightContainer/Threshold/CustomColor.styles.scss b/frontend/src/container/NewWidget/RightContainer/Threshold/CustomColor.styles.scss index 058052f2f6..7837dc38d8 100644 --- a/frontend/src/container/NewWidget/RightContainer/Threshold/CustomColor.styles.scss +++ b/frontend/src/container/NewWidget/RightContainer/Threshold/CustomColor.styles.scss @@ -1,18 +1,29 @@ .custom-color-container { - display: flex; - gap: 10px; - align-items: center; + display: flex; + gap: 8px; + align-items: center; - .custom-color-typography-dark { - color: #fff !important; - } + .custom-color-typography-dark { + color: #fff !important; + font-family: 'Space Mono'; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; /* 133.333% */ + } - .custom-color-typography-light { - color: #000 !important; - } + .custom-color-typography-light { + color: #000 !important; + font-family: 'Space Mono'; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; /* 133.333% */ + } - .custom-color-tag { - width: 20px; - height: 20px; - } -} \ No newline at end of file + .custom-color-tag { + width: 12px; + height: 12px; + border-radius: 12px; + } +} diff --git a/frontend/src/container/NewWidget/RightContainer/Threshold/Threshold.styles.scss b/frontend/src/container/NewWidget/RightContainer/Threshold/Threshold.styles.scss index dcf7acf88c..84c1b2b62e 100644 --- a/frontend/src/container/NewWidget/RightContainer/Threshold/Threshold.styles.scss +++ b/frontend/src/container/NewWidget/RightContainer/Threshold/Threshold.styles.scss @@ -1,58 +1,153 @@ .threshold-container { + margin-top: 12px; - .threshold-card { - padding: 0px; - border-radius: 10px; - position: relative; - margin-top: 10px; - - .threshold-card-container { - display: flex; - flex-direction: column; - gap: 10px; - } - - .ant-typography { - font-size: 14px; - font-weight: 400; - line-height: 22px; - } - - .ant-typograph-dark { - color: #FFFFFF73; - } - - .ant-typograph-light { - color: #00000073; - } - - } - - .threshold-card-dark { - background-color: #1F1F1F; - } - - .threshold-card-light { - background-color: rgb(255, 255, 255); - } - - .threshold-action-button { - position: absolute; - right: 10px; - top: 10px; - } - - .threshold-action-icon { - font-size: 16px; - } - - .threshold-units-selector { - display: flex; - align-items: center; - } - - .threshold-color-picker { - display: flex; - flex-direction: column; - } -} \ No newline at end of file + .threshold-card-container { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 12px; + flex-shrink: 0; + padding: 12px; + border-radius: 2px; + border: 1px solid var(--Slate-500, #161922); + background: var(--Ink-400, #121317); + + .time-series-alerts { + display: flex; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-400, #121317); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + width: 100%; + align-items: center; + + .label { + color: var(--Vanilla-400, #c0c1c3); + font-family: 'Space Mono'; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; /* 133.333% */ + letter-spacing: 0.48px; + text-transform: uppercase; + width: 20%; + padding: 8px; + } + + .label-input { + height: 32px; + width: 80%; + flex-shrink: 0; + border-radius: 2px; + border-left: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-400, #121317); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + } + } + + .threshold-units-selector { + display: flex; + border-radius: 2px 2px 0px 0px; + border: 1px solid var(--Slate-400, #1d212d); + background: var(--Ink-400, #121317); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + height: 32px; + flex-shrink: 0; + width: 100%; + + .unit-input { + width: 50%; + border: none; + } + + .unit-selection { + width: 50%; + border: none; + border-left: 1px solid var(--Slate-400, #1d212d); + + .ant-select-selector { + border: none; + height: unset; + color: var(--Vanilla-400, #c0c1c3); + font-family: 'Space Mono'; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; /* 133.333% */ + } + } + } + + .thresholds-color-selector { + display: flex; + align-items: center; + border-radius: 0px 0px 2px 2px; + border: 1px solid var(--Slate-400, #1d212d); + border-top: none; + background: var(--Ink-400, #121317); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1); + height: 32px; + flex-shrink: 0; + width: 100%; + margin-top: -12px; + + .color-selector { + width: 50%; + } + .color-format { + width: 50%; + border: none; + border-left: 1px solid var(--Slate-400, #1d212d); + + .ant-select-selector { + border: none; + height: unset; + color: var(--Vanilla-400, #c0c1c3); + font-family: 'Space Mono'; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; /* 133.333% */ + background-color: unset; + } + } + } + + .threshold-action-button { + display: flex; + align-items: center; + width: 100%; + gap: 12px; + + .discard-btn { + display: flex; + width: 50%; + align-items: center; + height: 34px; + padding: 4px 8px 4px 10px; + justify-content: center; + gap: 6px; + flex: 1 0 0; + border-radius: 2px; + border: 1px solid var(--Slate-400, #1d2023); + background: var(--Slate-500, #161922); + box-shadow: none; + } + + .save-changes { + display: flex; + width: 50%; + align-items: center; + height: 34px; + padding: 4px 8px 4px 10px; + justify-content: center; + gap: 6px; + flex: 1 0 0; + border-radius: 2px; + border: 1px solid var(--Robin-500, #4e74f8); + background: var(--Robin-500, #4e74f8); + box-shadow: none; + } + } + } +} diff --git a/frontend/src/container/NewWidget/RightContainer/Threshold/Threshold.tsx b/frontend/src/container/NewWidget/RightContainer/Threshold/Threshold.tsx index a35acabf64..797a33e272 100644 --- a/frontend/src/container/NewWidget/RightContainer/Threshold/Threshold.tsx +++ b/frontend/src/container/NewWidget/RightContainer/Threshold/Threshold.tsx @@ -1,18 +1,10 @@ /* eslint-disable sonarjs/cognitive-complexity */ import './Threshold.styles.scss'; -import { CheckOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'; -import { - Card, - Divider, - Input, - InputNumber, - Select, - Space, - Typography, -} from 'antd'; +import { Button, Input, InputNumber, Select, Space, Typography } from 'antd'; import { PANEL_TYPES } from 'constants/queryBuilder'; import { useIsDarkMode } from 'hooks/useDarkMode'; +import { Check, X } from 'lucide-react'; import { useRef, useState } from 'react'; import { useDrag, useDrop, XYCoord } from 'react-dnd'; @@ -197,147 +189,129 @@ function Threshold({ data-handler-id={handlerId} className="threshold-container" > - -
-
- {isEditMode ? ( - - ) : ( - - )} - - -
-
- - {selectedGraph === PANEL_TYPES.TIME_SERIES && ( - - Label - {isEditMode ? ( - - ) : ( - - )} - +
+
+ {selectedGraph === PANEL_TYPES.TIME_SERIES && ( +
+ Label + {isEditMode ? ( + + ) : ( + )} - {(selectedGraph === PANEL_TYPES.VALUE || - selectedGraph === PANEL_TYPES.TABLE) && ( +
+ )} + {(selectedGraph === PANEL_TYPES.VALUE || + selectedGraph === PANEL_TYPES.TABLE) && ( + <> + + If value {selectedGraph === PANEL_TYPES.TABLE ? 'in' : 'is'} + + {isEditMode ? ( <> - - If value {selectedGraph === PANEL_TYPES.TABLE ? 'in' : 'is'} - - {isEditMode ? ( - <> - {selectedGraph === PANEL_TYPES.TABLE && ( - - - - ) : ( - <> - {selectedGraph === PANEL_TYPES.TABLE && ( - - - is - - )} - - + is + )} + - ) : ( - + <> + {selectedGraph === PANEL_TYPES.TABLE && ( + + + is + + )} + + )} - -
-
- - Show with - - {isEditMode ? ( - <> - - + ) : ( + + )} +
+
+ {isEditMode ? ( + <> +
+ +
+ + - +
); } diff --git a/frontend/src/container/NewWidget/RightContainer/index.tsx b/frontend/src/container/NewWidget/RightContainer/index.tsx index d00dcb1130..f8b25659d4 100644 --- a/frontend/src/container/NewWidget/RightContainer/index.tsx +++ b/frontend/src/container/NewWidget/RightContainer/index.tsx @@ -1,15 +1,6 @@ -import { UploadOutlined } from '@ant-design/icons'; -import { - Button, - Divider, - Input, - InputNumber, - Select, - Space, - Switch, - Typography, -} from 'antd'; -import InputComponent from 'components/Input'; +import './RightContainer.styles.scss'; + +import { Input, InputNumber, Select, Space, Switch, Typography } from 'antd'; import TimePreference from 'components/TimePreferenceDropDown'; import { PANEL_TYPES } from 'constants/queryBuilder'; import GraphTypes, { @@ -17,6 +8,7 @@ import GraphTypes, { } from 'container/NewDashboard/ComponentsSlider/menuItems'; import useCreateAlerts from 'hooks/queryBuilder/useCreateAlerts'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; +import { ConciergeBell, Plus } from 'lucide-react'; import { Dispatch, SetStateAction, @@ -35,7 +27,6 @@ import { panelTypeVsThreshold, panelTypeVsYAxisUnit, } from './constants'; -import { Container, Title } from './styles'; import ThresholdSelector from './Threshold/ThresholdSelector'; import { ThresholdProps } from './Threshold/types'; import { timePreferance } from './timeItems'; @@ -118,67 +109,72 @@ function RightContainer({ ); return ( - - Panel Type - - Panel Attributes - - - onChangeHandler(setTitle, event.target.value) - } - value={title} - /> - - Description +
+
+
+ Panel details +
+
+ Name + onChangeHandler(setTitle, event.target.value)} + value={title} + rootClassName="name-input" + /> + Description +