Compare commits
38 Commits
tpapi-demo
...
v0.45.0-da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dd0debcc6 | ||
|
|
d85ba14a25 | ||
|
|
6d64f250bb | ||
|
|
ddb3a8b568 | ||
|
|
b689e8997d | ||
|
|
5024d5dbc2 | ||
|
|
f8f45af3b5 | ||
|
|
ba8b40ccfb | ||
|
|
8679083e68 | ||
|
|
f1b0144c01 | ||
|
|
46c2420768 | ||
|
|
e322068d2f | ||
|
|
4429d998e5 | ||
|
|
709f119ce7 | ||
|
|
0516441b52 | ||
|
|
1517af2639 | ||
|
|
2d186efc19 | ||
|
|
55ae60590d | ||
|
|
43e6fae902 | ||
|
|
6b4169a3fb | ||
|
|
dfc159b1e4 | ||
|
|
4dcbaa8638 | ||
|
|
04f6faacc8 | ||
|
|
00c13585e5 | ||
|
|
52c6a93db8 | ||
|
|
6c458d98ad | ||
|
|
65b1922b10 | ||
|
|
f991197255 | ||
|
|
178ffc187e | ||
|
|
1d5189b693 | ||
|
|
f6b9971e61 | ||
|
|
9a9a77f452 | ||
|
|
5890184f45 | ||
|
|
67a360d3e2 | ||
|
|
6f901ef31c | ||
|
|
eb591ff296 | ||
|
|
272451be12 | ||
|
|
a0f0803966 |
@@ -85,7 +85,7 @@
|
|||||||
"less": "^4.1.2",
|
"less": "^4.1.2",
|
||||||
"less-loader": "^10.2.0",
|
"less-loader": "^10.2.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"lucide-react": "0.321.0",
|
"lucide-react": "0.379.0",
|
||||||
"mini-css-extract-plugin": "2.4.5",
|
"mini-css-extract-plugin": "2.4.5",
|
||||||
"papaparse": "5.4.1",
|
"papaparse": "5.4.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
|||||||
1
frontend/public/Icons/dashboard_emoji.svg
Normal file
1
frontend/public/Icons/dashboard_emoji.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="32" height="32" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.72 12.839l-9.054.92s.05.649.236.798c.178.142 5.617.066 11.048.088 5.433.023 10.82.125 10.944.072.249-.107.249-.992.249-.992l-13.424-.886zM16.55 7.787l-12.623-.32s.275.61.637.813c.523.29 3.71.889 11.518.918 7.808.028 10.635-.4 11.317-.678.58-.238 1.215-1.576 1.215-1.576l-12.064.843z" fill="#8A1E0C"/><path d="M21.95 8.658v1.335l2.176-.087V8.542l-2.176.116z" fill="#8A1E0C"/><path d="M21.948 9.566h2.177v16.797l-2.206.294.029-17.09z" fill="#EB2901"/><path d="M21.355 26.19c-.111.193-.111 2.297-.007 2.444.105.147 3.242.104 3.326 0 .085-.104.063-2.38 0-2.464-.062-.085-3.235-.125-3.32.02z" fill="#474C4F"/><path d="M8.462 9.85V8.488l2.042.125v1.22l-2.042.017z" fill="#8A1E0C"/><path d="M8.462 9.55l-.038 17.051 2.08-.207V9.566l-2.042-.015z" fill="#EB2901"/><path d="M7.804 25.919c-.073.073-.147 2.36-.02 2.464.125.104 3.14.129 3.244.024.105-.104.085-2.304.023-2.43-.063-.127-3.142-.163-3.247-.058z" fill="#474C4F"/><path d="M14.788 8.107v4.876l2.393-.33V8.108h-2.393z" fill="#EB2901"/><path d="M27.067 11.978c-.115-.16-.482-.138-.482-.138l-1.137-.013c.002-.398-.01-.913-.078-.996-.116-.137-4.542-.09-4.702.047-.091.078-.11.527-.107.898-2.738-.027-5.99-.058-8.83-.076 0-.384-.012-.849-.078-.915-.116-.116-4.22-.185-4.38-.07-.113.083-.136.647-.138.97-1.384.002-2.275.013-2.34.04-.322.137-.137 2.042-.137 2.042l22.476.16c.002.002.049-1.787-.067-1.95z" fill="#EB2901"/><path d="M3.93 6.942s-.646-.34-1.377-1.573c-.509-.858-.595-1.658-.387-1.778.21-.12 2.154 1.08 5.745 1.616a60.81 60.81 0 008.173.644c2.884.027 5.717-.135 8.397-.644 3.62-.689 4.906-1.436 5.264-1.316.36.12-.109 1.227-.369 1.78-.178.376-.944 1.77-1.515 1.87-.411.072-19.953-.09-19.953-.09l-3.977-.509z" fill="#474C4F"/><path d="M3.31 5.724c-.108.137-.057.457.212 1.06.107.237.415.782.529.917 0 0 2.982.756 11.977.7 8.995-.055 12.108-.62 12.108-.62s.911-1.277.745-1.32c-.096-.024-4.847.98-12.909.898C7.911 7.277 3.311 5.724 3.311 5.724z" fill="#EB2901"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
1
frontend/public/Icons/dashboards.svg
Normal file
1
frontend/public/Icons/dashboards.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 5.2 KiB |
1
frontend/public/Icons/landscape.svg
Normal file
1
frontend/public/Icons/landscape.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.1 KiB |
1
frontend/public/Icons/tools.svg
Normal file
1
frontend/public/Icons/tools.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="14" height="14" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.305 13.063c.74.739 1.637.482 2.156-.109.53-.604.813-.956.813-.956.66-.973 3.392-4.227 5.724-6.568a2.638 2.638 0 002.74-.434 2.648 2.648 0 00.922-2.041.155.155 0 00-.23-.132l-1.607.927a1.64 1.64 0 01-1.076-1.864l1.6-.923a.153.153 0 00.077-.134.153.153 0 00-.077-.133 2.65 2.65 0 00-3.66 3.563C6.11 6.826 2.966 9.604 2.15 10.223c0 0-.492.356-.962.84-.464.476-.636 1.245.117 1.999zm.542-1.137a.592.592 0 111.184 0 .592.592 0 01-1.184 0z" fill="#82AEC0"/><path d="M8.334 4.61l.353-.35a2.63 2.63 0 01-.212-2.039c.073-.12.189-.249.262-.171-.03.946.245 1.931.902 2.611.327.338.752.582 1.207.696.224.057.458.082.69.069.137-.008.519-.149.596-.044v.004a2.656 2.656 0 01-2.135.043 38.176 38.176 0 00-1.903 2.05c.262-.495 1.034-1.408 1.241-1.757a.412.412 0 00-.036-.464c-.207-.255-.633-.493-.965-.649z" fill="#2F7889"/><path d="M5.186 8.529c.06-.062.004-.167-.08-.148-.158.035-.386.125-.657.345-.531.43-1.934 1.595-2.107 1.825-.173.23.522-.003.767-.047.2-.036 1.602-1.48 2.077-1.975zM10.048 1.104c-.296.212-.563.465-.84.701-.072.061-.177.122-.25.065-.08-.064-.03-.191.03-.274C9.512.874 10.493.358 11.442.563c-.5.161-.95.223-1.395.541z" fill="#B9E4EA"/><path d="M12.408 3.583a2.1 2.1 0 01-.371.19c-.112.031-.43-.092-.522-.166l1.183-.772c.043-.028.087-.056.137-.072a.546.546 0 01.185-.014c.087.004.51-.01.56.064.05.075-.126.149-.183.183-.33.197-.66.391-.99.587zM7.867 7.687L6.624 6.254c-.45.423-.895.835-1.321 1.225l.362-.078a.482.482 0 01.439.13l.58.65c.122.122.142.334.096.5l-.065.308c.367-.423.755-.862 1.152-1.302z" fill="#2F7889"/><g><path d="M13.378 12.86l-.744.643a.686.686 0 01-.968-.072L2.84 2.779l1.135-.853 9.459 9.976a.668.668 0 01-.057.957z" fill="#A06841"/><path d="M3.648 3.752l2.1 2.535c.328-.493.494-1.084.629-1.83l-2.028-2.14a1.838 1.838 0 00-.414.48 2.17 2.17 0 00-.287.955z" fill="#7D5133"/><path d="M7.81.438C5.885.416 5.17.588 4.098 1.515l-.966.835c-.35.302-.815.566-.742 1.089.027.19.086.384.05.573-.034.179-.242.268-.39.166-.139-.096-.292-.214-.463-.234a.588.588 0 00-.45.14l-.747.664s-.107.434.729 1.38c.835.946 1.373.878 1.373.878l.702-.618a.53.53 0 00.176-.412c-.003-.184-.11-.326-.174-.49-.013-.031-.083-.143.04-.244.109-.094.333-.062.46-.027.129.034.25.088.38.122.25.065.369-.051.543-.201L6.013 3.93c.619-.536-.325-1.474-.325-1.474C5.244 1.953 7.941.687 7.941.687c.198-.069.138-.246-.13-.249z" fill="#82AEC0"/><path d="M4.076 5.338a.504.504 0 00.14.016v-.02c-.011-.12-.077-.23-.144-.33A7.18 7.18 0 002.545 3.33a1.683 1.683 0 00-.154-.111.726.726 0 00-.002.22c.027.19.086.384.05.573-.038.196-.242.25-.399.177a3.27 3.27 0 011.011 1.027c.035.056.07.115.11.168a.2.2 0 01.075-.14c.109-.095.333-.063.46-.029.13.034.25.088.38.123zM1.778 5.573c.585.613.914 1.247.734 1.42-.179.17-.799-.186-1.384-.797C.542 5.584.21 4.92.388 4.748c.18-.171.804.213 1.39.825z" fill="#2F7889"/><path d="M4.057 2.41c.465-.198.88-.623 1.422-1.09A2.53 2.53 0 016.03.964c.076-.035.048-.149-.036-.148-.278.005-.527.09-.772.196-.342.149-.644.374-.935.608-.2.16-.67.555-.965.805-.055.047-.012.12.06.12.208.002.325.014.674-.135zM1.124 4.352c-.196.221.055.281.496.646.311.257.642.018.645-.223.003-.216-.052-.333-.366-.53-.315-.199-.597-.093-.775.107z" fill="#B9E4EA"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.2 KiB |
234
frontend/public/Images/blankDashboardTemplatePreview.svg
Normal file
234
frontend/public/Images/blankDashboardTemplatePreview.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 204 KiB |
9
frontend/public/Images/redisTemplatePreview.svg
Normal file
9
frontend/public/Images/redisTemplatePreview.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 1.7 MiB |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"create_dashboard": "Create Dashboard",
|
"create_dashboard": "Create Dashboard",
|
||||||
"import_json": "Import JSON",
|
"import_json": "Import Dashboard JSON",
|
||||||
"import_grafana_json": "Import Grafana JSON",
|
"import_grafana_json": "Import Grafana JSON",
|
||||||
"copy_to_clipboard": "Copy To ClipBoard",
|
"copy_to_clipboard": "Copy To ClipBoard",
|
||||||
"download_json": "Download JSON",
|
"download_json": "Download JSON",
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"upload_json_file": "Upload JSON file",
|
"upload_json_file": "Upload JSON file",
|
||||||
"paste_json_below": "Paste JSON below",
|
"paste_json_below": "Paste JSON below",
|
||||||
"error_upload_json": "Invalid JSON",
|
"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",
|
"import_dashboard_by_pasting": "Import dashboard by pasting JSON or importing JSON file",
|
||||||
"error_loading_json": "Error loading JSON file",
|
"error_loading_json": "Error loading JSON file",
|
||||||
"empty_json_not_allowed": "Empty JSON is not allowed",
|
"empty_json_not_allowed": "Empty JSON is not allowed",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"create_dashboard": "Create Dashboard",
|
"create_dashboard": "Create Dashboard",
|
||||||
"import_json": "Import JSON",
|
"import_json": "Import Dashboard JSON",
|
||||||
"import_grafana_json": "Import Grafana JSON",
|
"import_grafana_json": "Import Grafana JSON",
|
||||||
"copy_to_clipboard": "Copy To ClipBoard",
|
"copy_to_clipboard": "Copy To ClipBoard",
|
||||||
"download_json": "Download JSON",
|
"download_json": "Download JSON",
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"upload_json_file": "Upload JSON file",
|
"upload_json_file": "Upload JSON file",
|
||||||
"paste_json_below": "Paste JSON below",
|
"paste_json_below": "Paste JSON below",
|
||||||
"error_upload_json": "Invalid JSON",
|
"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",
|
"import_dashboard_by_pasting": "Import dashboard by pasting JSON or importing JSON file",
|
||||||
"error_loading_json": "Error loading JSON file",
|
"error_loading_json": "Error loading JSON file",
|
||||||
"empty_json_not_allowed": "Empty JSON is not allowed",
|
"empty_json_not_allowed": "Empty JSON is not allowed",
|
||||||
|
|||||||
@@ -1,26 +1,20 @@
|
|||||||
import axios from 'api';
|
import axios from 'api';
|
||||||
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
|
|
||||||
import { AxiosError } from 'axios';
|
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import { PayloadProps, Props } from 'types/api/dashboard/update';
|
import { PayloadProps, Props } from 'types/api/dashboard/update';
|
||||||
|
|
||||||
const updateDashboard = async (
|
const updateDashboard = async (
|
||||||
props: Props,
|
props: Props,
|
||||||
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
|
||||||
try {
|
const response = await axios.put(`/dashboards/${props.uuid}`, {
|
||||||
const response = await axios.put(`/dashboards/${props.uuid}`, {
|
...props.data,
|
||||||
...props.data,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
error: null,
|
error: null,
|
||||||
message: response.data.status,
|
message: response.data.status,
|
||||||
payload: response.data.data,
|
payload: response.data.data,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
|
||||||
return ErrorResponseHandler(error as AxiosError);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default updateDashboard;
|
export default updateDashboard;
|
||||||
|
|||||||
176
frontend/src/assets/CustomIcons/ApacheIcon.tsx
Normal file
176
frontend/src/assets/CustomIcons/ApacheIcon.tsx
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
export default function ApacheIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8.7112 1.05739C8.3796 1.30831 8.08524 1.60498 7.83691 1.93853L8.17977 2.58567C8.40218 2.26279 8.64677 1.95576 8.91177 1.66681C8.93063 1.64581 8.94091 1.63596 8.94091 1.63596L8.91177 1.66681C8.66003 1.95965 8.43081 2.27111 8.22606 2.59853C8.67305 2.56672 9.11808 2.51165 9.55934 2.43353C9.60936 2.25525 9.62374 2.06886 9.60168 1.88502C9.57962 1.70118 9.52154 1.52349 9.43077 1.3621C9.43077 1.3621 9.09991 0.828957 8.7112 1.05739Z"
|
||||||
|
fill="url(#paint0_linear_2061_4195)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.55932 6.49365L7.42432 6.51722L7.49332 6.50651C7.51432 6.50265 7.53703 6.49837 7.55932 6.49365Z"
|
||||||
|
fill="#BE202E"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
opacity="0.35"
|
||||||
|
d="M7.55932 6.49365L7.42432 6.51722L7.49332 6.50651C7.51432 6.50265 7.53703 6.49837 7.55932 6.49365Z"
|
||||||
|
fill="#BE202E"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.67407 5.92858L7.6955 5.92558C7.72464 5.9213 7.75336 5.91616 7.78122 5.91016L7.67493 5.92816L7.67407 5.92858Z"
|
||||||
|
fill="#BE202E"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
opacity="0.35"
|
||||||
|
d="M7.67407 5.92858L7.6955 5.92558C7.72464 5.9213 7.75336 5.91616 7.78122 5.91016L7.67493 5.92816L7.67407 5.92858Z"
|
||||||
|
fill="#BE202E"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.16872 4.25736C7.273 4.0625 7.37858 3.87221 7.48543 3.6865C7.59629 3.49393 7.70829 3.3075 7.82143 3.12721L7.84115 3.09507C7.95315 2.91793 8.066 2.74779 8.17972 2.58464L7.83686 1.9375L7.75886 2.03393C7.65986 2.15736 7.55743 2.29107 7.452 2.43036C7.33329 2.58893 7.21115 2.75779 7.08729 2.93564C6.97286 3.09979 6.85672 3.27164 6.74058 3.44993C6.64158 3.60121 6.54258 3.75721 6.444 3.91707L6.43286 3.93507L6.879 4.8145C6.97443 4.62707 7.071 4.44136 7.16872 4.25736Z"
|
||||||
|
fill="url(#paint1_linear_2061_4195)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M5.13606 9.22519C5.07692 9.38748 5.01763 9.55305 4.95821 9.72191L4.95563 9.72919L4.93035 9.80076C4.89049 9.91476 4.85535 10.015 4.77563 10.2503C4.92444 10.3467 5.0416 10.4847 5.11249 10.6472C5.10283 10.4581 5.01907 10.2804 4.87935 10.1526C5.16043 10.1981 5.44862 10.1654 5.71236 10.0581C5.97609 9.95074 6.20521 9.77291 6.37463 9.54405C6.40102 9.50088 6.42464 9.45607 6.44535 9.40991C6.37459 9.49741 6.28141 9.56408 6.17575 9.6028C6.07008 9.64152 5.95589 9.65084 5.84535 9.62976C6.20937 9.49539 6.51802 9.24316 6.72221 8.91319C6.76978 8.83691 6.81563 8.75376 6.86278 8.66162C6.6974 8.84328 6.48756 8.97872 6.25393 9.05463C6.02029 9.13053 5.77091 9.14426 5.53035 9.09448L5.16949 9.13391C5.15706 9.16434 5.14721 9.19476 5.13606 9.22519Z"
|
||||||
|
fill="url(#paint2_linear_2061_4195)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M5.30448 8.417C5.38248 8.21528 5.46276 8.01157 5.54533 7.80586C5.62419 7.60871 5.70519 7.41057 5.78833 7.21143C5.87148 7.01228 5.95633 6.81228 6.0429 6.61143C6.1309 6.40828 6.22076 6.20557 6.31248 6.00328C6.40419 5.801 6.49633 5.60257 6.5889 5.408C6.62262 5.33714 6.65662 5.26643 6.6909 5.19586C6.75005 5.07414 6.80962 4.95343 6.86962 4.83371C6.87262 4.82728 6.87605 4.82086 6.87948 4.81443L6.4329 3.93457L6.41105 3.97014C6.30733 4.14157 6.20362 4.313 6.10205 4.49128C6.00048 4.66957 5.89848 4.853 5.80205 5.03814C5.7189 5.19443 5.63776 5.35157 5.55862 5.50957L5.51148 5.606C5.41419 5.80614 5.32633 5.99943 5.24705 6.18543C5.15705 6.396 5.07762 6.59686 5.00876 6.788C4.9629 6.91357 4.92305 7.03486 4.88362 7.151C4.85233 7.25043 4.82276 7.34986 4.79448 7.451C4.72762 7.68471 4.67048 7.91771 4.62305 8.15L5.07133 9.035C5.13076 8.87671 5.19162 8.71614 5.2539 8.55328L5.30448 8.417Z"
|
||||||
|
fill="url(#paint3_linear_2061_4195)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M4.615 8.18082C4.55868 8.46014 4.51975 8.74268 4.49843 9.02682C4.49843 9.03668 4.49843 9.04653 4.49629 9.05639C4.3547 8.8778 4.1801 8.72808 3.982 8.61539C4.24526 8.95089 4.41819 9.34823 4.48429 9.76953C4.28982 9.78674 4.0942 9.75338 3.91643 9.67268C4.05057 9.80984 4.21714 9.91096 4.40072 9.96668C4.14974 10.0146 3.9168 10.1307 3.72743 10.3022C3.97375 10.178 4.25059 10.1271 4.525 10.1557C4.21858 11.024 3.91129 11.9827 3.604 13.0001C3.64664 12.988 3.6856 12.9655 3.71739 12.9346C3.74918 12.9037 3.7728 12.8654 3.78615 12.8231C3.841 12.6388 4.20443 11.4298 4.77443 9.84068L4.82372 9.70439L4.83743 9.66625C4.89772 9.49968 4.96015 9.32968 5.02472 9.15625L5.06758 9.03753V9.03539L4.62143 8.15039C4.61929 8.16025 4.61672 8.17053 4.615 8.18082Z"
|
||||||
|
fill="url(#paint4_linear_2061_4195)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.94843 4.89059L6.90986 4.96987C6.87129 5.04959 6.83214 5.13102 6.79243 5.21416C6.74957 5.30416 6.70671 5.3963 6.66386 5.49059C6.64157 5.53816 6.621 5.58573 6.59743 5.63416C6.53057 5.7793 6.46286 5.92916 6.39429 6.08373C6.30857 6.27402 6.22286 6.47173 6.13714 6.67687C6.054 6.87259 5.96971 7.07516 5.88429 7.28459C5.80314 7.48459 5.721 7.68973 5.63786 7.90002C5.56386 8.08888 5.48914 8.28273 5.41371 8.48159C5.40986 8.49145 5.40643 8.50087 5.403 8.51073C5.32814 8.70873 5.25257 8.91187 5.17629 9.12016L5.17114 9.1343L5.532 9.09487L5.51057 9.09102C6.039 8.98351 6.52026 8.7126 6.88629 8.31659C7.0686 8.1182 7.22683 7.89896 7.35771 7.66345C7.47147 7.46033 7.57252 7.25036 7.66029 7.03473C7.74386 6.83245 7.824 6.61387 7.90114 6.37645C7.79448 6.43086 7.68084 6.47037 7.56343 6.49388C7.54157 6.49859 7.52057 6.50287 7.49657 6.50673C7.47257 6.51059 7.45071 6.51445 7.42757 6.51745C7.80325 6.36305 8.10458 6.06924 8.26843 5.69759C8.12155 5.79773 7.95733 5.86966 7.78414 5.90973C7.75586 5.91616 7.72757 5.92087 7.69843 5.92516L7.677 5.92816C7.80484 5.87656 7.92565 5.80903 8.03657 5.72716C8.05843 5.71087 8.07943 5.69373 8.1 5.67573C8.13129 5.64873 8.16086 5.62045 8.18914 5.59002C8.20714 5.57116 8.22471 5.55145 8.24186 5.53087C8.28293 5.48179 8.32059 5.42996 8.35457 5.37573C8.36529 5.35859 8.376 5.34145 8.38629 5.32345C8.39957 5.29773 8.41243 5.27245 8.42486 5.24716C8.481 5.13402 8.526 5.03288 8.56157 4.94459C8.57957 4.90173 8.595 4.85888 8.60829 4.82116C8.61386 4.80616 8.619 4.79116 8.62371 4.7783C8.63786 4.73545 8.64943 4.69816 8.65843 4.66473C8.66941 4.62595 8.67828 4.58661 8.685 4.54688C8.67015 4.5586 8.65454 4.56934 8.63829 4.57902C8.4822 4.66169 8.31419 4.71953 8.14029 4.75045H8.13257L8.08157 4.75859L8.09057 4.75473L6.957 4.87902L6.94843 4.89059Z"
|
||||||
|
fill="url(#paint5_linear_2061_4195)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.22475 2.59871C8.12404 2.75343 8.01389 2.92914 7.89561 3.12843L7.87675 3.16014C7.77446 3.33157 7.66604 3.52114 7.55147 3.72886C7.45261 3.90771 7.34989 4.10014 7.24332 4.30614C7.15018 4.48586 7.05418 4.67671 6.95532 4.87871L8.08889 4.75443C8.33914 4.65567 8.55501 4.48583 8.70989 4.26586C8.74804 4.211 8.78618 4.15357 8.82432 4.09443C8.94089 3.91271 9.05489 3.71257 9.15689 3.51371C9.25018 3.33322 9.33429 3.14813 9.40889 2.95914C9.44758 2.86102 9.48092 2.76087 9.50875 2.65914C9.52932 2.58028 9.54561 2.50571 9.55804 2.43457C9.11675 2.51236 8.67172 2.56715 8.22475 2.59871Z"
|
||||||
|
fill="url(#paint6_linear_2061_4195)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.49234 6.50635C7.46963 6.5102 7.44648 6.51406 7.42334 6.51706C7.44648 6.51406 7.47134 6.5102 7.49234 6.50635Z"
|
||||||
|
fill="#BE202E"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
opacity="0.35"
|
||||||
|
d="M7.49234 6.50635C7.46963 6.5102 7.44648 6.51406 7.42334 6.51706C7.44648 6.51406 7.47134 6.5102 7.49234 6.50635Z"
|
||||||
|
fill="#BE202E"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.49234 6.50635C7.46963 6.5102 7.44648 6.51406 7.42334 6.51706C7.44648 6.51406 7.47134 6.5102 7.49234 6.50635Z"
|
||||||
|
fill="url(#paint7_linear_2061_4195)"
|
||||||
|
/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient
|
||||||
|
id="paint0_linear_2061_4195"
|
||||||
|
x1="7.26579"
|
||||||
|
y1="1.16584"
|
||||||
|
x2="9.7782"
|
||||||
|
y2="0.46843"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stopColor="#F69923" />
|
||||||
|
<stop offset="0.312" stopColor="#F79A23" />
|
||||||
|
<stop offset="0.838" stopColor="#E97826" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint1_linear_2061_4195"
|
||||||
|
x1="1.76109"
|
||||||
|
y1="12.4382"
|
||||||
|
x2="6.87606"
|
||||||
|
y2="1.48267"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0.323" stopColor="#9E2064" />
|
||||||
|
<stop offset="0.63" stopColor="#C92037" />
|
||||||
|
<stop offset="0.751" stopColor="#CD2335" />
|
||||||
|
<stop offset="1" stopColor="#E97826" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint2_linear_2061_4195"
|
||||||
|
x1="3.47784"
|
||||||
|
y1="11.6287"
|
||||||
|
x2="6.5258"
|
||||||
|
y2="5.10046"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stopColor="#282662" />
|
||||||
|
<stop offset="0.095" stopColor="#662E8D" />
|
||||||
|
<stop offset="0.788" stopColor="#9F2064" />
|
||||||
|
<stop offset="0.949" stopColor="#CD2032" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint3_linear_2061_4195"
|
||||||
|
x1="1.94596"
|
||||||
|
y1="11.7748"
|
||||||
|
x2="7.06094"
|
||||||
|
y2="0.819304"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0.323" stopColor="#9E2064" />
|
||||||
|
<stop offset="0.63" stopColor="#C92037" />
|
||||||
|
<stop offset="0.751" stopColor="#CD2335" />
|
||||||
|
<stop offset="1" stopColor="#E97826" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint4_linear_2061_4195"
|
||||||
|
x1="2.46768"
|
||||||
|
y1="11.0455"
|
||||||
|
x2="5.15578"
|
||||||
|
y2="5.28798"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stopColor="#282662" />
|
||||||
|
<stop offset="0.095" stopColor="#662E8D" />
|
||||||
|
<stop offset="0.788" stopColor="#9F2064" />
|
||||||
|
<stop offset="0.949" stopColor="#CD2032" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint5_linear_2061_4195"
|
||||||
|
x1="3.08048"
|
||||||
|
y1="12.3044"
|
||||||
|
x2="8.19546"
|
||||||
|
y2="1.3489"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0.323" stopColor="#9E2064" />
|
||||||
|
<stop offset="0.63" stopColor="#C92037" />
|
||||||
|
<stop offset="0.751" stopColor="#CD2335" />
|
||||||
|
<stop offset="1" stopColor="#E97826" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint6_linear_2061_4195"
|
||||||
|
x1="2.70679"
|
||||||
|
y1="12.9581"
|
||||||
|
x2="7.82195"
|
||||||
|
y2="2.00223"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0.323" stopColor="#9E2064" />
|
||||||
|
<stop offset="0.63" stopColor="#C92037" />
|
||||||
|
<stop offset="0.751" stopColor="#CD2335" />
|
||||||
|
<stop offset="1" stopColor="#E97826" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint7_linear_2061_4195"
|
||||||
|
x1="3.41759"
|
||||||
|
y1="12.4619"
|
||||||
|
x2="8.53277"
|
||||||
|
y2="1.50629"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0.323" stopColor="#9E2064" />
|
||||||
|
<stop offset="0.63" stopColor="#C92037" />
|
||||||
|
<stop offset="0.751" stopColor="#CD2335" />
|
||||||
|
<stop offset="1" stopColor="#E97826" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
28
frontend/src/assets/CustomIcons/DockerIcon.tsx
Normal file
28
frontend/src/assets/CustomIcons/DockerIcon.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
export default function DockerIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g clipPath="url(#clip0_2061_4220)">
|
||||||
|
<path
|
||||||
|
d="M13.574 5.82107C13.2652 5.60679 12.5575 5.52644 12.0042 5.63358C11.9398 5.09788 11.6439 4.62915 11.1292 4.21399L10.8332 3.99971L10.6274 4.30774C10.37 4.70951 10.2413 5.27198 10.2799 5.80768C10.2928 5.99517 10.3571 6.32998 10.5502 6.62461C10.37 6.73175 9.99686 6.86567 9.50789 6.86567H0.204685L0.17895 6.97281C0.0888774 7.5085 0.0888774 9.18254 1.14401 10.4682C1.9418 11.4458 3.12561 11.9414 4.68258 11.9414C8.05386 11.9414 10.5502 10.3209 11.7211 7.38797C12.1843 7.40136 13.1751 7.38797 13.677 6.38354C13.6898 6.35676 13.7156 6.30319 13.8056 6.10231L13.8571 5.99517L13.574 5.82107ZM7.6421 2.04443H6.22668V3.38367H7.6421V2.04443ZM7.6421 3.65151H6.22668V4.99074H7.6421V3.65151ZM5.96933 3.65151H4.5539V4.99074H5.96933V3.65151ZM4.29655 3.65151H2.88113V4.99074H4.29655V3.65151ZM2.62378 5.25859H1.20835V6.59782H2.62378V5.25859ZM4.29655 5.25859H2.88113V6.59782H4.29655V5.25859ZM5.96933 5.25859H4.5539V6.59782H5.96933V5.25859ZM7.6421 5.25859H6.22668V6.59782H7.6421V5.25859ZM9.31488 5.25859H7.89945V6.59782H9.31488V5.25859Z"
|
||||||
|
fill="#2396ED"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_2061_4220">
|
||||||
|
<rect
|
||||||
|
width="13.7143"
|
||||||
|
height="13.7143"
|
||||||
|
fill="white"
|
||||||
|
transform="translate(0.142822 0.143066)"
|
||||||
|
/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
36
frontend/src/assets/CustomIcons/ElasticSearchIcon.tsx
Normal file
36
frontend/src/assets/CustomIcons/ElasticSearchIcon.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
export default function ElasticSearchIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.38041 6.94508L9.70241 8.45858L13.0524 5.52158C13.1019 5.27892 13.1255 5.03171 13.1229 4.78408C13.1236 3.9846 12.8681 3.20592 12.3941 2.56216C11.92 1.9184 11.2522 1.44339 10.4885 1.20675C9.72487 0.970101 8.9055 0.984259 8.15047 1.24714C7.39544 1.51003 6.74446 2.00782 6.29291 2.66758L5.73291 5.56008L6.38041 6.94508Z"
|
||||||
|
fill="#FED10A"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2.943 10.4593C2.89356 10.7062 2.86994 10.9575 2.8725 11.2093C2.87361 12.012 3.13177 12.7932 3.60915 13.4385C4.08654 14.0838 4.75804 14.5592 5.52528 14.7952C6.29252 15.0311 7.11514 15.0151 7.87262 14.7495C8.63009 14.4839 9.28259 13.9827 9.7345 13.3193L10.2845 10.4398L9.55 9.02928L6.215 7.50928L2.943 10.4593Z"
|
||||||
|
fill="#24BBB1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2.92394 4.71302L5.19994 5.25002L5.69994 2.66552C5.39077 2.43015 5.01365 2.30134 4.62509 2.29839C4.23654 2.29544 3.8575 2.41852 3.54479 2.64916C3.23208 2.8798 3.00256 3.20559 2.89063 3.57768C2.77869 3.94978 2.79039 4.34813 2.92394 4.71302Z"
|
||||||
|
fill="#EF5098"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2.72503 5.2583C2.23266 5.42016 1.80253 5.73058 1.49379 6.14687C1.18505 6.56317 1.01286 7.0649 1.00091 7.58305C0.988962 8.1012 1.13784 8.61033 1.42706 9.04041C1.71628 9.4705 2.13164 9.80042 2.61603 9.9848L5.81003 7.0998L5.22653 5.8498L2.72503 5.2583Z"
|
||||||
|
fill="#17A8E0"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10.312 13.3197C10.6209 13.5543 10.9975 13.6825 11.3853 13.6851C11.7732 13.6877 12.1514 13.5646 12.4634 13.3342C12.7755 13.1038 13.0044 12.7785 13.116 12.407C13.2276 12.0356 13.2159 11.6379 13.0825 11.2737L10.812 10.7412L10.312 13.3197Z"
|
||||||
|
fill="#93C83E"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10.7735 10.145L13.2735 10.7285C13.7666 10.5672 14.1976 10.257 14.507 9.84058C14.8165 9.42415 14.9891 8.922 15.0013 8.40333C15.0134 7.88467 14.8643 7.375 14.5747 6.94457C14.2851 6.51414 13.8691 6.18413 13.384 6L10.1135 8.8665L10.7735 10.145Z"
|
||||||
|
fill="#0779A1"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
18
frontend/src/assets/CustomIcons/GrafanaIcon.tsx
Normal file
18
frontend/src/assets/CustomIcons/GrafanaIcon.tsx
Normal file
File diff suppressed because one or more lines are too long
27
frontend/src/assets/CustomIcons/HerokuIcon.tsx
Normal file
27
frontend/src/assets/CustomIcons/HerokuIcon.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
function HerokuIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g clipPath="url(#clip0_2061_4245)">
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M13.6285 0H2.10787C1.31283 0 0.666748 0.644312 0.666748 1.44112V14.5602C0.666748 15.3557 1.31283 16 2.10787 16H13.6285C14.4237 16 15.0678 15.3557 15.0678 14.5602V1.44112C15.0678 0.644312 14.4237 0 13.6285 0ZM14.2677 14.5602C14.2677 14.9135 13.9815 15.1994 13.6285 15.1994H2.10787C1.75506 15.1994 1.46688 14.9135 1.46688 14.5602V1.44112C1.46688 1.08654 1.75506 0.800133 2.10787 0.800133H13.6285C13.9815 0.800133 14.2677 1.08654 14.2677 1.44112V14.5602ZM4.26699 13.6009L6.06823 12.0002L4.26699 10.3999V13.6009ZM10.7719 7.11485C10.4481 6.78927 9.8569 6.40038 8.86819 6.40038C7.78342 6.40038 6.66611 6.68302 5.86752 6.94177V2.40082H4.26704V9.33907L5.39807 8.82667C5.41688 8.81826 7.24025 8.00086 8.86819 8.00086C9.68027 8.00086 9.86022 8.44796 9.86885 8.82158V13.6009H11.4676V8.801C11.4693 8.6983 11.4592 7.81051 10.7719 7.11485ZM8.66761 5.00027H10.2681C10.9912 4.1811 11.3597 3.30903 11.4677 2.40066H9.86881C9.69063 3.30726 9.29643 4.17424 8.66761 5.00027Z"
|
||||||
|
fill="#6762A6"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_2061_4245">
|
||||||
|
<rect width="16" height="16" fill="white" />
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HerokuIcon;
|
||||||
82
frontend/src/assets/CustomIcons/JuiceBoxIcon.tsx
Normal file
82
frontend/src/assets/CustomIcons/JuiceBoxIcon.tsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
function JuiceBoxIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M7.15412 6.3041L3.80207 4.64419C3.80207 4.64419 3.79429 4.48531 3.94429 4.40531C4.09539 4.32532 6.47082 3.35204 6.66192 3.35204C6.85302 3.35204 7.97185 3.56758 8.78625 3.74868C9.60065 3.92978 11.7528 4.39198 11.7628 4.53308C11.7728 4.67419 9.56066 6.93629 9.56066 6.93629L7.15412 6.3041Z"
|
||||||
|
fill="#C3FECE"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10.2117 5.2686C10.2117 5.2686 8.80626 4.85529 7.43855 4.53419C6.80192 4.3842 4.93091 3.992 4.93091 3.992C4.93091 3.992 5.12979 3.90534 5.27978 3.84201C5.43199 3.77868 5.5531 3.74535 5.5531 3.74535C5.5531 3.74535 6.77303 3.98867 7.67965 4.18199C8.90625 4.44309 10.6228 4.95528 10.6628 5.03639C10.7039 5.11639 10.2117 5.2686 10.2117 5.2686Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.48978 4.87973C7.19091 5.0875 7.48423 5.21305 8.03531 5.34193C8.63861 5.48303 9.09858 5.6908 9.48634 5.46526C9.83632 5.26304 8.9797 5.04306 8.58639 4.95862C8.28641 4.89418 7.72088 4.71974 7.48978 4.87973Z"
|
||||||
|
fill="#ACB1B2"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.58521 5.29749C8.58299 5.29749 8.59521 2.86317 8.59521 2.77317C8.59521 2.68318 8.49411 2.60207 8.60521 2.41097C8.71632 2.21987 9.00741 2.23987 9.00741 2.23987C9.00741 2.23987 10.2151 1.88878 10.6973 1.76767C11.1795 1.64657 12.2461 1.36547 12.2461 1.36547L12.3172 1.97544C12.3172 1.97544 11.1995 2.29098 10.6462 2.43208C10.0929 2.57319 9.33851 2.80428 9.33851 2.80428L9.2274 2.90539L9.25962 5.28415C9.25962 5.28415 9.1563 5.3997 8.9252 5.3997C8.70076 5.39859 8.58521 5.29749 8.58521 5.29749Z"
|
||||||
|
fill="#FFD816"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M12.0472 1.67768C12.0561 1.86767 12.1572 1.98544 12.2772 1.98544C12.3972 1.98544 12.4794 1.83211 12.4616 1.63212C12.4427 1.43325 12.3138 1.34214 12.2038 1.3788C12.0939 1.41547 12.0405 1.5388 12.0472 1.67768Z"
|
||||||
|
fill="#FEB804"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9.22962 2.96094C9.20851 2.96094 9.1874 2.95539 9.16851 2.94206L8.59187 2.55763C8.54076 2.52319 8.52743 2.4543 8.56076 2.4032C8.59521 2.35209 8.66298 2.33764 8.7152 2.37209L9.29184 2.75651C9.34294 2.79095 9.35628 2.85984 9.32295 2.91095C9.30072 2.94317 9.26517 2.96094 9.22962 2.96094Z"
|
||||||
|
fill="#FEB804"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9.31847 2.86761C9.28514 2.86761 9.25181 2.85206 9.22959 2.82317C9.08182 2.62651 8.91294 2.40319 8.88294 2.36875C8.84516 2.33208 8.83739 2.27209 8.86739 2.22653C8.90183 2.17542 8.9696 2.16098 9.02182 2.19542C9.04182 2.20876 9.05293 2.21653 9.40736 2.68873C9.44402 2.73762 9.41069 2.80761 9.3618 2.84428C9.34181 2.85983 9.34181 2.86761 9.31847 2.86761Z"
|
||||||
|
fill="#FEB804"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9.18298 3.05427C9.17742 3.05427 9.17187 3.05427 9.1652 3.05316L8.60968 2.96539C8.54968 2.95539 8.50746 2.89872 8.51746 2.83873C8.52746 2.77873 8.58301 2.73651 8.64412 2.74651L9.19965 2.83428C9.25964 2.84428 9.31186 2.85539 9.30186 2.9165C9.29408 2.96983 9.23742 3.05427 9.18298 3.05427Z"
|
||||||
|
fill="#FEB804"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M3.79761 4.63197C3.97426 4.63197 5.39197 5.00417 6.12304 5.13861C6.85411 5.27304 9.06177 5.79524 9.13621 5.80968C9.21066 5.82413 9.19621 6.77963 9.19621 6.77963C9.19621 6.77963 10.2406 12.1793 10.2106 12.4338C10.1806 12.6871 9.49508 14.6414 9.49508 14.6414C9.49508 14.6414 9.09177 14.7014 8.06294 14.4026C7.0341 14.1037 4.31869 13.3582 4.15426 13.1493C3.98982 12.9404 4.09426 10.1806 4.00537 8.48065C3.91427 6.77963 3.79761 4.63197 3.79761 4.63197Z"
|
||||||
|
fill="#79DD8A"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M12.0294 13.2682C12.086 13.0804 11.7705 11.0672 11.7261 9.21728C11.6816 7.36849 11.8405 4.5553 11.7638 4.53308C11.6872 4.51197 9.13621 5.80968 9.13621 5.80968C9.13621 5.80968 9.1251 7.64514 9.15621 9.37616C9.1962 11.616 9.37508 14.5814 9.49396 14.6414C9.61285 14.7014 10.645 14.1237 10.9561 13.9548C11.5072 13.6559 11.9849 13.4182 12.0294 13.2682Z"
|
||||||
|
fill="#02AB46"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10.204 6.65964L10.2095 5.26638L10.6662 5.04195L10.6795 6.56964L10.4684 6.93962L10.204 6.65964Z"
|
||||||
|
fill="#DBDFE1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.16088 7.1485C5.17427 7.04295 4.49097 7.9229 4.5443 9.06951C4.60763 10.4239 5.4998 11.4216 6.46531 11.6205C7.43081 11.8194 8.36632 11.4005 8.38632 9.91947C8.40854 8.37621 7.05194 7.24294 6.16088 7.1485Z"
|
||||||
|
fill="#FEFEFD"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.81861 8.3851C6.81861 8.3851 6.61862 7.71292 6.01754 7.89179C5.41646 8.07067 5.09092 9.37838 6.11087 9.96724C7.09082 10.5328 7.99299 9.49504 7.67745 8.82286C7.3908 8.20956 6.81861 8.3851 6.81861 8.3851Z"
|
||||||
|
fill="#EF5B44"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.58968 7.56292C6.52191 7.58737 6.46858 7.86402 6.53968 8.12845C6.59302 8.32622 6.76301 8.59731 6.86189 8.57954C6.94077 8.56509 7.00077 8.254 6.92633 7.9929C6.83967 7.69181 6.66857 7.53404 6.58968 7.56292Z"
|
||||||
|
fill="#B8CF17"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.57531 9.12284C6.2931 9.03729 5.97534 10.0072 6.54642 10.6116C7.17639 11.2772 7.9119 10.6905 7.89191 10.5617C7.86302 10.3828 7.36971 10.2539 7.12639 9.9539C6.88307 9.6517 6.73974 9.17284 6.57531 9.12284Z"
|
||||||
|
fill="#FD8F01"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M5.67307 8.9584C5.67307 8.9584 5.72973 8.53398 5.33642 8.55731C4.95644 8.58065 5.04977 9.02951 5.04977 9.02951C5.04977 9.02951 4.73312 9.06729 4.78645 9.41838C4.82645 9.68392 5.10643 9.68059 5.10643 9.68059C5.10643 9.68059 4.79867 9.80169 4.93866 10.1528C5.0631 10.465 5.34975 10.3394 5.34975 10.3394C5.34975 10.3394 5.2442 10.6439 5.49308 10.805C5.70307 10.9405 5.88639 10.8261 5.88639 10.8261C5.88639 10.8261 5.87528 11.0861 6.16526 11.1338C6.51636 11.1916 6.66857 10.7639 6.41858 10.5661C6.22859 10.4161 6.05638 10.5328 6.05638 10.5328C6.05638 10.5328 6.09193 10.4494 6.0586 10.3539C6.03638 10.2917 6.00083 10.2683 6.00083 10.2683C6.00083 10.2683 6.30859 10.2394 6.25859 9.88947C6.2086 9.53837 5.90083 9.5817 5.90083 9.5817C5.90083 9.5817 6.07971 9.43838 6.00861 9.18061C5.93861 8.92174 5.67307 8.9584 5.67307 8.9584Z"
|
||||||
|
fill="#A281D0"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10.5205 7.04739C10.265 7.04739 9.17503 5.96412 9.16503 5.95301C9.12504 5.90634 9.13059 5.83635 9.17726 5.79635C9.22392 5.75635 9.29281 5.76191 9.33391 5.80746C9.40391 5.88523 10.2372 6.65853 10.4772 6.80741C10.6327 6.5752 11.1383 5.55858 11.5727 4.64085C11.5994 4.5853 11.666 4.56197 11.7205 4.58752C11.776 4.61419 11.7993 4.67974 11.7738 4.73529C10.7027 6.99851 10.5972 7.02851 10.5405 7.04406C10.5339 7.0474 10.5272 7.04739 10.5205 7.04739Z"
|
||||||
|
fill="#2D802D"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JuiceBoxIcon;
|
||||||
22
frontend/src/assets/CustomIcons/KubernetesIcon.tsx
Normal file
22
frontend/src/assets/CustomIcons/KubernetesIcon.tsx
Normal file
File diff suppressed because one or more lines are too long
38
frontend/src/assets/CustomIcons/MagicBallIcon.tsx
Normal file
38
frontend/src/assets/CustomIcons/MagicBallIcon.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
function MagicBallIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M13.2883 12.3928C14.4283 11.0451 15.4015 8.62412 14.396 5.84427C13.9061 4.49101 13.3528 3.73549 12.7084 3.25552C12.3162 2.96331 10.7496 2.2278 8.67524 2.54889C7.15865 2.78443 5.1332 3.74105 3.8166 5.29763C2.54 6.80978 1.5545 8.00416 1.50895 9.1641C1.45006 10.6562 2.57445 11.9384 2.71111 12.1462C2.95443 12.515 4.61434 14.6238 7.73306 14.7316C10.4862 14.826 12.2795 13.5861 13.2883 12.3928Z"
|
||||||
|
fill="#403D3E"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M4.04763 2.43331C2.61104 3.45881 0.996679 5.55647 1.28666 8.49854C1.42777 9.93069 1.77997 10.7995 2.2855 11.4228C2.59326 11.8028 3.92875 12.9328 6.02086 13.0994C8.12964 13.2672 9.73288 12.795 11.4072 11.6306C14.8104 9.26295 14.3093 5.68313 14.1638 5.26649C14.0182 4.84984 12.9283 2.39664 9.93176 1.52446C7.28746 0.755617 5.31867 1.52446 4.04763 2.43331Z"
|
||||||
|
fill="#5E6367"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.57189 2.63219C4.99308 2.57553 3.48427 3.81213 3.33872 5.33871C3.19318 6.86419 4.13757 8.02635 5.6086 8.263C7.07964 8.49855 8.78066 7.60526 9.12286 5.73425C9.47618 3.80657 8.07958 2.68663 6.57189 2.63219Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.05971 5.24541C7.05971 5.24541 7.43969 5.16653 7.51524 4.60655C7.58968 4.05547 7.31636 3.5855 6.67862 3.41662C5.98532 3.23329 5.51535 3.61438 5.39313 4.01547C5.22314 4.57322 5.47424 4.83876 5.47424 4.83876C5.47424 4.83876 4.79427 5.00209 4.73983 5.80427C4.68872 6.5609 5.20536 6.96754 5.72422 7.09198C6.3653 7.24642 7.09193 7.07087 7.2697 6.25313C7.41747 5.57984 7.05971 5.24541 7.05971 5.24541Z"
|
||||||
|
fill="#303030"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M5.99081 4.22544C5.92971 4.45543 6.05192 4.67764 6.29191 4.73874C6.55079 4.8043 6.78633 4.71875 6.84966 4.45431C6.90521 4.21988 6.79411 4.01323 6.52079 3.94656C6.29635 3.89101 6.05748 3.97434 5.99081 4.22544Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.18643 5.36871C5.89533 5.27871 5.51091 5.39093 5.4498 5.78202C5.38869 6.17311 5.62313 6.3731 5.92978 6.42865C6.23643 6.4842 6.52641 6.3231 6.58308 6.00978C6.63863 5.69758 6.47641 5.45759 6.18643 5.36871Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MagicBallIcon;
|
||||||
68
frontend/src/assets/CustomIcons/MongoDBIcon.tsx
Normal file
68
frontend/src/assets/CustomIcons/MongoDBIcon.tsx
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
export default function MongoDBIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M7.26568 13.0004L6.94382 12.8937C6.94382 12.8937 6.98668 11.2651 6.39739 11.1507C6.01168 10.7015 6.45439 -8.02403 7.86439 11.0868C7.59687 11.2225 7.39217 11.4564 7.29311 11.7395C7.24001 12.1577 7.23082 12.5803 7.26568 13.0004Z"
|
||||||
|
fill="url(#paint0_linear_2061_4238)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.43957 11.4272C8.29654 10.7821 8.95282 9.90701 9.33214 8.90369C9.71147 7.90037 9.79826 6.81 9.58243 5.75931C8.95243 2.98002 7.46058 2.06631 7.29986 1.71745C7.1612 1.50022 7.04284 1.27068 6.94629 1.03174L7.065 8.7756C7.065 8.7756 6.819 11.1422 7.43957 11.4272Z"
|
||||||
|
fill="url(#paint1_linear_2061_4238)"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.78015 11.5296C6.78015 11.5296 4.15687 9.74286 4.30858 6.58214C4.32273 5.62928 4.54121 4.69054 4.94926 3.82935C5.3573 2.96816 5.94542 2.20456 6.67387 1.59014C6.759 1.51782 6.82663 1.42715 6.87168 1.32493C6.91674 1.22272 6.93805 1.11163 6.93401 1C7.0973 1.35143 7.07072 6.247 7.08787 6.81957C7.1543 9.04686 6.96401 11.1091 6.78015 11.5296Z"
|
||||||
|
fill="url(#paint2_linear_2061_4238)"
|
||||||
|
/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient
|
||||||
|
id="paint0_linear_2061_4238"
|
||||||
|
x1="5.1021"
|
||||||
|
y1="7.10853"
|
||||||
|
x2="8.80138"
|
||||||
|
y2="8.36386"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop offset="0.231" stopColor="#999875" />
|
||||||
|
<stop offset="0.563" stopColor="#9B9977" />
|
||||||
|
<stop offset="0.683" stopColor="#A09F7E" />
|
||||||
|
<stop offset="0.768" stopColor="#A9A889" />
|
||||||
|
<stop offset="0.837" stopColor="#B7B69A" />
|
||||||
|
<stop offset="0.896" stopColor="#C9C7B0" />
|
||||||
|
<stop offset="0.948" stopColor="#DEDDCB" />
|
||||||
|
<stop offset="0.994" stopColor="#F8F6EB" />
|
||||||
|
<stop offset="1" stopColor="#FBF9EF" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint1_linear_2061_4238"
|
||||||
|
x1="6.45855"
|
||||||
|
y1="0.976404"
|
||||||
|
x2="8.09399"
|
||||||
|
y2="11.1888"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stopColor="#48A547" />
|
||||||
|
<stop offset="1" stopColor="#3F9143" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="paint2_linear_2061_4238"
|
||||||
|
x1="4.08293"
|
||||||
|
y1="6.89501"
|
||||||
|
x2="8.47176"
|
||||||
|
y2="5.42519"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<stop stopColor="#41A247" />
|
||||||
|
<stop offset="0.352" stopColor="#4BA74B" />
|
||||||
|
<stop offset="0.956" stopColor="#67B554" />
|
||||||
|
<stop offset="1" stopColor="#69B655" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
28
frontend/src/assets/CustomIcons/MySQLIcon.tsx
Normal file
28
frontend/src/assets/CustomIcons/MySQLIcon.tsx
Normal file
File diff suppressed because one or more lines are too long
22
frontend/src/assets/CustomIcons/NginxIcon.tsx
Normal file
22
frontend/src/assets/CustomIcons/NginxIcon.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
function NginxIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.97775 1H7.00561C7.14837 1.068 7.28743 1.14353 7.42218 1.22629C8.97332 2.11829 10.5245 3.01057 12.0756 3.90314C12.1356 3.93517 12.1846 3.9845 12.2163 4.04472C12.2479 4.10493 12.2607 4.17327 12.253 4.24086C12.2496 6.12186 12.253 8.00243 12.2509 9.88257C12.2307 9.9723 12.1759 10.0504 12.0983 10.0999C10.4489 11.0496 8.79932 11.9987 7.14961 12.9473C7.10963 12.9778 7.06144 12.9956 7.01125 12.9984C6.96106 13.0012 6.91118 12.9889 6.86803 12.9631C5.21661 12.0163 3.56675 11.0677 1.91846 10.1174C1.86489 10.0921 1.82003 10.0515 1.78952 10.0007C1.75901 9.94988 1.74423 9.89119 1.74703 9.832C1.74703 7.95143 1.74703 6.071 1.74703 4.19071C1.74299 4.13178 1.75661 4.07299 1.78616 4.02184C1.8157 3.97069 1.85983 3.92951 1.91289 3.90357C3.46203 3.01271 5.01118 2.12129 6.56032 1.22929C6.69832 1.15043 6.83375 1.06686 6.97775 1Z"
|
||||||
|
fill="#019639"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M3.90007 4.65924C3.90007 6.21039 3.90007 7.76167 3.90007 9.3131C3.89809 9.39901 3.91326 9.48446 3.94468 9.56445C3.9761 9.64444 4.02315 9.71736 4.08307 9.77896C4.19794 9.89243 4.34824 9.96309 4.5089 9.97916C4.66956 9.99522 4.83087 9.95572 4.96593 9.86724C5.05634 9.80581 5.13035 9.72321 5.18152 9.62662C5.23269 9.53003 5.25946 9.4224 5.2595 9.3131C5.2595 8.19024 5.25736 7.06739 5.2595 5.94453C6.28322 7.17024 7.30907 8.39424 8.33707 9.61653C8.4799 9.76122 8.65676 9.86772 8.85145 9.92628C9.04614 9.98484 9.25242 9.99357 9.45136 9.95167C9.59184 9.924 9.71973 9.85198 9.81624 9.74622C9.91275 9.64045 9.97278 9.50652 9.9875 9.3641C9.98979 7.78096 9.98979 6.19796 9.9875 4.6151C9.97275 4.44614 9.8952 4.28884 9.77016 4.17425C9.64512 4.05966 9.48168 3.99609 9.31207 3.99609C9.14247 3.99609 8.97902 4.05966 8.85399 4.17425C8.72895 4.28884 8.6514 4.44614 8.63665 4.6151C8.63665 5.75596 8.62979 6.89553 8.63665 8.03596C7.63122 6.85053 6.63822 5.65481 5.63665 4.4651C5.5046 4.29578 5.32979 4.16474 5.13023 4.08549C4.93067 4.00624 4.71359 3.98165 4.50136 4.01424C4.34059 4.03214 4.19154 4.10704 4.08124 4.22536C3.97093 4.34369 3.90666 4.49761 3.90007 4.65924Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NginxIcon;
|
||||||
40
frontend/src/assets/CustomIcons/PostgreSQLIcon.tsx
Normal file
40
frontend/src/assets/CustomIcons/PostgreSQLIcon.tsx
Normal file
File diff suppressed because one or more lines are too long
60
frontend/src/assets/CustomIcons/RedisIcon.tsx
Normal file
60
frontend/src/assets/CustomIcons/RedisIcon.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
export default function RedisIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="14"
|
||||||
|
height="14"
|
||||||
|
viewBox="0 0 14 14"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<g clipPath="url(#clip0_2061_4282)">
|
||||||
|
<path
|
||||||
|
d="M13.3198 10.158C12.5879 10.5395 8.79654 12.0984 7.98938 12.5192C7.18221 12.94 6.73382 12.936 6.09616 12.6312C5.45855 12.3263 1.42388 10.6966 0.697072 10.3492C0.333858 10.1756 0.142822 10.029 0.142822 9.8906V8.50438C0.142822 8.50438 5.3955 7.3609 6.24348 7.05667C7.09141 6.75244 7.38563 6.74145 8.10723 7.00578C8.82895 7.2702 13.1439 8.0487 13.8571 8.30992L13.8568 9.67653C13.8569 9.81356 13.6923 9.96388 13.3198 10.158Z"
|
||||||
|
fill="#912626"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13.3195 8.77972C12.5877 9.16104 8.79642 10.72 7.98926 11.1407C7.18215 11.5616 6.73376 11.5575 6.09615 11.2527C5.45849 10.9481 1.42397 9.31805 0.697221 8.97086C-0.029529 8.62345 -0.0447433 8.38436 0.66915 8.10482C1.38304 7.82518 5.39544 6.25098 6.24353 5.94675C7.09145 5.64263 7.38561 5.63154 8.10722 5.89597C8.82888 6.16029 12.5975 7.66034 13.3106 7.9215C14.024 8.18298 14.0513 8.39829 13.3195 8.77972Z"
|
||||||
|
fill="#C6302B"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13.3198 7.91483C12.5879 8.29637 8.79654 9.85519 7.98938 10.2762C7.18221 10.6968 6.73382 10.6928 6.09616 10.388C5.4585 10.0833 1.42388 8.45338 0.697072 8.10597C0.333858 7.9324 0.142822 7.78604 0.142822 7.64756V6.26119C0.142822 6.26119 5.3955 5.11776 6.24348 4.81353C7.09141 4.50929 7.38563 4.49826 8.10723 4.76263C8.829 5.02701 13.144 5.80535 13.8571 6.06661L13.8568 7.43338C13.8569 7.57036 13.6923 7.72069 13.3198 7.91483Z"
|
||||||
|
fill="#912626"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13.3195 6.53701C12.5877 6.91844 8.79642 8.47726 7.98926 8.89817C7.18215 9.31892 6.73376 9.3148 6.09615 9.00998C5.45849 8.70537 1.42397 7.07541 0.697221 6.72816C-0.029529 6.38085 -0.0447433 6.14171 0.66915 5.86207C1.38304 5.58258 5.39549 4.00828 6.24353 3.7041C7.09145 3.39992 7.38561 3.38889 8.10722 3.65326C8.82888 3.91758 12.5975 5.41753 13.3106 5.6788C14.024 5.94023 14.0513 6.15558 13.3195 6.53701Z"
|
||||||
|
fill="#C6302B"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13.3198 5.58855C12.5879 5.96998 8.79654 7.5289 7.98938 7.94987C7.18221 8.37062 6.73382 8.36649 6.09616 8.06167C5.4585 7.75701 1.42388 6.12705 0.697072 5.7798C0.333858 5.60607 0.142822 5.45965 0.142822 5.32133V3.9349C0.142822 3.9349 5.3955 2.79153 6.24348 2.48735C7.09141 2.18307 7.38563 2.17214 8.10723 2.43646C8.829 2.70083 13.144 3.47917 13.8571 3.74044L13.8568 5.10715C13.8569 5.24403 13.6923 5.39435 13.3198 5.58855Z"
|
||||||
|
fill="#912626"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13.3195 4.21078C12.5876 4.59221 8.79639 6.15113 7.98923 6.57188C7.18212 6.99263 6.73373 6.98851 6.09612 6.68385C5.45852 6.37903 1.42394 4.74917 0.697248 4.40187C-0.0295558 4.05462 -0.0447165 3.81542 0.669123 3.53583C1.38302 3.2563 5.39546 1.68221 6.2435 1.37792C7.09143 1.07369 7.38559 1.06276 8.1072 1.32714C8.82886 1.59151 12.5975 3.09146 13.3106 3.35272C14.0239 3.61394 14.0513 3.82935 13.3195 4.21078Z"
|
||||||
|
fill="#C6302B"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.67572 2.86218L7.49661 2.9846L7.23267 3.61974L6.80635 2.91099L5.44483 2.78863L6.46076 2.42226L6.15594 1.85986L7.1071 2.23186L8.00378 1.93829L7.76142 2.51981L8.67572 2.86218ZM7.16228 5.94351L4.96172 5.03081L8.11494 4.54679L7.16228 5.94351ZM4.11138 3.21522C5.04219 3.21522 5.79674 3.50772 5.79674 3.86847C5.79674 4.22933 5.04219 4.52177 4.11138 4.52177C3.18058 4.52177 2.42603 4.22927 2.42603 3.86847C2.42603 3.50772 3.18058 3.21522 4.11138 3.21522Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10.0693 3.0357L11.9355 3.77316L10.0709 4.50993L10.0693 3.0357Z"
|
||||||
|
fill="#621B1C"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.00464 3.85234L10.0693 3.03564L10.0709 4.50988L9.86844 4.58906L8.00464 3.85234Z"
|
||||||
|
fill="#9A2928"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_2061_4282">
|
||||||
|
<rect
|
||||||
|
width="13.7143"
|
||||||
|
height="13.7143"
|
||||||
|
fill="white"
|
||||||
|
transform="translate(0.142822 0.143066)"
|
||||||
|
/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
110
frontend/src/assets/CustomIcons/TentIcon.tsx
Normal file
110
frontend/src/assets/CustomIcons/TentIcon.tsx
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
function TentIcon(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M9.75393 9.01964L6.72187 8.90409L6.18079 14.0994C6.18079 14.0994 7.01185 14.0416 8.1118 14.0416C9.21174 14.0416 10.1395 14.1194 10.1395 14.1194L9.75393 9.01964Z"
|
||||||
|
fill="#8A2E08"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M3.65538 9.74625L2.9132 9.59182C2.9132 9.59182 2.73099 10.7684 2.56322 11.4973C2.39545 12.2261 2.11658 13.2116 2.11658 13.2116L3.88093 14.0882C3.88093 14.0882 5.47751 14.2282 5.50529 14.1727C5.53306 14.1171 6.70967 11.3851 6.70967 11.3851L6.98965 10.334L3.65538 9.74625Z"
|
||||||
|
fill="#FF6110"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9.17395 10.3207L12.8715 9.55071L13.0393 9.99847C13.0393 9.99847 13.2826 11.0162 13.4171 11.5673C13.6337 12.4517 13.9126 13.2439 13.9126 13.2439L12.2538 14.2705L10.545 14.2149L9.17395 10.3207Z"
|
||||||
|
fill="#FF6110"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M2.90422 9.15296C2.90422 9.17852 2.92199 9.36406 2.9131 9.49961C2.90422 9.63516 2.87866 9.80182 2.87866 9.80182C2.87866 9.80182 2.97977 9.82404 3.0731 9.88403C3.16642 9.94403 3.35308 10.1729 3.35308 10.1729C3.35308 10.1729 3.71751 10.0385 3.93861 10.1218C4.27859 10.2496 4.42303 10.564 4.42303 10.564C4.42303 10.564 4.77078 10.2407 5.19632 10.3096C5.61185 10.3762 5.77407 10.7684 5.77407 10.7684C5.77407 10.7684 6.08627 10.5162 6.35959 10.5307C6.68291 10.5473 6.80179 10.7851 6.80179 10.7851L7.28621 9.80848L3.68529 9.15407H2.90422V9.15296Z"
|
||||||
|
fill="#AF0D03"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M1.93542 13.6716L2.13097 13.1539C2.13097 13.1539 2.99759 13.5783 3.62534 13.7649C4.25308 13.9516 4.99304 13.9772 4.99304 13.9772C4.99304 13.9772 4.98415 13.6838 4.71194 13.4716C4.43974 13.2594 4.00865 12.9028 4.00865 12.9028L4.59751 12.7061L4.92527 12.575L5.95299 13.7983L5.6219 14.6227C5.6219 14.6227 4.89971 14.716 3.74533 14.4194C2.59095 14.1227 1.93542 13.6716 1.93542 13.6716Z"
|
||||||
|
fill="#C9C9C9"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M9.104 9.63738C9.12067 9.70516 9.11289 10.2407 9.11289 10.2407L9.42732 10.5973C9.42732 10.5973 9.59731 10.3762 9.9884 10.394C10.3795 10.4107 10.5573 10.5896 10.5573 10.5896C10.5573 10.5896 10.795 10.3007 11.1183 10.2418C11.4417 10.1818 11.755 10.3518 11.755 10.3518C11.755 10.3518 11.9761 9.94403 12.2983 9.85071C12.6216 9.75738 13.0394 9.99959 13.0394 9.99959L12.8671 8.95075L9.69953 9.17852L9.104 9.63738Z"
|
||||||
|
fill="#AF0D03"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M13.8782 13.1372L14.0815 13.6549C14.0815 13.6549 13.4615 14.1394 12.6627 14.3605C11.8638 14.5816 10.7528 14.6704 10.7528 14.6704L10.4283 12.8494L11.5238 12.5183L12.1249 12.775C12.1249 12.775 11.5927 13.2227 11.4472 13.4283C11.1705 13.8172 11.2694 14.0638 11.2694 14.0638C11.2694 14.0638 12.1183 13.9872 12.7727 13.7072C13.4282 13.425 13.8782 13.1372 13.8782 13.1372Z"
|
||||||
|
fill="#C9C9C9"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M4.42432 12.8905C4.42432 12.8905 4.80096 13.0594 4.99318 13.1961C5.23094 13.3661 5.46871 13.6205 5.54537 14.0283C5.5987 14.3094 5.62203 14.6227 5.62203 14.6227C5.62203 14.6227 5.88535 14.826 6.4031 13.9605C6.92085 13.095 7.18417 11.8962 7.2275 11.0473C7.26972 10.1985 7.25306 10.0029 7.25306 10.0029L6.48865 11.2595L5.35871 12.2872L4.42432 12.8905Z"
|
||||||
|
fill="#D92F0A"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.25966 10.0074C7.25966 10.0074 7.34855 10.7784 6.30971 11.735C5.66419 12.3295 5.03422 12.7383 4.60314 12.9072C4.45537 12.965 4.32315 12.9417 4.22982 12.9405C3.92539 12.9361 3.98206 12.8839 4.15205 12.7972C4.35204 12.695 4.93312 12.4828 6.02084 11.4806C6.89079 10.6784 6.95079 9.87626 6.95079 9.87626L7.25855 9.7096V10.0074H7.25966Z"
|
||||||
|
fill="#FFFEFF"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M10.7949 14.666C10.7949 14.666 10.4127 14.8015 9.835 14.0205C9.25725 13.2394 9.07948 11.855 9.05393 11.4128C9.02837 10.9706 9.03726 10.1385 9.03726 10.1385L10.0994 11.4717C10.0994 11.4717 11.7471 12.7117 11.7216 12.7205C11.696 12.7294 11.1838 13.0516 10.9916 13.375C10.5994 14.0283 10.7949 14.666 10.7949 14.666Z"
|
||||||
|
fill="#D92F0A"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.97839 9.77071C8.97839 9.77071 8.96284 10.0618 9.0195 10.2829C9.13839 10.7495 9.54836 11.254 10.0817 11.7273C10.7694 12.3384 11.5683 12.7639 11.6271 12.7806C11.6871 12.7972 12.1116 12.815 12.1193 12.7717C12.1227 12.7572 12.1482 12.6939 12.0093 12.5928C11.7238 12.3872 11.0916 12.025 10.5739 11.6162C10.2083 11.3273 9.73947 10.9684 9.33171 10.2285C9.25727 10.094 9.28393 9.75405 9.28393 9.75405L8.97839 9.77071Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M3.32974 7.25306C3.32974 7.25306 2.44534 7.36861 2.41756 7.49416C2.38979 7.62082 2.48756 9.28962 2.48756 9.28962C2.48756 9.28962 2.85976 9.22074 3.04753 9.26185C3.2353 9.30296 3.58861 9.53183 3.58861 9.53183L4.18081 9.16741L4.60745 9.7596C4.60745 9.7596 4.90854 9.60405 5.32519 9.64516C5.74183 9.68627 6.02182 9.96736 6.02182 9.96736L6.60401 9.4885L7.25398 9.99959C7.25398 9.99959 7.55063 9.65405 8.10171 9.64405C8.65279 9.63405 8.98611 10.0396 8.98611 10.0396L9.71385 9.40517L10.4316 9.95625C10.4316 9.95625 10.7127 9.72738 11.0349 9.65516C11.3571 9.58183 11.596 9.70738 11.596 9.70738L12.0537 8.89631L12.5737 9.27074C12.5737 9.27074 12.7404 9.07297 12.9792 9.04186C13.2181 9.01075 13.5092 9.00075 13.5092 9.00075C13.5092 9.00075 13.4881 7.87748 13.4881 7.71082C13.4881 7.54416 13.4259 7.27417 13.3525 7.22195C13.2792 7.16973 12.6248 7.02419 12.6248 7.02419L3.32974 7.25306Z"
|
||||||
|
fill="#D92F0A"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M4.4997 7.73859L3.63197 7.93969L3.58752 9.53294C3.58752 9.53294 3.85195 9.45628 4.11639 9.48405C4.38082 9.51183 4.60636 9.76182 4.60636 9.76182C4.60636 9.76182 4.6008 8.72632 4.60969 8.55188C4.61858 8.37745 4.68636 8.04635 4.72302 7.98302C4.75968 7.91858 4.4997 7.73859 4.4997 7.73859Z"
|
||||||
|
fill="#E1E1E1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.78407 8.07747L5.99189 8.36745C5.99189 8.36745 5.97078 9.10074 5.98967 9.39295C6.00744 9.68516 6.02078 9.96959 6.02078 9.96959C6.02078 9.96959 6.38187 9.84959 6.67519 9.86737C6.96739 9.88515 7.25293 10.0018 7.25293 10.0018L7.24182 8.433L6.78407 8.07747Z"
|
||||||
|
fill="#E1E1E1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.95947 8.40634C8.95947 8.40634 8.98725 9.00075 8.99614 9.30184C9.00503 9.60294 8.98503 10.0429 8.98503 10.0429C8.98503 10.0429 9.41612 9.82293 9.75499 9.79515C10.0927 9.76738 10.4305 9.95959 10.4305 9.95959C10.4305 9.95959 10.4038 9.33851 10.3672 8.88187C10.3416 8.56299 10.2483 8.28745 10.2483 8.28745L9.38056 7.82192L8.95947 8.40634Z"
|
||||||
|
fill="#E1E1E1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M11.5949 9.70961C11.5949 9.70961 11.8827 9.39296 12.1116 9.31963C12.3405 9.2463 12.5727 9.27296 12.5727 9.27296C12.5727 9.27296 12.5593 8.52522 12.5227 8.18635C12.486 7.84859 12.4527 7.65416 12.4527 7.65416L11.3905 7.19974L11.4205 8.03525C11.4205 8.03525 11.5461 8.31412 11.5827 8.79854C11.6183 9.28296 11.5949 9.70961 11.5949 9.70961Z"
|
||||||
|
fill="#E1E1E1"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.04625 4.2021L6.7641 4.77318C6.7641 4.77318 5.5986 5.64758 4.67643 6.23088C3.75425 6.81418 3.22428 7.03639 3.11429 7.08195C2.93874 7.15528 2.65431 7.24194 2.53099 7.32638C2.32655 7.46859 2.4121 7.53526 2.44543 7.54637C2.47877 7.55748 3.49871 8.01412 5.30639 8.28188C7.11408 8.54965 9.57172 8.44076 10.8317 8.19633C12.0905 7.9519 13.3526 7.22305 13.3526 7.22305C13.3526 7.22305 13.2471 7.04639 12.5482 6.74308C11.8483 6.43976 11.2539 6.11311 10.2395 5.4487C9.22508 4.78429 8.98065 4.45764 8.98065 4.45764L8.04625 4.2021Z"
|
||||||
|
fill="#FF6110"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M6.96185 5.00653C6.96185 5.00653 5.55081 6.452 3.81312 7.65305C3.62313 7.78416 3.63202 7.9397 3.63202 7.9397C3.63202 7.9397 3.77202 7.99303 4.11644 8.07303C4.46642 8.15414 4.66752 8.17414 4.66752 8.17414C4.66752 8.17414 4.8264 7.99192 5.16528 7.65305C5.77191 7.04642 6.14856 6.56533 6.62298 5.95092C6.9374 5.54316 7.31183 5.0543 7.31183 5.0543L6.96185 5.00653Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.5684 5.19318C7.5684 5.19318 7.0551 6.382 6.81067 6.89531C6.69512 7.13641 6.43735 7.58305 6.20403 7.95636C6.00071 8.2819 5.99182 8.36856 5.99182 8.36856C5.99182 8.36856 6.44846 8.43412 6.66956 8.43412C6.89066 8.43412 7.24064 8.43189 7.24064 8.43189C7.24064 8.43189 7.41619 7.90859 7.60285 6.85975C7.71173 6.24979 7.87061 5.18095 7.87061 5.18095L7.5684 5.19318Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.27954 5.23983C8.27954 5.23983 8.39509 6.38532 8.52397 6.98862C8.69841 7.80525 8.95839 8.40522 8.95839 8.40522C8.95839 8.40522 9.39837 8.38744 9.6428 8.36411C9.88723 8.34077 10.2461 8.28633 10.2461 8.28633C10.2461 8.28633 9.82613 7.6397 9.42059 6.98862C9.15283 6.55754 8.65063 5.55425 8.56953 5.16983C8.50064 4.83874 8.27954 5.23983 8.27954 5.23983Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.90845 5.02984C8.90845 5.06428 9.27732 5.85091 10.1906 6.83752C10.925 7.63081 11.415 8.03857 11.415 8.03857C11.415 8.03857 11.8338 7.90969 12.0216 7.8408C12.2427 7.75969 12.4527 7.65414 12.4527 7.65414C12.4527 7.65414 11.4616 6.9664 10.8783 6.48865C10.295 6.0109 9.49064 5.34649 9.26954 5.04317C9.04844 4.73874 8.90845 5.02984 8.90845 5.02984Z"
|
||||||
|
fill="white"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.03411 3.40993C7.78856 3.4277 7.70746 3.84102 7.57969 3.9699C7.45191 4.09767 6.76306 4.7743 6.76306 4.7743C6.76306 4.7743 6.88528 5.41316 8.09855 5.40093C9.20849 5.38871 9.41959 4.86318 9.41959 4.86318C9.41959 4.86318 8.71074 4.10989 8.54741 3.92323C8.38409 3.73547 8.36075 3.3866 8.03411 3.40993Z"
|
||||||
|
fill="#D92F0A"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M8.07516 2.86996C8.07516 2.86996 8.28515 2.8033 8.58402 2.83774C8.88845 2.8733 9.09066 2.97218 9.40731 2.96551C9.89173 2.95663 10.2817 2.72886 10.4217 2.59998C10.5617 2.4711 10.7406 2.26222 10.6472 2.19222C10.5539 2.12223 10.1562 2.22778 9.71174 2.05223C9.31954 1.89779 9.12288 1.49448 8.56624 1.43004C8.08738 1.3756 7.94739 1.57225 7.94739 1.57225L8.07516 2.86996Z"
|
||||||
|
fill="#FF6110"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M7.88843 1.43226V3.6177L8.23841 3.52437L8.20397 1.43226H7.88843Z"
|
||||||
|
fill="#D92F0A"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TentIcon;
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
.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(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
.button-selected-text {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-value {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.time-selection-target {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.selected-value {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
|
import './TimePreference.styles.scss';
|
||||||
|
|
||||||
import { DownOutlined } from '@ant-design/icons';
|
import { DownOutlined } from '@ant-design/icons';
|
||||||
import { Button, Dropdown } from 'antd';
|
import { Button, Dropdown, Typography } from 'antd';
|
||||||
import TimeItems, {
|
import TimeItems, {
|
||||||
timePreferance,
|
timePreferance,
|
||||||
timePreferenceType,
|
timePreferenceType,
|
||||||
} from 'container/NewWidget/RightContainer/timeItems';
|
} from 'container/NewWidget/RightContainer/timeItems';
|
||||||
|
import { Globe } from 'lucide-react';
|
||||||
import { Dispatch, SetStateAction, useCallback, useMemo } from 'react';
|
import { Dispatch, SetStateAction, useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import { menuItems } from './config';
|
import { menuItems } from './config';
|
||||||
import { TextContainer } from './styles';
|
|
||||||
|
|
||||||
function TimePreference({
|
function TimePreference({
|
||||||
setSelectedTime,
|
setSelectedTime,
|
||||||
@@ -32,13 +34,22 @@ function TimePreference({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TextContainer noButtonMargin>
|
<Dropdown
|
||||||
<Dropdown menu={menu}>
|
menu={menu}
|
||||||
<Button>
|
rootClassName="time-selection-menu"
|
||||||
{selectedTime.name} <DownOutlined />
|
className="time-selection-target"
|
||||||
</Button>
|
trigger={['click']}
|
||||||
</Dropdown>
|
>
|
||||||
</TextContainer>
|
<Button>
|
||||||
|
<div className="button-selected-text">
|
||||||
|
<Globe size={14} />
|
||||||
|
<Typography.Text className="selected-value">
|
||||||
|
{selectedTime.name}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<DownOutlined />
|
||||||
|
</Button>
|
||||||
|
</Dropdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -267,6 +267,21 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
|
|||||||
const isTracesView = (): boolean =>
|
const isTracesView = (): boolean =>
|
||||||
routeKey === 'TRACES_EXPLORER' || routeKey === 'TRACES_SAVE_VIEWS';
|
routeKey === 'TRACES_EXPLORER' || routeKey === 'TRACES_SAVE_VIEWS';
|
||||||
|
|
||||||
|
const isDashboardListView = (): boolean => routeKey === 'ALL_DASHBOARD';
|
||||||
|
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_-]+$/;
|
||||||
|
return regex.test(pathname);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isDashboardWidgetView = (): boolean => {
|
||||||
|
const regex = /^\/dashboard\/[a-zA-Z0-9_-]+\/new$/;
|
||||||
|
return regex.test(pathname);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDarkMode) {
|
if (isDarkMode) {
|
||||||
document.body.classList.remove('lightMode');
|
document.body.classList.remove('lightMode');
|
||||||
@@ -331,7 +346,14 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
|
|||||||
<LayoutContent>
|
<LayoutContent>
|
||||||
<ChildrenContainer
|
<ChildrenContainer
|
||||||
style={{
|
style={{
|
||||||
margin: isLogsView() || isTracesView() ? 0 : ' 0 1rem',
|
margin:
|
||||||
|
isLogsView() ||
|
||||||
|
isTracesView() ||
|
||||||
|
isDashboardView() ||
|
||||||
|
isDashboardWidgetView() ||
|
||||||
|
isDashboardListView()
|
||||||
|
? 0
|
||||||
|
: ' 0 1rem',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isToDisplayLayout && !renderFullScreen && <TopNav />}
|
{isToDisplayLayout && !renderFullScreen && <TopNav />}
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ export const Layout = styled(LayoutComponent)`
|
|||||||
export const LayoutContent = styled(LayoutComponent.Content)`
|
export const LayoutContent = styled(LayoutComponent.Content)`
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0.1rem;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ChildrenContainer = styled.div`
|
export const ChildrenContainer = styled.div`
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.dashboard-empty-state {
|
||||||
|
.dashboard-content {
|
||||||
|
.heading {
|
||||||
|
.icons {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.welcome-info {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
.actions-1 {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.configure-button {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-configure {
|
||||||
|
.actions-configure-text {
|
||||||
|
.icons {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.configure {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.configure-info {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-panel-btn {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions-add-panel {
|
||||||
|
.actions-panel-text {
|
||||||
|
.icons {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-info {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/* eslint-disable jsx-a11y/img-redundant-alt */
|
||||||
|
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 { 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<AppState, AppReducer>((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 (
|
||||||
|
<section className="dashboard-empty-state">
|
||||||
|
<div className="dashboard-content">
|
||||||
|
<section className="heading">
|
||||||
|
<img
|
||||||
|
src="/Icons/dashboard_emoji.svg"
|
||||||
|
alt="header-image"
|
||||||
|
style={{ height: '32px', width: '32px' }}
|
||||||
|
/>
|
||||||
|
<Typography.Text className="welcome">
|
||||||
|
Welcome to your new dashboard
|
||||||
|
</Typography.Text>
|
||||||
|
<Typography.Text className="welcome-info">
|
||||||
|
Follow the steps to populate it with data and share with your teammates
|
||||||
|
</Typography.Text>
|
||||||
|
</section>
|
||||||
|
<section className="actions">
|
||||||
|
<div className="actions-1">
|
||||||
|
<div className="actions-configure">
|
||||||
|
<div className="actions-configure-text">
|
||||||
|
<img
|
||||||
|
src="/Icons/tools.svg"
|
||||||
|
alt="header-image"
|
||||||
|
style={{ height: '14px', width: '14px' }}
|
||||||
|
/>
|
||||||
|
<Typography.Text className="configure">
|
||||||
|
Configure your new dashboard
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<Typography.Text className="configure-info">
|
||||||
|
Give it a name, add description, tags and variables
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<SettingsDrawer drawerTitle="Dashboard Configuration" />
|
||||||
|
</div>
|
||||||
|
<div className="actions-1">
|
||||||
|
<div className="actions-add-panel">
|
||||||
|
<div className="actions-panel-text">
|
||||||
|
<img
|
||||||
|
src="/Icons/landscape.svg"
|
||||||
|
alt="header-image"
|
||||||
|
style={{ height: '14px', width: '14px' }}
|
||||||
|
/>
|
||||||
|
<Typography.Text className="panel">Add panels</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<Typography.Text className="panel-info">
|
||||||
|
Add panels to visualize your data
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
{!isDashboardLocked && addPanelPermission && (
|
||||||
|
<Button
|
||||||
|
className="add-panel-btn"
|
||||||
|
onClick={onEmptyWidgetHandler}
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
type="primary"
|
||||||
|
data-testid="add-panel"
|
||||||
|
>
|
||||||
|
New Panel
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -6,12 +6,85 @@
|
|||||||
border: none !important;
|
border: none !important;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|
||||||
|
.row-panel {
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(18, 19, 23, 0.4);
|
||||||
|
padding: 8px;
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.settings-icon {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-icon {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grip {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.widget-graph-container {
|
.widget-graph-container {
|
||||||
&.graph {
|
&.graph {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
width: -webkit-fill-available;
|
||||||
|
|
||||||
|
.locked-text {
|
||||||
|
align-self: flex-end;
|
||||||
|
width: 80px;
|
||||||
|
border: none;
|
||||||
|
cursor: default;
|
||||||
|
display: inline-flex;
|
||||||
|
padding: 4px 6px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: 4px 0px 0px 0px;
|
||||||
|
background: var(--bg-sakura-500);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
color: var(--bg-ink-500);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
letter-spacing: 0.48px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
|
||||||
|
.ant-btn-icon {
|
||||||
|
margin-inline-end: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.locked-bar {
|
||||||
|
background: var(--bg-sakura-500);
|
||||||
|
height: 6px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget-graph-container {
|
.widget-graph-container {
|
||||||
@@ -32,18 +105,257 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.row-settings {
|
||||||
|
.ant-popover-inner {
|
||||||
|
width: 191px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
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: 0px;
|
||||||
|
|
||||||
|
.menu-content {
|
||||||
|
.section-1 {
|
||||||
|
.rename-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: normal;
|
||||||
|
letter-spacing: 0.14px;
|
||||||
|
padding: 14px;
|
||||||
|
width: 100%;
|
||||||
|
.ant-btn-icon {
|
||||||
|
margin-inline-end: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-2 {
|
||||||
|
border-top: 1px solid #1d212d;
|
||||||
|
.remove-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
gap: 6px;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: normal;
|
||||||
|
letter-spacing: 0.14px;
|
||||||
|
padding: 10px 18px 12px 14px;
|
||||||
|
color: var(--bg-cherry-400);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rename-section {
|
||||||
|
.ant-modal-content {
|
||||||
|
width: 384px;
|
||||||
|
height: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--bg-slate-500);
|
||||||
|
background: var(--Ink-400, #121317);
|
||||||
|
box-shadow: 0px -4px 16px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
margin-bottom: 0px;
|
||||||
|
|
||||||
|
.ant-modal-title {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-body {
|
||||||
|
padding: 12px 16px 16px 16px;
|
||||||
|
|
||||||
|
.typography {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-item {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
|
||||||
|
.ant-input {
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btns {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.ok-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 24px; /* 200% */
|
||||||
|
display: flex;
|
||||||
|
width: 140px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--bg-robin-500);
|
||||||
|
|
||||||
|
.ant-btn-icon {
|
||||||
|
margin-inline-end: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 24px; /* 200% */
|
||||||
|
display: flex;
|
||||||
|
padding: 4px 8px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--bg-slate-500);
|
||||||
|
|
||||||
|
.ant-btn-icon {
|
||||||
|
margin-inline-end: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.lightMode {
|
.lightMode {
|
||||||
.fullscreen-grid-container {
|
.fullscreen-grid-container {
|
||||||
background-color: rgb(250, 250, 250);
|
.react-grid-layout {
|
||||||
|
.row-panel {
|
||||||
|
background: var(--bg-vanilla-200);
|
||||||
|
|
||||||
|
.settings-icon {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-icon {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget-full-view {
|
.widget-full-view {
|
||||||
.ant-modal-content {
|
.ant-modal-content {
|
||||||
background-color: var(--bg-vanilla-100);
|
background-color: var(--bg-vanilla-100);
|
||||||
}
|
|
||||||
|
|
||||||
.ant-modal-header {
|
.ant-modal-header {
|
||||||
background-color: var(--bg-vanilla-100);
|
background-color: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-settings {
|
||||||
|
.ant-popover-inner {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.menu-content {
|
||||||
|
.section-1 {
|
||||||
|
.rename-btn {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-2 {
|
||||||
|
border-top: 1px solid var(--bg-vanilla-300);
|
||||||
|
.remove-section {
|
||||||
|
color: var(--bg-cherry-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rename-section {
|
||||||
|
.ant-modal-content {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-modal-title {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-body {
|
||||||
|
.typography {
|
||||||
|
color: var(--bg-ink-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-item {
|
||||||
|
.action-btns {
|
||||||
|
.cancel-btn {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import './GridCardLayout.styles.scss';
|
import './GridCardLayout.styles.scss';
|
||||||
|
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { Color } from '@signozhq/design-tokens';
|
||||||
import { Flex, Form, Input, Modal, Tooltip, Typography } from 'antd';
|
import { Button, Form, Input, Modal, Typography } from 'antd';
|
||||||
import { useForm } from 'antd/es/form/Form';
|
import { useForm } from 'antd/es/form/Form';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn';
|
|
||||||
import { dashboardHelpMessage } from 'components/facingIssueBtn/util';
|
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
import { PANEL_GROUP_TYPES, PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_GROUP_TYPES, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { themeColors } from 'constants/theme';
|
import { themeColors } from 'constants/theme';
|
||||||
|
import { DEFAULT_ROW_NAME } from 'container/NewDashboard/DashboardDescription/utils';
|
||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||||
import useComponentPermission from 'hooks/useComponentPermission';
|
import useComponentPermission from 'hooks/useComponentPermission';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
@@ -19,19 +18,18 @@ import history from 'lib/history';
|
|||||||
import { defaultTo } from 'lodash-es';
|
import { defaultTo } from 'lodash-es';
|
||||||
import isEqual from 'lodash-es/isEqual';
|
import isEqual from 'lodash-es/isEqual';
|
||||||
import {
|
import {
|
||||||
FullscreenIcon,
|
Check,
|
||||||
|
ChevronDown,
|
||||||
|
ChevronUp,
|
||||||
GripVertical,
|
GripVertical,
|
||||||
MoveDown,
|
LockKeyhole,
|
||||||
MoveUp,
|
X,
|
||||||
Settings,
|
|
||||||
Trash2,
|
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import { sortLayout } from 'providers/Dashboard/util';
|
import { sortLayout } from 'providers/Dashboard/util';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useMemo, 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 { ItemCallback, Layout } from 'react-grid-layout';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { UpdateTimeInterval } from 'store/actions';
|
import { UpdateTimeInterval } from 'store/actions';
|
||||||
@@ -40,21 +38,21 @@ import { Dashboard, Widgets } from 'types/api/dashboard/getAll';
|
|||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
import { ROLES, USER_ROLES } from 'types/roles';
|
import { ROLES, USER_ROLES } from 'types/roles';
|
||||||
import { ComponentTypes } from 'utils/permission';
|
import { ComponentTypes } from 'utils/permission';
|
||||||
import { v4 as uuid } from 'uuid';
|
|
||||||
|
|
||||||
import { EditMenuAction, ViewMenuAction } from './config';
|
import { EditMenuAction, ViewMenuAction } from './config';
|
||||||
|
import DashboardEmptyState from './DashboardEmptyState/DashboardEmptyState';
|
||||||
import GridCard from './GridCard';
|
import GridCard from './GridCard';
|
||||||
import {
|
import { Card, CardContainer, ReactGridLayout } from './styles';
|
||||||
Button,
|
|
||||||
ButtonContainer,
|
|
||||||
Card,
|
|
||||||
CardContainer,
|
|
||||||
ReactGridLayout,
|
|
||||||
} from './styles';
|
|
||||||
import { GraphLayoutProps } from './types';
|
|
||||||
import { removeUndefinedValuesFromLayout } from './utils';
|
import { removeUndefinedValuesFromLayout } from './utils';
|
||||||
|
import { WidgetRowHeader } from './WidgetRow';
|
||||||
|
|
||||||
function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
interface GraphLayoutProps {
|
||||||
|
handle: FullScreenHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
|
function GraphLayout(props: GraphLayoutProps): JSX.Element {
|
||||||
|
const { handle } = props;
|
||||||
const {
|
const {
|
||||||
selectedDashboard,
|
selectedDashboard,
|
||||||
layouts,
|
layouts,
|
||||||
@@ -65,14 +63,11 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
isDashboardLocked,
|
isDashboardLocked,
|
||||||
} = useDashboard();
|
} = useDashboard();
|
||||||
const { data } = selectedDashboard || {};
|
const { data } = selectedDashboard || {};
|
||||||
const handle = useFullScreenHandle();
|
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const { widgets, variables } = data || {};
|
const { widgets, variables } = data || {};
|
||||||
|
|
||||||
const { t } = useTranslation(['dashboard']);
|
|
||||||
|
|
||||||
const { featureResponse, role, user } = useSelector<AppState, AppReducer>(
|
const { featureResponse, role, user } = useSelector<AppState, AppReducer>(
|
||||||
(state) => state.app,
|
(state) => state.app,
|
||||||
);
|
);
|
||||||
@@ -122,6 +117,11 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
userRole,
|
userRole,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [deleteWidget, editWidget] = useComponentPermission(
|
||||||
|
['delete_widget', 'edit_widget'],
|
||||||
|
role,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDashboardLayout(sortLayout(layouts));
|
setDashboardLayout(sortLayout(layouts));
|
||||||
}, [layouts]);
|
}, [layouts]);
|
||||||
@@ -206,80 +206,6 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [dashboardLayout]);
|
}, [dashboardLayout]);
|
||||||
|
|
||||||
function handleAddRow(): void {
|
|
||||||
if (!selectedDashboard) return;
|
|
||||||
const id = uuid();
|
|
||||||
|
|
||||||
const newRowWidgetMap: { widgets: Layout[]; collapsed: boolean } = {
|
|
||||||
widgets: [],
|
|
||||||
collapsed: false,
|
|
||||||
};
|
|
||||||
const currentRowIdx = 0;
|
|
||||||
for (let j = currentRowIdx; j < dashboardLayout.length; j++) {
|
|
||||||
if (!currentPanelMap[dashboardLayout[j].i]) {
|
|
||||||
newRowWidgetMap.widgets.push(dashboardLayout[j]);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedDashboard: Dashboard = {
|
|
||||||
...selectedDashboard,
|
|
||||||
data: {
|
|
||||||
...selectedDashboard.data,
|
|
||||||
layout: [
|
|
||||||
{
|
|
||||||
i: id,
|
|
||||||
w: 12,
|
|
||||||
minW: 12,
|
|
||||||
minH: 1,
|
|
||||||
maxH: 1,
|
|
||||||
x: 0,
|
|
||||||
h: 1,
|
|
||||||
y: 0,
|
|
||||||
},
|
|
||||||
...dashboardLayout.filter((e) => e.i !== PANEL_TYPES.EMPTY_WIDGET),
|
|
||||||
],
|
|
||||||
panelMap: { ...currentPanelMap, [id]: newRowWidgetMap },
|
|
||||||
widgets: [
|
|
||||||
...(selectedDashboard.data.widgets || []),
|
|
||||||
{
|
|
||||||
id,
|
|
||||||
title: 'Sample Row',
|
|
||||||
description: '',
|
|
||||||
panelTypes: PANEL_GROUP_TYPES.ROW,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
uuid: selectedDashboard.uuid,
|
|
||||||
};
|
|
||||||
|
|
||||||
updateDashboardMutation.mutate(updatedDashboard, {
|
|
||||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
|
||||||
onSuccess: (updatedDashboard) => {
|
|
||||||
if (updatedDashboard.payload) {
|
|
||||||
if (updatedDashboard.payload.data.layout)
|
|
||||||
setLayouts(sortLayout(updatedDashboard.payload.data.layout));
|
|
||||||
setSelectedDashboard(updatedDashboard.payload);
|
|
||||||
setPanelMap(updatedDashboard.payload?.data?.panelMap || {});
|
|
||||||
}
|
|
||||||
|
|
||||||
featureResponse.refetch();
|
|
||||||
},
|
|
||||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
|
||||||
onError: () => {
|
|
||||||
notifications.error({
|
|
||||||
message: SOMETHING_WENT_WRONG,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleRowSettingsClick = (id: string): void => {
|
|
||||||
setIsSettingsModalOpen(true);
|
|
||||||
setCurrentSelectRowId(id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSettingsModalSubmit = (): void => {
|
const onSettingsModalSubmit = (): void => {
|
||||||
const newTitle = form.getFieldValue('title');
|
const newTitle = form.getFieldValue('title');
|
||||||
if (!selectedDashboard) return;
|
if (!selectedDashboard) return;
|
||||||
@@ -330,6 +256,15 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!currentSelectRowId) return;
|
||||||
|
form.setFieldValue(
|
||||||
|
'title',
|
||||||
|
(widgets?.find((widget) => widget.id === currentSelectRowId)
|
||||||
|
?.title as string) || DEFAULT_ROW_NAME,
|
||||||
|
);
|
||||||
|
}, [currentSelectRowId, form, widgets]);
|
||||||
|
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
const handleRowCollapse = (id: string): void => {
|
const handleRowCollapse = (id: string): void => {
|
||||||
if (!selectedDashboard) return;
|
if (!selectedDashboard) return;
|
||||||
@@ -483,192 +418,187 @@ function GraphLayout({ onAddPanelHandler }: GraphLayoutProps): JSX.Element {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
return (
|
const isDashboardEmpty = useMemo(
|
||||||
<>
|
() =>
|
||||||
<Flex justify="flex-end" gap={8} align="center">
|
selectedDashboard?.data.layout
|
||||||
<FacingIssueBtn
|
? selectedDashboard?.data.layout?.length === 0
|
||||||
attributes={{
|
: true,
|
||||||
uuid: selectedDashboard?.uuid,
|
[selectedDashboard],
|
||||||
title: data?.title,
|
);
|
||||||
screen: 'Dashboard Details',
|
return isDashboardEmpty ? (
|
||||||
}}
|
<DashboardEmptyState />
|
||||||
eventName="Dashboard: Facing Issues in dashboard"
|
) : (
|
||||||
buttonText="Need help with this dashboard?"
|
<FullScreen handle={handle} className="fullscreen-grid-container">
|
||||||
message={dashboardHelpMessage(data, selectedDashboard)}
|
<ReactGridLayout
|
||||||
onHoverText="Click here to get help for this dashboard"
|
cols={12}
|
||||||
/>
|
rowHeight={45}
|
||||||
<ButtonContainer>
|
autoSize
|
||||||
<Tooltip title="Open in Full Screen">
|
width={100}
|
||||||
<Button
|
useCSSTransforms
|
||||||
className="periscope-btn"
|
isDraggable={!isDashboardLocked && addPanelPermission}
|
||||||
loading={updateDashboardMutation.isLoading}
|
isDroppable={!isDashboardLocked && addPanelPermission}
|
||||||
onClick={handle.enter}
|
isResizable={!isDashboardLocked && addPanelPermission}
|
||||||
icon={<FullscreenIcon size={16} />}
|
allowOverlap={false}
|
||||||
disabled={updateDashboardMutation.isLoading}
|
onLayoutChange={handleLayoutChange}
|
||||||
/>
|
onDragStop={handleDragStop}
|
||||||
</Tooltip>
|
draggableHandle=".drag-handle"
|
||||||
|
layout={dashboardLayout}
|
||||||
{!isDashboardLocked && addPanelPermission && (
|
style={{ backgroundColor: isDarkMode ? '' : themeColors.snowWhite }}
|
||||||
<Button
|
>
|
||||||
className="periscope-btn"
|
{dashboardLayout.map((layout) => {
|
||||||
onClick={onAddPanelHandler}
|
const { i: id } = layout;
|
||||||
icon={<PlusOutlined />}
|
const currentWidget = (widgets || [])?.find((e) => e.id === id);
|
||||||
data-testid="add-panel"
|
|
||||||
>
|
|
||||||
{t('dashboard:add_panel')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{!isDashboardLocked && addPanelPermission && (
|
|
||||||
<Button
|
|
||||||
className="periscope-btn"
|
|
||||||
onClick={(): void => handleAddRow()}
|
|
||||||
icon={<PlusOutlined />}
|
|
||||||
data-testid="add-row"
|
|
||||||
>
|
|
||||||
{t('dashboard:add_row')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</ButtonContainer>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<FullScreen handle={handle} className="fullscreen-grid-container">
|
|
||||||
<ReactGridLayout
|
|
||||||
cols={12}
|
|
||||||
rowHeight={45}
|
|
||||||
autoSize
|
|
||||||
width={100}
|
|
||||||
useCSSTransforms
|
|
||||||
isDraggable={!isDashboardLocked && addPanelPermission}
|
|
||||||
isDroppable={!isDashboardLocked && addPanelPermission}
|
|
||||||
isResizable={!isDashboardLocked && addPanelPermission}
|
|
||||||
allowOverlap={false}
|
|
||||||
onLayoutChange={handleLayoutChange}
|
|
||||||
onDragStop={handleDragStop}
|
|
||||||
draggableHandle=".drag-handle"
|
|
||||||
layout={dashboardLayout}
|
|
||||||
style={{ backgroundColor: isDarkMode ? '' : themeColors.snowWhite }}
|
|
||||||
>
|
|
||||||
{dashboardLayout.map((layout) => {
|
|
||||||
const { i: id } = layout;
|
|
||||||
const currentWidget = (widgets || [])?.find((e) => e.id === id);
|
|
||||||
|
|
||||||
if (currentWidget?.panelTypes === PANEL_GROUP_TYPES.ROW) {
|
|
||||||
const rowWidgetProperties = currentPanelMap[id] || {};
|
|
||||||
return (
|
|
||||||
<CardContainer
|
|
||||||
className="row-card"
|
|
||||||
isDarkMode={isDarkMode}
|
|
||||||
key={id}
|
|
||||||
data-grid={JSON.stringify(currentWidget)}
|
|
||||||
>
|
|
||||||
<div className={cx('row-panel')}>
|
|
||||||
<div style={{ display: 'flex', gap: '10px', alignItems: 'center' }}>
|
|
||||||
<Button
|
|
||||||
disabled={updateDashboardMutation.isLoading}
|
|
||||||
icon={
|
|
||||||
rowWidgetProperties.collapsed ? (
|
|
||||||
<MoveDown size={14} />
|
|
||||||
) : (
|
|
||||||
<MoveUp size={14} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
type="text"
|
|
||||||
onClick={(): void => handleRowCollapse(id)}
|
|
||||||
/>
|
|
||||||
<Typography.Text>{currentWidget.title}</Typography.Text>
|
|
||||||
<Button
|
|
||||||
icon={<Settings size={14} />}
|
|
||||||
type="text"
|
|
||||||
onClick={(): void => handleRowSettingsClick(id)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{rowWidgetProperties.collapsed && (
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<GripVertical size={14} />}
|
|
||||||
className="drag-handle"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!rowWidgetProperties.collapsed && (
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<Trash2 size={14} />}
|
|
||||||
onClick={(): void => {
|
|
||||||
setIsDeleteModalOpen(true);
|
|
||||||
setCurrentSelectRowId(id);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</CardContainer>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (currentWidget?.panelTypes === PANEL_GROUP_TYPES.ROW) {
|
||||||
|
const rowWidgetProperties = currentPanelMap[id] || {};
|
||||||
return (
|
return (
|
||||||
<CardContainer
|
<CardContainer
|
||||||
className={isDashboardLocked ? '' : 'enable-resize'}
|
className="row-card"
|
||||||
isDarkMode={isDarkMode}
|
isDarkMode={isDarkMode}
|
||||||
key={id}
|
key={id}
|
||||||
data-grid={JSON.stringify(currentWidget)}
|
data-grid={JSON.stringify(currentWidget)}
|
||||||
>
|
>
|
||||||
<Card
|
<div className={cx('row-panel')}>
|
||||||
className="grid-item"
|
<div style={{ display: 'flex', gap: '6px', alignItems: 'center' }}>
|
||||||
$panelType={currentWidget?.panelTypes || PANEL_TYPES.TIME_SERIES}
|
{rowWidgetProperties.collapsed && (
|
||||||
>
|
<GripVertical
|
||||||
<GridCard
|
size={14}
|
||||||
widget={(currentWidget as Widgets) || ({ id, query: {} } as Widgets)}
|
className="drag-handle"
|
||||||
headerMenuList={widgetActions}
|
color={isDarkMode ? Color.BG_VANILLA_100 : Color.BG_INK_300}
|
||||||
variables={variables}
|
cursor="move"
|
||||||
version={selectedDashboard?.data?.version}
|
/>
|
||||||
onDragSelect={onDragSelect}
|
)}
|
||||||
|
<Typography.Text className="section-title">
|
||||||
|
{currentWidget.title}
|
||||||
|
</Typography.Text>
|
||||||
|
{rowWidgetProperties.collapsed ? (
|
||||||
|
<ChevronDown
|
||||||
|
size={14}
|
||||||
|
onClick={(): void => handleRowCollapse(id)}
|
||||||
|
className="row-icon"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<ChevronUp
|
||||||
|
size={14}
|
||||||
|
onClick={(): void => handleRowCollapse(id)}
|
||||||
|
className="row-icon"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<WidgetRowHeader
|
||||||
|
id={id}
|
||||||
|
rowWidgetProperties={rowWidgetProperties}
|
||||||
|
setCurrentSelectRowId={setCurrentSelectRowId}
|
||||||
|
setIsDeleteModalOpen={setIsDeleteModalOpen}
|
||||||
|
setIsSettingsModalOpen={setIsSettingsModalOpen}
|
||||||
|
editWidget={editWidget}
|
||||||
|
deleteWidget={deleteWidget}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</div>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
</ReactGridLayout>
|
|
||||||
<Modal
|
return (
|
||||||
open={isSettingsModalOpen}
|
<CardContainer
|
||||||
title="Row Options"
|
className={isDashboardLocked ? '' : 'enable-resize'}
|
||||||
destroyOnClose
|
isDarkMode={isDarkMode}
|
||||||
footer={null}
|
key={id}
|
||||||
onCancel={(): void => {
|
data-grid={JSON.stringify(currentWidget)}
|
||||||
setIsSettingsModalOpen(false);
|
>
|
||||||
setCurrentSelectRowId(null);
|
<Card
|
||||||
}}
|
className="grid-item"
|
||||||
>
|
isDarkMode={isDarkMode}
|
||||||
<Form form={form} onFinish={onSettingsModalSubmit} requiredMark>
|
$panelType={currentWidget?.panelTypes || PANEL_TYPES.TIME_SERIES}
|
||||||
<Form.Item required name={['title']}>
|
>
|
||||||
<Input
|
<GridCard
|
||||||
placeholder="Enter row name here..."
|
widget={(currentWidget as Widgets) || ({ id, query: {} } as Widgets)}
|
||||||
defaultValue={defaultTo(
|
headerMenuList={widgetActions}
|
||||||
widgets?.find((widget) => widget.id === currentSelectRowId)
|
variables={variables}
|
||||||
?.title as string,
|
version={selectedDashboard?.data?.version}
|
||||||
'Sample Title',
|
onDragSelect={onDragSelect}
|
||||||
)}
|
/>
|
||||||
/>
|
</Card>
|
||||||
</Form.Item>
|
</CardContainer>
|
||||||
<Form.Item>
|
);
|
||||||
<Button type="primary" htmlType="submit">
|
})}
|
||||||
|
</ReactGridLayout>
|
||||||
|
{isDashboardLocked && (
|
||||||
|
<div className="footer">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<LockKeyhole size={14} />}
|
||||||
|
className="locked-text"
|
||||||
|
>
|
||||||
|
Locked
|
||||||
|
</Button>
|
||||||
|
<div className="locked-bar" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Modal
|
||||||
|
open={isSettingsModalOpen}
|
||||||
|
title="Rename Section"
|
||||||
|
rootClassName="rename-section"
|
||||||
|
destroyOnClose
|
||||||
|
footer={null}
|
||||||
|
onCancel={(): void => {
|
||||||
|
setIsSettingsModalOpen(false);
|
||||||
|
setCurrentSelectRowId(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Form form={form} onFinish={onSettingsModalSubmit} requiredMark>
|
||||||
|
<Typography.Text className="typography">
|
||||||
|
Enter section name
|
||||||
|
</Typography.Text>
|
||||||
|
<Form.Item required name={['title']}>
|
||||||
|
<Input
|
||||||
|
placeholder="Enter row name here..."
|
||||||
|
defaultValue={defaultTo(
|
||||||
|
widgets?.find((widget) => widget.id === currentSelectRowId)
|
||||||
|
?.title as string,
|
||||||
|
'Sample Title',
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<div className="action-btns">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
className="ok-btn"
|
||||||
|
icon={<Check size={14} />}
|
||||||
|
disabled={updateDashboardMutation.isLoading}
|
||||||
|
>
|
||||||
Apply Changes
|
Apply Changes
|
||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
<Button
|
||||||
</Form>
|
type="text"
|
||||||
</Modal>
|
className="cancel-btn"
|
||||||
<Modal
|
icon={<X size={14} />}
|
||||||
open={isDeleteModalOpen}
|
onClick={(): void => {
|
||||||
title="Delete Row"
|
setIsSettingsModalOpen(false);
|
||||||
destroyOnClose
|
setCurrentSelectRowId(null);
|
||||||
onCancel={(): void => {
|
}}
|
||||||
setIsDeleteModalOpen(false);
|
>
|
||||||
setCurrentSelectRowId(null);
|
Cancel
|
||||||
}}
|
</Button>
|
||||||
onOk={(): void => handleRowDelete()}
|
</div>
|
||||||
>
|
</Form.Item>
|
||||||
<Typography.Text>Are you sure you want to delete this row</Typography.Text>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
</FullScreen>
|
<Modal
|
||||||
</>
|
open={isDeleteModalOpen}
|
||||||
|
title="Delete Row"
|
||||||
|
destroyOnClose
|
||||||
|
onCancel={(): void => {
|
||||||
|
setIsDeleteModalOpen(false);
|
||||||
|
setCurrentSelectRowId(null);
|
||||||
|
}}
|
||||||
|
onOk={(): void => handleRowDelete()}
|
||||||
|
>
|
||||||
|
<Typography.Text>Are you sure you want to delete this row</Typography.Text>
|
||||||
|
</Modal>
|
||||||
|
</FullScreen>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
82
frontend/src/container/GridCardLayout/WidgetRow.tsx
Normal file
82
frontend/src/container/GridCardLayout/WidgetRow.tsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { Button, Popover } from 'antd';
|
||||||
|
import { EllipsisIcon, PenLine, X } from 'lucide-react';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { Layout } from 'react-grid-layout';
|
||||||
|
|
||||||
|
interface WidgetRowHeaderProps {
|
||||||
|
rowWidgetProperties: {
|
||||||
|
widgets: Layout[];
|
||||||
|
collapsed: boolean;
|
||||||
|
};
|
||||||
|
editWidget: boolean;
|
||||||
|
deleteWidget: boolean;
|
||||||
|
setIsSettingsModalOpen: (value: React.SetStateAction<boolean>) => void;
|
||||||
|
setCurrentSelectRowId: (value: React.SetStateAction<string | null>) => void;
|
||||||
|
setIsDeleteModalOpen: (value: React.SetStateAction<boolean>) => void;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function WidgetRowHeader(props: WidgetRowHeaderProps): JSX.Element {
|
||||||
|
const {
|
||||||
|
rowWidgetProperties,
|
||||||
|
editWidget,
|
||||||
|
deleteWidget,
|
||||||
|
setCurrentSelectRowId,
|
||||||
|
setIsDeleteModalOpen,
|
||||||
|
setIsSettingsModalOpen,
|
||||||
|
id,
|
||||||
|
} = props;
|
||||||
|
const [isRowSettingsOpen, setIsRowSettingsOpen] = useState<boolean>(false);
|
||||||
|
return (
|
||||||
|
<Popover
|
||||||
|
open={isRowSettingsOpen}
|
||||||
|
arrow={false}
|
||||||
|
onOpenChange={(visible): void => setIsRowSettingsOpen(visible)}
|
||||||
|
rootClassName="row-settings"
|
||||||
|
trigger="hover"
|
||||||
|
placement="bottomRight"
|
||||||
|
content={
|
||||||
|
<div className="menu-content">
|
||||||
|
<section className="section-1">
|
||||||
|
<Button
|
||||||
|
className="rename-btn"
|
||||||
|
type="text"
|
||||||
|
disabled={!editWidget}
|
||||||
|
icon={<PenLine size={14} />}
|
||||||
|
onClick={(): void => {
|
||||||
|
setIsSettingsModalOpen(true);
|
||||||
|
setCurrentSelectRowId(id);
|
||||||
|
setIsRowSettingsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Rename
|
||||||
|
</Button>
|
||||||
|
</section>
|
||||||
|
{!rowWidgetProperties.collapsed && (
|
||||||
|
<section className="section-2">
|
||||||
|
<Button
|
||||||
|
className="remove-section"
|
||||||
|
type="text"
|
||||||
|
icon={<X size={14} />}
|
||||||
|
disabled={!deleteWidget}
|
||||||
|
onClick={(): void => {
|
||||||
|
setIsDeleteModalOpen(true);
|
||||||
|
setCurrentSelectRowId(id);
|
||||||
|
setIsRowSettingsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Remove Section
|
||||||
|
</Button>
|
||||||
|
</section>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<EllipsisIcon
|
||||||
|
size={14}
|
||||||
|
className="settings-icon"
|
||||||
|
onClick={(): void => setIsRowSettingsOpen(!isRowSettingsOpen)}
|
||||||
|
/>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,16 +1,13 @@
|
|||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { FullScreenHandle } from 'react-full-screen';
|
||||||
import { useCallback } from 'react';
|
|
||||||
|
|
||||||
import GraphLayoutContainer from './GridCardLayout';
|
import GraphLayoutContainer from './GridCardLayout';
|
||||||
|
|
||||||
function GridGraph(): JSX.Element {
|
interface GridGraphProps {
|
||||||
const { handleToggleDashboardSlider } = useDashboard();
|
handle: FullScreenHandle;
|
||||||
|
}
|
||||||
const onEmptyWidgetHandler = useCallback(() => {
|
function GridGraph(props: GridGraphProps): JSX.Element {
|
||||||
handleToggleDashboardSlider(true);
|
const { handle } = props;
|
||||||
}, [handleToggleDashboardSlider]);
|
return <GraphLayoutContainer handle={handle} />;
|
||||||
|
|
||||||
return <GraphLayoutContainer onAddPanelHandler={onEmptyWidgetHandler} />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GridGraph;
|
export default GridGraph;
|
||||||
|
|||||||
@@ -8,12 +8,28 @@ const ReactGridLayoutComponent = WidthProvider(RGL);
|
|||||||
|
|
||||||
interface CardProps {
|
interface CardProps {
|
||||||
$panelType: PANEL_TYPES;
|
$panelType: PANEL_TYPES;
|
||||||
|
isDarkMode: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Card = styled(CardComponent)<CardProps>`
|
export const Card = styled(CardComponent)<CardProps>`
|
||||||
&&& {
|
&&& {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid var(--bg-slate-500);
|
||||||
|
background: linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgba(171, 189, 255, 0) 0%,
|
||||||
|
rgba(171, 189, 255, 0) 100%
|
||||||
|
),
|
||||||
|
#0b0c0e;
|
||||||
|
|
||||||
|
${({ isDarkMode }): StyledCSS =>
|
||||||
|
!isDarkMode &&
|
||||||
|
css`
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: unset;
|
||||||
|
`}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
@@ -75,6 +91,7 @@ export const ReactGridLayout = styled(ReactGridLayoutComponent)`
|
|||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 40vh;
|
min-height: 40vh;
|
||||||
|
margin: 16px;
|
||||||
|
|
||||||
.react-grid-item.react-grid-placeholder {
|
.react-grid-item.react-grid-placeholder {
|
||||||
background: grey;
|
background: grey;
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
export interface GraphLayoutProps {
|
|
||||||
onAddPanelHandler: VoidFunction;
|
|
||||||
}
|
|
||||||
1191
frontend/src/container/ListOfDashboard/DashboardList.styles.scss
Normal file
1191
frontend/src/container/ListOfDashboard/DashboardList.styles.scss
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,269 @@
|
|||||||
|
.new-dashboard-templates-modal {
|
||||||
|
.ant-modal-content {
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
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;
|
||||||
|
height: 72vh;
|
||||||
|
|
||||||
|
.ant-modal-body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-dashboard-templates-content-container {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-dashboard-templates-content-header {
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
height: 60px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-dashboard-templates-content {
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
|
||||||
|
.new-dashboard-templates-list {
|
||||||
|
padding: 16px 8px;
|
||||||
|
height: 100%;
|
||||||
|
width: 25%;
|
||||||
|
border-right: 1px solid var(--bg-slate-500);
|
||||||
|
|
||||||
|
.new-dashboard-templates-search {
|
||||||
|
height: 32px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templates-list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
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;
|
||||||
|
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(--bg-vanilla-100);
|
||||||
|
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(--bg-vanilla-400);
|
||||||
|
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: 100%;
|
||||||
|
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(--bg-slate-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.new-dashboard-templates-modal {
|
||||||
|
.ant-modal-content {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-dashboard-templates-content-header {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-dashboard-templates-content {
|
||||||
|
.new-dashboard-templates-list {
|
||||||
|
border-right: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.templates-list {
|
||||||
|
.template-list-item {
|
||||||
|
.template-name {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(171, 189, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: rgba(171, 189, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-dashboard-template-preview {
|
||||||
|
.template-preview-header {
|
||||||
|
.template-preview-title {
|
||||||
|
.template-preview-icon {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-info {
|
||||||
|
.template-name {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-description {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-dashboard-btn {
|
||||||
|
.ant-btn {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.template-preview-image {
|
||||||
|
img {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-footer {
|
||||||
|
border-top: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
/* 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 { ChangeEvent, useState } from 'react';
|
||||||
|
import { DashboardTemplate } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
|
import { filterTemplates } from '../utils';
|
||||||
|
|
||||||
|
const templatesList: DashboardTemplate[] = [
|
||||||
|
{
|
||||||
|
name: 'Blank dashboard',
|
||||||
|
icon: <Drill />,
|
||||||
|
id: 'blank',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Alert Manager',
|
||||||
|
icon: <ConciergeBell />,
|
||||||
|
id: 'alertManager',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Apache',
|
||||||
|
icon: <ApacheIcon />,
|
||||||
|
id: 'apache',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Docker',
|
||||||
|
icon: <DockerIcon />,
|
||||||
|
id: 'docker',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Elasticsearch',
|
||||||
|
icon: <ElasticSearchIcon />,
|
||||||
|
id: 'elasticSearch',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'MongoDB',
|
||||||
|
icon: <MongoDBIcon />,
|
||||||
|
id: 'mongoDB',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Heroku',
|
||||||
|
icon: <HerokuIcon />,
|
||||||
|
id: 'heroku',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Nginx',
|
||||||
|
icon: <NginxIcon />,
|
||||||
|
id: 'nginx',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Kubernetes',
|
||||||
|
icon: <KubernetesIcon />,
|
||||||
|
id: 'kubernetes',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'MySQL',
|
||||||
|
icon: <MySQLIcon />,
|
||||||
|
id: 'mySQL',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'PostgreSQL',
|
||||||
|
icon: <PostgreSQLIcon />,
|
||||||
|
id: 'postgreSQL',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/blankDashboardTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Redis',
|
||||||
|
icon: <RedisIcon />,
|
||||||
|
id: 'redis',
|
||||||
|
description: 'Create a custom dashboard from scratch.',
|
||||||
|
previewImage: '/Images/redisTemplatePreview.svg',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'AWS',
|
||||||
|
icon: <DraftingCompass size={14} />,
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
|
||||||
|
const [dashboardTemplates, setDashboardTemplates] = useState(templatesList);
|
||||||
|
|
||||||
|
const handleDashboardTemplateSearch = (
|
||||||
|
event: ChangeEvent<HTMLInputElement>,
|
||||||
|
) => {
|
||||||
|
const searchText = event.target.value;
|
||||||
|
const filteredTemplates = filterTemplates(searchText, templatesList);
|
||||||
|
setDashboardTemplates(filteredTemplates);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
wrapClassName="new-dashboard-templates-modal"
|
||||||
|
open={showNewDashboardTemplatesModal}
|
||||||
|
centered
|
||||||
|
closable={false}
|
||||||
|
footer={null}
|
||||||
|
destroyOnClose
|
||||||
|
width="60vw"
|
||||||
|
>
|
||||||
|
<div className="new-dashboard-templates-content-container">
|
||||||
|
<div className="new-dashboard-templates-content-header">
|
||||||
|
<Typography.Text>New Dashboard</Typography.Text>
|
||||||
|
|
||||||
|
<X size={14} className="periscope-btn ghost" onClick={onCancel} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="new-dashboard-templates-content">
|
||||||
|
<div className="new-dashboard-templates-list">
|
||||||
|
<Input
|
||||||
|
className="new-dashboard-templates-search"
|
||||||
|
placeholder="🔍 Search..."
|
||||||
|
onChange={handleDashboardTemplateSearch}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="templates-list">
|
||||||
|
{dashboardTemplates.map((template) => (
|
||||||
|
<div
|
||||||
|
className={cx(
|
||||||
|
'template-list-item',
|
||||||
|
selectedDashboardTemplate.id === template.id ? 'active' : '',
|
||||||
|
)}
|
||||||
|
key={template.name}
|
||||||
|
onClick={() => setSelectedDashboardTemplate(template)}
|
||||||
|
>
|
||||||
|
<div className="template-icon">{template.icon}</div>
|
||||||
|
<div className="template-name">{template.name}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="new-dashboard-template-preview">
|
||||||
|
<div className="template-preview-header">
|
||||||
|
<div className="template-preview-title">
|
||||||
|
<div className="template-preview-icon">
|
||||||
|
{selectedDashboardTemplate.icon}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="template-info">
|
||||||
|
<div className="template-name">{selectedDashboardTemplate.name}</div>
|
||||||
|
|
||||||
|
<div className="template-description">
|
||||||
|
{selectedDashboardTemplate.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="create-dashboard-btn">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
className="periscope-btn primary"
|
||||||
|
icon={<Plus size={14} />}
|
||||||
|
onClick={onCreateNewDashboard}
|
||||||
|
>
|
||||||
|
New dashboard
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="template-preview-image">
|
||||||
|
<img
|
||||||
|
src={selectedDashboardTemplate.previewImage}
|
||||||
|
alt={`${selectedDashboardTemplate.name}-preview`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
|||||||
|
.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin {
|
||||||
|
background: linear-gradient(
|
||||||
|
139deg,
|
||||||
|
rgba(18, 19, 23, 0.8) 0%,
|
||||||
|
rgba(18, 19, 23, 0.9) 98.68%
|
||||||
|
);
|
||||||
|
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
}
|
||||||
|
.view-lines {
|
||||||
|
background: linear-gradient(
|
||||||
|
139deg,
|
||||||
|
rgba(18, 19, 23, 0.8) 0%,
|
||||||
|
rgba(18, 19, 23, 0.9) 98.68%
|
||||||
|
);
|
||||||
|
|
||||||
|
backdrop-filter: blur(20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.import-json-modal {
|
||||||
|
.ant-modal-content {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin {
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
.view-lines {
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-json-content-header {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-footer {
|
||||||
|
border-top: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +1,23 @@
|
|||||||
|
import './importJSON.styles.scss';
|
||||||
|
|
||||||
import { red } from '@ant-design/colors';
|
import { red } from '@ant-design/colors';
|
||||||
import { ExclamationCircleTwoTone } from '@ant-design/icons';
|
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 { Button, Modal, Space, Typography, Upload, UploadProps } from 'antd';
|
||||||
import createDashboard from 'api/dashboard/create';
|
import createDashboard from 'api/dashboard/create';
|
||||||
import Editor from 'components/Editor';
|
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import { MESSAGE } from 'hooks/useFeatureFlag';
|
import { MESSAGE } from 'hooks/useFeatureFlag';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import { getUpdatedLayout } from 'lib/dashboard/getUpdatedLayout';
|
import { getUpdatedLayout } from 'lib/dashboard/getUpdatedLayout';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
|
import { MonitorDot, MoveRight, X } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { generatePath } from 'react-router-dom';
|
import { generatePath } from 'react-router-dom';
|
||||||
import { DashboardData } from 'types/api/dashboard/getAll';
|
import { DashboardData } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
import { EditorContainer, FooterContainer } from './styles';
|
|
||||||
|
|
||||||
function ImportJSON({
|
function ImportJSON({
|
||||||
isImportJSONModalVisible,
|
isImportJSONModalVisible,
|
||||||
uploadedGrafana,
|
uploadedGrafana,
|
||||||
@@ -125,62 +128,114 @@ function ImportJSON({
|
|||||||
onModalHandler();
|
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 (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
wrapClassName="import-json-modal"
|
||||||
open={isImportJSONModalVisible}
|
open={isImportJSONModalVisible}
|
||||||
centered
|
centered
|
||||||
maskClosable
|
closable={false}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
width="70vw"
|
width="60vw"
|
||||||
onCancel={onCancelHandler}
|
|
||||||
title={
|
|
||||||
<>
|
|
||||||
<Typography.Title level={4}>{t('import_json')}</Typography.Title>
|
|
||||||
<Typography>{t('import_dashboard_by_pasting')}</Typography>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
footer={
|
footer={
|
||||||
<FooterContainer>
|
<div className="import-json-modal-footer">
|
||||||
<Button
|
{isCreateDashboardError && (
|
||||||
disabled={editorValue.length === 0}
|
<div className="create-dashboard-json-error">
|
||||||
onClick={onClickLoadJsonHandler}
|
{getErrorNode(t('error_loading_json'))}
|
||||||
loading={dashboardCreating}
|
</div>
|
||||||
>
|
|
||||||
{t('load_json')}
|
|
||||||
</Button>
|
|
||||||
{isCreateDashboardError && getErrorNode(t('error_loading_json'))}
|
|
||||||
{isFeatureAlert && (
|
|
||||||
<Typography.Text type="danger">
|
|
||||||
{MESSAGE.CREATE_DASHBOARD}
|
|
||||||
</Typography.Text>
|
|
||||||
)}
|
)}
|
||||||
</FooterContainer>
|
|
||||||
|
{isUploadJSONError && (
|
||||||
|
<div className="create-dashboard-json-error">
|
||||||
|
{getErrorNode(t('error_upload_json'))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="action-btns-container">
|
||||||
|
<Upload
|
||||||
|
accept=".json"
|
||||||
|
showUploadList={false}
|
||||||
|
multiple={false}
|
||||||
|
onChange={onChangeHandler}
|
||||||
|
beforeUpload={(): boolean => false}
|
||||||
|
action="none"
|
||||||
|
data={jsonData}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
className="periscope-btn"
|
||||||
|
icon={<MonitorDot size={14} />}
|
||||||
|
>
|
||||||
|
{' '}
|
||||||
|
{t('upload_json_file')}
|
||||||
|
</Button>
|
||||||
|
</Upload>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
// disabled={editorValue.length === 0}
|
||||||
|
onClick={onClickLoadJsonHandler}
|
||||||
|
loading={dashboardCreating}
|
||||||
|
className="periscope-btn primary"
|
||||||
|
type="primary"
|
||||||
|
>
|
||||||
|
{t('load_json')} <MoveRight size={14} />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{isFeatureAlert && (
|
||||||
|
<Typography.Text type="danger">
|
||||||
|
{MESSAGE.CREATE_DASHBOARD}
|
||||||
|
</Typography.Text>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<div className="import-json-content-container">
|
||||||
<Space direction="horizontal">
|
<div className="import-json-content-header">
|
||||||
<Upload
|
<Typography.Text>{t('import_json')}</Typography.Text>
|
||||||
accept=".json"
|
|
||||||
showUploadList={false}
|
|
||||||
multiple={false}
|
|
||||||
onChange={onChangeHandler}
|
|
||||||
beforeUpload={(): boolean => false}
|
|
||||||
action="none"
|
|
||||||
data={jsonData}
|
|
||||||
>
|
|
||||||
<Button type="primary">{t('upload_json_file')}</Button>
|
|
||||||
</Upload>
|
|
||||||
{isUploadJSONError && <>{getErrorNode(t('error_upload_json'))}</>}
|
|
||||||
</Space>
|
|
||||||
|
|
||||||
<EditorContainer>
|
<X size={14} className="periscope-btn ghost" onClick={onCancelHandler} />
|
||||||
<Typography.Paragraph>{t('paste_json_below')}</Typography.Paragraph>
|
</div>
|
||||||
<Editor
|
|
||||||
onChange={(newValue): void => setEditorValue(newValue)}
|
<MEditor
|
||||||
value={editorValue}
|
language="json"
|
||||||
language="json"
|
height="40vh"
|
||||||
/>
|
onChange={(newValue): void => setEditorValue(newValue || '')}
|
||||||
</EditorContainer>
|
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}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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;
|
|
||||||
`;
|
|
||||||
@@ -3,3 +3,13 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.delete-btn:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.delete-btn:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.06) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import './DeleteButton.styles.scss';
|
|||||||
import { DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
||||||
import { Modal, Tooltip, Typography } from 'antd';
|
import { Modal, Tooltip, Typography } from 'antd';
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
import { useDeleteDashboard } from 'hooks/dashboard/useDeleteDashboard';
|
import { useDeleteDashboard } from 'hooks/dashboard/useDeleteDashboard';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
|
import history from 'lib/history';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQueryClient } from 'react-query';
|
import { useQueryClient } from 'react-query';
|
||||||
@@ -21,13 +23,15 @@ interface DeleteButtonProps {
|
|||||||
name: string;
|
name: string;
|
||||||
id: string;
|
id: string;
|
||||||
isLocked: boolean;
|
isLocked: boolean;
|
||||||
|
routeToListPage?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DeleteButton({
|
export function DeleteButton({
|
||||||
createdBy,
|
createdBy,
|
||||||
name,
|
name,
|
||||||
id,
|
id,
|
||||||
isLocked,
|
isLocked,
|
||||||
|
routeToListPage,
|
||||||
}: DeleteButtonProps): JSX.Element {
|
}: DeleteButtonProps): JSX.Element {
|
||||||
const [modal, contextHolder] = Modal.useModal();
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
const { role, user } = useSelector<AppState, AppReducer>((state) => state.app);
|
const { role, user } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
@@ -42,7 +46,7 @@ function DeleteButton({
|
|||||||
const deleteDashboardMutation = useDeleteDashboard(id);
|
const deleteDashboardMutation = useDeleteDashboard(id);
|
||||||
|
|
||||||
const openConfirmationDialog = useCallback((): void => {
|
const openConfirmationDialog = useCallback((): void => {
|
||||||
modal.confirm({
|
const { destroy } = modal.confirm({
|
||||||
title: (
|
title: (
|
||||||
<Typography.Title level={5}>
|
<Typography.Title level={5}>
|
||||||
Are you sure you want to delete the
|
Are you sure you want to delete the
|
||||||
@@ -51,24 +55,40 @@ function DeleteButton({
|
|||||||
</Typography.Title>
|
</Typography.Title>
|
||||||
),
|
),
|
||||||
icon: <ExclamationCircleOutlined style={{ color: '#e42b35' }} />,
|
icon: <ExclamationCircleOutlined style={{ color: '#e42b35' }} />,
|
||||||
onOk() {
|
|
||||||
deleteDashboardMutation.mutateAsync(undefined, {
|
|
||||||
onSuccess: () => {
|
|
||||||
notifications.success({
|
|
||||||
message: t('dashboard:delete_dashboard_success', {
|
|
||||||
name,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
queryClient.invalidateQueries([REACT_QUERY_KEY.GET_ALL_DASHBOARDS]);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
okText: 'Delete',
|
okText: 'Delete',
|
||||||
okButtonProps: { danger: true },
|
okButtonProps: {
|
||||||
|
danger: true,
|
||||||
|
onClick: (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
deleteDashboardMutation.mutateAsync(undefined, {
|
||||||
|
onSuccess: () => {
|
||||||
|
notifications.success({
|
||||||
|
message: t('dashboard:delete_dashboard_success', {
|
||||||
|
name,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
queryClient.invalidateQueries([REACT_QUERY_KEY.GET_ALL_DASHBOARDS]);
|
||||||
|
if (routeToListPage) {
|
||||||
|
history.replace(ROUTES.ALL_DASHBOARD);
|
||||||
|
}
|
||||||
|
destroy();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
centered: true,
|
centered: true,
|
||||||
className: 'delete-modal',
|
className: 'delete-modal',
|
||||||
});
|
});
|
||||||
}, [modal, name, deleteDashboardMutation, notifications, t, queryClient]);
|
}, [
|
||||||
|
modal,
|
||||||
|
name,
|
||||||
|
deleteDashboardMutation,
|
||||||
|
notifications,
|
||||||
|
t,
|
||||||
|
queryClient,
|
||||||
|
routeToListPage,
|
||||||
|
]);
|
||||||
|
|
||||||
const getDeleteTooltipContent = (): string => {
|
const getDeleteTooltipContent = (): string => {
|
||||||
if (isLocked) {
|
if (isLocked) {
|
||||||
@@ -87,14 +107,17 @@ function DeleteButton({
|
|||||||
<Tooltip placement="left" title={getDeleteTooltipContent()}>
|
<Tooltip placement="left" title={getDeleteTooltipContent()}>
|
||||||
<TableLinkText
|
<TableLinkText
|
||||||
type="danger"
|
type="danger"
|
||||||
onClick={(): void => {
|
onClick={(e): void => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
if (!isLocked) {
|
if (!isLocked) {
|
||||||
openConfirmationDialog();
|
openConfirmationDialog();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={isLocked}
|
className="delete-btn"
|
||||||
|
disabled={isLocked || (role === USER_ROLES.VIEWER && !isAuthor)}
|
||||||
>
|
>
|
||||||
<DeleteOutlined /> Delete
|
<DeleteOutlined /> Delete dashboard
|
||||||
</TableLinkText>
|
</TableLinkText>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
@@ -103,6 +126,10 @@ function DeleteButton({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeleteButton.defaultProps = {
|
||||||
|
routeToListPage: false,
|
||||||
|
};
|
||||||
|
|
||||||
// This is to avoid the type collision
|
// This is to avoid the type collision
|
||||||
function Wrapper(props: Data): JSX.Element {
|
function Wrapper(props: Data): JSX.Element {
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
import { Dashboard, DashboardTemplate } from 'types/api/dashboard/getAll';
|
||||||
|
|
||||||
export const filterDashboard = (
|
export const filterDashboard = (
|
||||||
searchValue: string,
|
searchValue: string,
|
||||||
@@ -25,3 +25,31 @@ export const filterDashboard = (
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const filterTemplates = (
|
||||||
|
searchValue: string,
|
||||||
|
dashboardList: DashboardTemplate[],
|
||||||
|
): DashboardTemplate[] => {
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface DashboardDynamicColumns {
|
||||||
|
createdAt: boolean;
|
||||||
|
createdBy: boolean;
|
||||||
|
updatedAt: boolean;
|
||||||
|
updatedBy: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DynamicColumns {
|
||||||
|
CREATED_AT = 'createdAt',
|
||||||
|
CREATED_BY = 'createdBy',
|
||||||
|
UPDATED_AT = 'updatedAt',
|
||||||
|
UPDATED_BY = 'updatedBy',
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
.graph-selection {
|
||||||
|
.ant-modal-content {
|
||||||
|
width: 515px;
|
||||||
|
max-height: 646px;
|
||||||
|
overflow-y: auto;
|
||||||
|
flex-shrink: 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);
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
height: 52px;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
margin-bottom: 0px;
|
||||||
|
|
||||||
|
.ant-modal-title {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-slate-400);
|
||||||
|
|
||||||
|
.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(--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-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(--bg-slate-500);
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
padding: 12px 15px;
|
||||||
|
margin-top: 0px;
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
/* button/ small */
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 24px; /* 200% */
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--bg-robin-500);
|
||||||
|
padding: 4px 8px;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0.1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.graph-selection {
|
||||||
|
.ant-modal-content {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-modal-title {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-body {
|
||||||
|
.panel-selection {
|
||||||
|
.selected {
|
||||||
|
background: var(--bg-vanilla-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-card-body {
|
||||||
|
.ant-typography {
|
||||||
|
color: var(--bg-ink-200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-footer {
|
||||||
|
border-top: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
color: var(--Vanilla-100, #fff);
|
||||||
|
|
||||||
|
background: var(--Robin-500, #4e74f8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import './ComponentSlider.styles.scss';
|
||||||
|
|
||||||
|
import { Card, Modal } from 'antd';
|
||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import createQueryParams from 'lib/createQueryParams';
|
import createQueryParams from 'lib/createQueryParams';
|
||||||
@@ -8,10 +11,10 @@ import { v4 as uuid } from 'uuid';
|
|||||||
|
|
||||||
import { PANEL_TYPES_INITIAL_QUERY } from './constants';
|
import { PANEL_TYPES_INITIAL_QUERY } from './constants';
|
||||||
import menuItems from './menuItems';
|
import menuItems from './menuItems';
|
||||||
import { Card, Container, Text } from './styles';
|
import { Text } from './styles';
|
||||||
|
|
||||||
function DashboardGraphSlider(): JSX.Element {
|
function DashboardGraphSlider(): JSX.Element {
|
||||||
const { handleToggleDashboardSlider } = useDashboard();
|
const { handleToggleDashboardSlider, isDashboardSliderOpen } = useDashboard();
|
||||||
|
|
||||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
const onClickHandler = (name: PANEL_TYPES) => (): void => {
|
const onClickHandler = (name: PANEL_TYPES) => (): void => {
|
||||||
@@ -56,15 +59,29 @@ function DashboardGraphSlider(): JSX.Element {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCardClick = (panelType: PANEL_TYPES): void => {
|
||||||
|
onClickHandler(panelType)();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Modal
|
||||||
{menuItems.map(({ name, icon, display }) => (
|
open={isDashboardSliderOpen}
|
||||||
<Card onClick={onClickHandler(name)} id={name} key={name}>
|
onCancel={(): void => {
|
||||||
{icon}
|
handleToggleDashboardSlider(false);
|
||||||
<Text>{display}</Text>
|
}}
|
||||||
</Card>
|
rootClassName="graph-selection"
|
||||||
))}
|
footer={null}
|
||||||
</Container>
|
title="New Panel"
|
||||||
|
>
|
||||||
|
<div className="panel-selection">
|
||||||
|
{menuItems.map(({ name, icon, display }) => (
|
||||||
|
<Card onClick={(): void => handleCardClick(name)} id={name} key={name}>
|
||||||
|
{icon}
|
||||||
|
<Text>{display}</Text>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,32 +12,32 @@ import {
|
|||||||
const Items: ItemsProps[] = [
|
const Items: ItemsProps[] = [
|
||||||
{
|
{
|
||||||
name: PANEL_TYPES.TIME_SERIES,
|
name: PANEL_TYPES.TIME_SERIES,
|
||||||
icon: <LineChart size={32} color={Color.BG_ROBIN_400} />,
|
icon: <LineChart size={16} color={Color.BG_ROBIN_400} />,
|
||||||
display: 'Time Series',
|
display: 'Time Series',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: PANEL_TYPES.VALUE,
|
name: PANEL_TYPES.VALUE,
|
||||||
icon: <SigmaSquare size={32} color={Color.BG_ROBIN_400} />,
|
icon: <SigmaSquare size={16} color={Color.BG_ROBIN_400} />,
|
||||||
display: 'Value',
|
display: 'Value',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: PANEL_TYPES.TABLE,
|
name: PANEL_TYPES.TABLE,
|
||||||
icon: <Table size={32} color={Color.BG_ROBIN_400} />,
|
icon: <Table size={16} color={Color.BG_ROBIN_400} />,
|
||||||
display: 'Table',
|
display: 'Table',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: PANEL_TYPES.LIST,
|
name: PANEL_TYPES.LIST,
|
||||||
icon: <List size={32} color={Color.BG_ROBIN_400} />,
|
icon: <List size={16} color={Color.BG_ROBIN_400} />,
|
||||||
display: 'List',
|
display: 'List',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: PANEL_TYPES.BAR,
|
name: PANEL_TYPES.BAR,
|
||||||
icon: <BarChart3 size={32} color={Color.BG_ROBIN_400} />,
|
icon: <BarChart3 size={16} color={Color.BG_ROBIN_400} />,
|
||||||
display: 'Bar',
|
display: 'Bar',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: PANEL_TYPES.PIE,
|
name: PANEL_TYPES.PIE,
|
||||||
icon: <PieChart size={32} color={Color.BG_ROBIN_400} />,
|
icon: <PieChart size={16} color={Color.BG_ROBIN_400} />,
|
||||||
display: 'Pie',
|
display: 'Pie',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,13 +1,230 @@
|
|||||||
.dashboard-description-container {
|
.settings-container-root {
|
||||||
box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.25);
|
.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);
|
||||||
|
|
||||||
border: 1px solid var(--bg-slate-400, #1d212d);
|
.ant-drawer-header {
|
||||||
background: var(--bg-ink-400, #121317);
|
height: 48px;
|
||||||
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
color: var(--bg-vanilla-400, #c0c1c3);
|
padding: 14px 14px 14px 11px;
|
||||||
|
|
||||||
|
.ant-drawer-header-title {
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.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;
|
||||||
|
padding-left: 16px;
|
||||||
|
border-left: 1px solid #161922;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-close {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
margin-inline-end: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-body {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0.1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-description-container {
|
||||||
|
box-shadow: none;
|
||||||
|
border: none;
|
||||||
|
background: unset;
|
||||||
|
box-shadow: none;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
|
||||||
.ant-card-body {
|
.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(--bg-vanilla-400);
|
||||||
|
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(--bg-robin-400);
|
||||||
|
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: 10px 16px 0px 0px;
|
||||||
|
gap: 14px;
|
||||||
|
|
||||||
|
.icons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 34px;
|
||||||
|
padding: 6px;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 10px; /* 83.333% */
|
||||||
|
letter-spacing: 0.12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
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(--bg-vanilla-100);
|
||||||
|
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(--bg-sienna-400);
|
||||||
|
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(--bg-vanilla-400);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,21 +236,467 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-actions {
|
.dashboard-settings {
|
||||||
display: flex;
|
width: 191px;
|
||||||
flex-direction: column;
|
height: 302px;
|
||||||
gap: 8px;
|
flex-shrink: 0;
|
||||||
}
|
|
||||||
|
|
||||||
.lightMode {
|
.ant-popover-inner {
|
||||||
.dashboard-description-container {
|
padding: 0px;
|
||||||
box-shadow: none;
|
border-radius: 4px;
|
||||||
border: 1px solid var(--bg-vanilla-300);
|
border: 1px solid var(--bg-slate-400);
|
||||||
background-color: rgb(250, 250, 250);
|
background: linear-gradient(
|
||||||
color: var(--bg-ink-300);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
.ant-card-body {
|
.menu-content {
|
||||||
padding: 12px 16px;
|
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(--bg-vanilla-400);
|
||||||
|
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(--bg-vanilla-400);
|
||||||
|
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(--bg-cherry-400) !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(--bg-slate-500);
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
box-shadow: 0px -4px 16px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
height: 52px;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
margin-bottom: 0px;
|
||||||
|
.ant-modal-title {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
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(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-name-input {
|
||||||
|
display: flex;
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
align-self: stretch;
|
||||||
|
border-radius: 0px 2px 2px 0px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-slate-500);
|
||||||
|
|
||||||
|
.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(--bg-robin-500);
|
||||||
|
|
||||||
|
.ant-btn-icon {
|
||||||
|
margin-inline-end: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-naming {
|
||||||
|
.ant-modal-content {
|
||||||
|
width: 384px;
|
||||||
|
flex-shrink: 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);
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
height: 52px;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
margin-bottom: 0px;
|
||||||
|
.ant-modal-title {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
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;
|
||||||
|
|
||||||
|
.section-naming-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.name-text {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-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(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-slate-500);
|
||||||
|
|
||||||
|
.ant-btn-icon {
|
||||||
|
margin-inline-end: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rename-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
width: 140px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--bg-robin-500);
|
||||||
|
|
||||||
|
.ant-btn-icon {
|
||||||
|
margin-inline-end: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.settings-container-root {
|
||||||
|
.ant-drawer-wrapper-body {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.ant-drawer-header {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-drawer-header-title {
|
||||||
|
.ant-drawer-title {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
border-left: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-drawer-close {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-description-container {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
|
||||||
|
.dashboard-breadcrumbs {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.dashboard-btn {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashbord-details {
|
||||||
|
.left-section {
|
||||||
|
.dashboard-title {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-section {
|
||||||
|
.icons {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
.configure-button {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-panel-btn {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-description-section {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dashboard-settings {
|
||||||
|
.ant-popover-inner {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.section-1 {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.section-2 {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rename-dashboard {
|
||||||
|
.ant-modal-content {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-modal-title {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-body {
|
||||||
|
.dashboard-content {
|
||||||
|
.name-text {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-name-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-footer {
|
||||||
|
.dashboard-rename {
|
||||||
|
.cancel-btn {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-naming {
|
||||||
|
.ant-modal-content {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.ant-modal-header {
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-modal-title {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-body {
|
||||||
|
.section-naming-content {
|
||||||
|
.name-text {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-name-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-modal-footer {
|
||||||
|
.dashboard-rename {
|
||||||
|
.cancel-btn {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { Button, Tooltip } from 'antd';
|
import './Description.styles.scss';
|
||||||
import { Cog } from 'lucide-react';
|
|
||||||
import { useState } from 'react';
|
import { Button } from 'antd';
|
||||||
|
import ConfigureIcon from 'assets/Integrations/ConfigureIcon';
|
||||||
|
import { useRef, useState } from 'react';
|
||||||
|
|
||||||
import DashboardSettingsContent from '../DashboardSettings';
|
import DashboardSettingsContent from '../DashboardSettings';
|
||||||
import { DrawerContainer } from './styles';
|
import { DrawerContainer } from './styles';
|
||||||
@@ -8,34 +10,38 @@ import { DrawerContainer } from './styles';
|
|||||||
function SettingsDrawer({ drawerTitle }: { drawerTitle: string }): JSX.Element {
|
function SettingsDrawer({ drawerTitle }: { drawerTitle: string }): JSX.Element {
|
||||||
const [visible, setVisible] = useState<boolean>(false);
|
const [visible, setVisible] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const variableViewModeRef = useRef<() => void>();
|
||||||
|
|
||||||
const showDrawer = (): void => {
|
const showDrawer = (): void => {
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClose = (): void => {
|
const onClose = (): void => {
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
|
variableViewModeRef?.current?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tooltip title="Configure" placement="left">
|
<Button
|
||||||
<Button
|
type="text"
|
||||||
className="periscope-btn"
|
className="configure-button"
|
||||||
onClick={showDrawer}
|
icon={<ConfigureIcon />}
|
||||||
style={{ width: '100%' }}
|
data-testid="show-drawer"
|
||||||
data-testid="show-drawer"
|
onClick={showDrawer}
|
||||||
icon={<Cog size={16} />}
|
>
|
||||||
/>
|
Configure
|
||||||
</Tooltip>
|
</Button>
|
||||||
|
|
||||||
<DrawerContainer
|
<DrawerContainer
|
||||||
title={drawerTitle}
|
title={drawerTitle}
|
||||||
placement="right"
|
placement="right"
|
||||||
width="60%"
|
width="50%"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
open={visible}
|
open={visible}
|
||||||
|
rootClassName="settings-container-root"
|
||||||
>
|
>
|
||||||
<DashboardSettingsContent />
|
<DashboardSettingsContent variableViewModeRef={variableViewModeRef} />
|
||||||
</DrawerContainer>
|
</DrawerContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,25 +1,66 @@
|
|||||||
import './Description.styles.scss';
|
import './Description.styles.scss';
|
||||||
|
|
||||||
import { LockFilled, UnlockFilled } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import { Button, Card, Col, Row, Tag, Tooltip, Typography } from 'antd';
|
import { Button, Card, Input, Modal, Popover, Tag, Typography } from 'antd';
|
||||||
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
|
import { PANEL_GROUP_TYPES, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
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 useComponentPermission from 'hooks/useComponentPermission';
|
||||||
import { Share2 } from 'lucide-react';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
|
import history from 'lib/history';
|
||||||
|
import { isEmpty } from 'lodash-es';
|
||||||
|
import {
|
||||||
|
Check,
|
||||||
|
ClipboardCopy,
|
||||||
|
Ellipsis,
|
||||||
|
FileJson,
|
||||||
|
FolderKanban,
|
||||||
|
Fullscreen,
|
||||||
|
LayoutGrid,
|
||||||
|
LockKeyhole,
|
||||||
|
PenLine,
|
||||||
|
X,
|
||||||
|
} from 'lucide-react';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import { useState } from 'react';
|
import { sortLayout } from 'providers/Dashboard/util';
|
||||||
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { FullScreenHandle } from 'react-full-screen';
|
||||||
|
import { Layout } from 'react-grid-layout';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
|
import { useCopyToClipboard } from 'react-use';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { DashboardData } from 'types/api/dashboard/getAll';
|
import { Dashboard, DashboardData } from 'types/api/dashboard/getAll';
|
||||||
import AppReducer from 'types/reducer/app';
|
import AppReducer from 'types/reducer/app';
|
||||||
import { USER_ROLES } from 'types/roles';
|
import { ROLES, USER_ROLES } from 'types/roles';
|
||||||
|
import { ComponentTypes } from 'utils/permission';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
|
import DashboardGraphSlider from '../ComponentsSlider';
|
||||||
|
import { Base64Icons } from '../DashboardSettings/General/utils';
|
||||||
import DashboardVariableSelection from '../DashboardVariablesSelection';
|
import DashboardVariableSelection from '../DashboardVariablesSelection';
|
||||||
import SettingsDrawer from './SettingsDrawer';
|
import SettingsDrawer from './SettingsDrawer';
|
||||||
import ShareModal from './ShareModal';
|
import { DEFAULT_ROW_NAME, 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 {
|
const {
|
||||||
selectedDashboard,
|
selectedDashboard,
|
||||||
|
panelMap,
|
||||||
|
setPanelMap,
|
||||||
|
layouts,
|
||||||
|
setLayouts,
|
||||||
isDashboardLocked,
|
isDashboardLocked,
|
||||||
|
setSelectedDashboard,
|
||||||
|
handleToggleDashboardSlider,
|
||||||
handleDashboardLockToggle,
|
handleDashboardLockToggle,
|
||||||
} = useDashboard();
|
} = useDashboard();
|
||||||
|
|
||||||
@@ -30,12 +71,30 @@ function DashboardDescription(): JSX.Element {
|
|||||||
}
|
}
|
||||||
: ({} as DashboardData);
|
: ({} as DashboardData);
|
||||||
|
|
||||||
const { title = '', tags, description } = selectedData || {};
|
const { title = '', description, tags, image = Base64Icons[0] } =
|
||||||
|
selectedData || {};
|
||||||
|
|
||||||
const [openDashboardJSON, setOpenDashboardJSON] = useState<boolean>(false);
|
const [updatedTitle, setUpdatedTitle] = useState<string>(title);
|
||||||
|
|
||||||
const { user, role } = useSelector<AppState, AppReducer>((state) => state.app);
|
const [sectionName, setSectionName] = useState<string>(DEFAULT_ROW_NAME);
|
||||||
|
|
||||||
|
const updateDashboardMutation = useUpdateDashboard();
|
||||||
|
|
||||||
|
const { featureResponse, user, role } = useSelector<AppState, AppReducer>(
|
||||||
|
(state) => state.app,
|
||||||
|
);
|
||||||
const [editDashboard] = useComponentPermission(['edit_dashboard'], role);
|
const [editDashboard] = useComponentPermission(['edit_dashboard'], role);
|
||||||
|
const [isDashboardSettingsOpen, setIsDashbordSettingsOpen] = useState<boolean>(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [isRenameDashboardOpen, setIsRenameDashboardOpen] = useState<boolean>(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
const [isPanelNameModalOpen, setIsPanelNameModalOpen] = useState<boolean>(
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
let isAuthor = false;
|
let isAuthor = false;
|
||||||
|
|
||||||
@@ -43,91 +102,399 @@ function DashboardDescription(): JSX.Element {
|
|||||||
isAuthor = selectedDashboard?.created_by === user?.email;
|
isAuthor = selectedDashboard?.created_by === user?.email;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onToggleHandler = (): void => {
|
let permissions: ComponentTypes[] = ['add_panel'];
|
||||||
setOpenDashboardJSON((state) => !state);
|
|
||||||
};
|
if (isDashboardLocked) {
|
||||||
|
permissions = ['add_panel_locked_dashboard'];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { notifications } = useNotifications();
|
||||||
|
|
||||||
|
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]);
|
||||||
|
|
||||||
const handleLockDashboardToggle = (): void => {
|
const handleLockDashboardToggle = (): void => {
|
||||||
|
setIsDashbordSettingsOpen(false);
|
||||||
handleDashboardLockToggle(!isDashboardLocked);
|
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]);
|
||||||
|
|
||||||
|
function handleAddRow(): void {
|
||||||
|
if (!selectedDashboard) return;
|
||||||
|
const id = uuid();
|
||||||
|
|
||||||
|
const newRowWidgetMap: { widgets: Layout[]; collapsed: boolean } = {
|
||||||
|
widgets: [],
|
||||||
|
collapsed: false,
|
||||||
|
};
|
||||||
|
const currentRowIdx = 0;
|
||||||
|
for (let j = currentRowIdx; j < layouts.length; j++) {
|
||||||
|
if (!panelMap[layouts[j].i]) {
|
||||||
|
newRowWidgetMap.widgets.push(layouts[j]);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedDashboard: Dashboard = {
|
||||||
|
...selectedDashboard,
|
||||||
|
data: {
|
||||||
|
...selectedDashboard.data,
|
||||||
|
layout: [
|
||||||
|
{
|
||||||
|
i: id,
|
||||||
|
w: 12,
|
||||||
|
minW: 12,
|
||||||
|
minH: 1,
|
||||||
|
maxH: 1,
|
||||||
|
x: 0,
|
||||||
|
h: 1,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
...layouts.filter((e) => e.i !== PANEL_TYPES.EMPTY_WIDGET),
|
||||||
|
],
|
||||||
|
panelMap: { ...panelMap, [id]: newRowWidgetMap },
|
||||||
|
widgets: [
|
||||||
|
...(selectedDashboard.data.widgets || []),
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
title: sectionName,
|
||||||
|
description: '',
|
||||||
|
panelTypes: PANEL_GROUP_TYPES.ROW,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
uuid: selectedDashboard.uuid,
|
||||||
|
};
|
||||||
|
|
||||||
|
updateDashboardMutation.mutate(updatedDashboard, {
|
||||||
|
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||||
|
onSuccess: (updatedDashboard) => {
|
||||||
|
if (updatedDashboard.payload) {
|
||||||
|
if (updatedDashboard.payload.data.layout)
|
||||||
|
setLayouts(sortLayout(updatedDashboard.payload.data.layout));
|
||||||
|
setSelectedDashboard(updatedDashboard.payload);
|
||||||
|
setPanelMap(updatedDashboard.payload?.data?.panelMap || {});
|
||||||
|
}
|
||||||
|
|
||||||
|
featureResponse.refetch();
|
||||||
|
setIsPanelNameModalOpen(false);
|
||||||
|
setSectionName(DEFAULT_ROW_NAME);
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||||
|
onError: () => {
|
||||||
|
notifications.error({
|
||||||
|
message: SOMETHING_WENT_WRONG,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="dashboard-description-container">
|
<Card className="dashboard-description-container">
|
||||||
<Row gutter={16}>
|
<section className="dashboard-breadcrumbs">
|
||||||
<Col flex={1} span={9}>
|
<Button
|
||||||
<Typography.Title
|
type="text"
|
||||||
level={4}
|
icon={<LayoutGrid size={14} />}
|
||||||
style={{ padding: 0, margin: 0 }}
|
className="dashboard-btn"
|
||||||
data-testid="dashboard-landing-name"
|
onClick={(): void => history.push(ROUTES.ALL_DASHBOARD)}
|
||||||
>
|
>
|
||||||
{isDashboardLocked && (
|
Dashboard /
|
||||||
<Tooltip title="Dashboard Locked" placement="top">
|
</Button>
|
||||||
<LockFilled />
|
<Button
|
||||||
</Tooltip>
|
type="text"
|
||||||
)}
|
className="id-btn"
|
||||||
{title}
|
icon={
|
||||||
</Typography.Title>
|
// eslint-disable-next-line jsx-a11y/img-redundant-alt
|
||||||
{description && (
|
<img
|
||||||
<Typography
|
src={image}
|
||||||
className="dashboard-description"
|
alt="dashboard-image"
|
||||||
data-testid="dashboard-landing-desc"
|
style={{ height: '14px', width: '14px' }}
|
||||||
>
|
|
||||||
{description}
|
|
||||||
</Typography>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{tags && (
|
|
||||||
<div style={{ margin: '0.5rem 0' }}>
|
|
||||||
{tags?.map((tag) => (
|
|
||||||
<Tag key={tag}>{tag}</Tag>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Col>
|
|
||||||
<Col span={14}>
|
|
||||||
<Row justify="end">
|
|
||||||
<DashboardVariableSelection />
|
|
||||||
</Row>
|
|
||||||
</Col>
|
|
||||||
<Col span={1} style={{ textAlign: 'right' }}>
|
|
||||||
{selectedData && (
|
|
||||||
<ShareModal
|
|
||||||
isJSONModalVisible={openDashboardJSON}
|
|
||||||
onToggleHandler={onToggleHandler}
|
|
||||||
selectedData={selectedData}
|
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</Button>
|
||||||
|
</section>
|
||||||
|
<section className="dashbord-details">
|
||||||
|
<div className="left-section">
|
||||||
|
<img
|
||||||
|
src={image}
|
||||||
|
alt="dashboard-img"
|
||||||
|
style={{ width: '16px', height: '16px' }}
|
||||||
|
/>
|
||||||
|
<Typography.Text className="dashboard-title">{title}</Typography.Text>
|
||||||
|
{isDashboardLocked && <LockKeyhole size={14} />}
|
||||||
|
</div>
|
||||||
|
<div className="right-section">
|
||||||
|
<DateTimeSelectionV2 showAutoRefresh hideShareModal />
|
||||||
|
<Popover
|
||||||
|
open={isDashboardSettingsOpen}
|
||||||
|
arrow={false}
|
||||||
|
onOpenChange={(visible): void => setIsDashbordSettingsOpen(visible)}
|
||||||
|
rootClassName="dashboard-settings"
|
||||||
|
content={
|
||||||
|
<div className="menu-content">
|
||||||
|
<section className="section-1">
|
||||||
|
{(isAuthor || role === USER_ROLES.ADMIN) && (
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<LockKeyhole size={14} />}
|
||||||
|
onClick={handleLockDashboardToggle}
|
||||||
|
>
|
||||||
|
{isDashboardLocked ? 'Unlock Dashboard' : 'Lock Dashboard'}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!isDashboardLocked && editDashboard && (
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<PenLine size={14} />}
|
||||||
|
onClick={(): void => {
|
||||||
|
setIsRenameDashboardOpen(true);
|
||||||
|
setIsDashbordSettingsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Rename
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<Fullscreen size={14} />}
|
||||||
|
onClick={handle.enter}
|
||||||
|
>
|
||||||
|
Full screen
|
||||||
|
</Button>
|
||||||
|
</section>
|
||||||
|
<section className="section-2">
|
||||||
|
{!isDashboardLocked && addPanelPermission && (
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<FolderKanban size={14} />}
|
||||||
|
onClick={(): void => {
|
||||||
|
setIsPanelNameModalOpen(true);
|
||||||
|
setIsDashbordSettingsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
New section
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<FileJson size={14} />}
|
||||||
|
onClick={(): void => {
|
||||||
|
downloadObjectAsJson(selectedData, selectedData.title);
|
||||||
|
setIsDashbordSettingsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Export JSON
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<ClipboardCopy size={14} />}
|
||||||
|
onClick={(): void => {
|
||||||
|
setCopy(JSON.stringify(selectedData, null, 2));
|
||||||
|
setIsDashbordSettingsOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Copy as JSON
|
||||||
|
</Button>
|
||||||
|
</section>
|
||||||
|
<section className="delete-dashboard">
|
||||||
|
<DeleteButton
|
||||||
|
createdBy={selectedDashboard?.created_by || ''}
|
||||||
|
name={selectedDashboard?.data.title || ''}
|
||||||
|
id={String(selectedDashboard?.uuid) || ''}
|
||||||
|
isLocked={isDashboardLocked}
|
||||||
|
routeToListPage
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
trigger="click"
|
||||||
|
placement="bottomRight"
|
||||||
|
>
|
||||||
|
<Button icon={<Ellipsis size={14} />} type="text" className="icons" />
|
||||||
|
</Popover>
|
||||||
|
{!isDashboardLocked && editDashboard && (
|
||||||
|
<SettingsDrawer drawerTitle="Dashboard Configuration" />
|
||||||
)}
|
)}
|
||||||
|
{!isDashboardLocked && addPanelPermission && (
|
||||||
|
<Button
|
||||||
|
className="add-panel-btn"
|
||||||
|
onClick={onEmptyWidgetHandler}
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
type="primary"
|
||||||
|
data-testid="add-panel"
|
||||||
|
>
|
||||||
|
New Panel
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{(tags?.length || 0) > 0 && (
|
||||||
|
<div className="dashboard-tags">
|
||||||
|
{tags?.map((tag) => (
|
||||||
|
<Tag key={tag} className="tag">
|
||||||
|
{tag}
|
||||||
|
</Tag>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!isEmpty(description) && (
|
||||||
|
<section className="dashboard-description-section">{description}</section>
|
||||||
|
)}
|
||||||
|
<section className="dashboard-variables">
|
||||||
|
<DashboardVariableSelection />
|
||||||
|
</section>
|
||||||
|
<DashboardGraphSlider />
|
||||||
|
|
||||||
<div className="dashboard-actions">
|
<Modal
|
||||||
{!isDashboardLocked && editDashboard && (
|
open={isRenameDashboardOpen}
|
||||||
<SettingsDrawer drawerTitle={title} />
|
title="Rename Dashboard"
|
||||||
)}
|
onOk={(): void => {
|
||||||
|
// handle update dashboard here
|
||||||
<Tooltip title="Share" placement="left">
|
}}
|
||||||
<Button
|
onCancel={(): void => {
|
||||||
className="periscope-btn"
|
setIsRenameDashboardOpen(false);
|
||||||
style={{ width: '100%' }}
|
}}
|
||||||
onClick={onToggleHandler}
|
rootClassName="rename-dashboard"
|
||||||
icon={<Share2 size={16} />}
|
footer={
|
||||||
/>
|
<div className="dashboard-rename">
|
||||||
</Tooltip>
|
<Button
|
||||||
|
type="primary"
|
||||||
{(isAuthor || role === USER_ROLES.ADMIN) && (
|
icon={<Check size={14} />}
|
||||||
<Tooltip
|
className="rename-btn"
|
||||||
placement="left"
|
onClick={onNameChangeHandler}
|
||||||
title={isDashboardLocked ? 'Unlock Dashboard' : 'Lock Dashboard'}
|
disabled={updateDashboardMutation.isLoading}
|
||||||
>
|
>
|
||||||
<Button
|
Rename Dashboard
|
||||||
style={{ width: '100%' }}
|
</Button>
|
||||||
className="periscope-btn"
|
<Button
|
||||||
onClick={handleLockDashboardToggle}
|
type="text"
|
||||||
icon={isDashboardLocked ? <LockFilled /> : <UnlockFilled />}
|
icon={<X size={14} />}
|
||||||
/>
|
className="cancel-btn"
|
||||||
</Tooltip>
|
onClick={(): void => setIsRenameDashboardOpen(false)}
|
||||||
)}
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
}
|
||||||
</Row>
|
>
|
||||||
|
<div className="dashboard-content">
|
||||||
|
<Typography.Text className="name-text">Enter a new name</Typography.Text>
|
||||||
|
<Input
|
||||||
|
data-testid="dashboard-name"
|
||||||
|
className="dashboard-name-input"
|
||||||
|
value={updatedTitle}
|
||||||
|
onChange={(e): void => setUpdatedTitle(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
open={isPanelNameModalOpen}
|
||||||
|
title="New Section"
|
||||||
|
rootClassName="section-naming"
|
||||||
|
onOk={(): void => handleAddRow()}
|
||||||
|
onCancel={(): void => {
|
||||||
|
setIsPanelNameModalOpen(false);
|
||||||
|
setSectionName(DEFAULT_ROW_NAME);
|
||||||
|
}}
|
||||||
|
footer={
|
||||||
|
<div className="dashboard-rename">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<Check size={14} />}
|
||||||
|
className="rename-btn"
|
||||||
|
onClick={(): void => handleAddRow()}
|
||||||
|
disabled={updateDashboardMutation.isLoading}
|
||||||
|
>
|
||||||
|
Create Section
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<X size={14} />}
|
||||||
|
className="cancel-btn"
|
||||||
|
onClick={(): void => {
|
||||||
|
setIsPanelNameModalOpen(false);
|
||||||
|
setSectionName(DEFAULT_ROW_NAME);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div className="section-naming-content">
|
||||||
|
<Typography.Text className="name-text">Enter Section name</Typography.Text>
|
||||||
|
<Input
|
||||||
|
data-testid="section-name"
|
||||||
|
className="section-name-input"
|
||||||
|
value={sectionName}
|
||||||
|
onChange={(e): void => setSectionName(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,3 +12,5 @@ export function downloadObjectAsJson(
|
|||||||
downloadAnchorNode.click();
|
downloadAnchorNode.click();
|
||||||
downloadAnchorNode.remove();
|
downloadAnchorNode.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_ROW_NAME = 'Sample Row';
|
||||||
|
|||||||
@@ -3,3 +3,134 @@
|
|||||||
color: rgb(207, 19, 34);
|
color: rgb(207, 19, 34);
|
||||||
font-style: italic;
|
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(--bg-robin-400);
|
||||||
|
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(--bg-sienna-400);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-slate-500);
|
||||||
|
background: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-cell::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody {
|
||||||
|
.ant-table-cell {
|
||||||
|
padding: 14px;
|
||||||
|
border: 1px solid var(--bg-slate-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-row {
|
||||||
|
.ant-table-cell:nth-child(even) {
|
||||||
|
background: rgba(22, 25, 34, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.dashboard-variable-settings-table {
|
||||||
|
.variable-description-actions {
|
||||||
|
.actions-btns {
|
||||||
|
.edit-variable-button {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-thead {
|
||||||
|
.ant-table-cell {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody {
|
||||||
|
.ant-table-cell {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-row {
|
||||||
|
.ant-table-cell:nth-child(even) {
|
||||||
|
background: var(--bg-vanilla-200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
.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);
|
||||||
|
transition: opacity 0.1s !important;
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.settings-tabs {
|
||||||
|
.ant-tabs-nav-list {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.ant-tabs-tab-active {
|
||||||
|
.overview-btn {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.variables-btn {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { PlusOutlined } from '@ant-design/icons';
|
import './AddTags.styles.scss';
|
||||||
import { Col, Tooltip, Typography } from 'antd';
|
|
||||||
|
import { Col, Tooltip } from 'antd';
|
||||||
import Input from 'components/Input';
|
import Input from 'components/Input';
|
||||||
import { Dispatch, SetStateAction, useState } from 'react';
|
import { Dispatch, SetStateAction, useState } from 'react';
|
||||||
|
|
||||||
@@ -7,7 +8,6 @@ import { InputContainer, NewTagContainer, TagsContainer } from './styles';
|
|||||||
|
|
||||||
function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
||||||
const [inputValue, setInputValue] = useState<string>('');
|
const [inputValue, setInputValue] = useState<string>('');
|
||||||
const [inputVisible, setInputVisible] = useState<boolean>(false);
|
|
||||||
const [editInputIndex, setEditInputIndex] = useState(-1);
|
const [editInputIndex, setEditInputIndex] = useState(-1);
|
||||||
const [editInputValue, setEditInputValue] = useState('');
|
const [editInputValue, setEditInputValue] = useState('');
|
||||||
|
|
||||||
@@ -15,7 +15,6 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
|||||||
if (inputValue) {
|
if (inputValue) {
|
||||||
setTags([...tags, inputValue]);
|
setTags([...tags, inputValue]);
|
||||||
}
|
}
|
||||||
setInputVisible(false);
|
|
||||||
setInputValue('');
|
setInputValue('');
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,10 +31,6 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
|||||||
setTags(newTags);
|
setTags(newTags);
|
||||||
};
|
};
|
||||||
|
|
||||||
const showInput = (): void => {
|
|
||||||
setInputVisible(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onChangeHandler = (
|
const onChangeHandler = (
|
||||||
value: string,
|
value: string,
|
||||||
func: Dispatch<SetStateAction<string>>,
|
func: Dispatch<SetStateAction<string>>,
|
||||||
@@ -48,7 +43,7 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
|||||||
{tags.map((tag, index) => {
|
{tags.map((tag, index) => {
|
||||||
if (editInputIndex === index) {
|
if (editInputIndex === index) {
|
||||||
return (
|
return (
|
||||||
<Col key={tag} lg={4}>
|
<Col key={tag} lg={4} className="edit-input">
|
||||||
<Input
|
<Input
|
||||||
size="small"
|
size="small"
|
||||||
value={editInputValue}
|
value={editInputValue}
|
||||||
@@ -65,7 +60,12 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
|||||||
const isLongTag = tag.length > 20;
|
const isLongTag = tag.length > 20;
|
||||||
|
|
||||||
const tagElem = (
|
const tagElem = (
|
||||||
<NewTagContainer closable key={tag} onClose={(): void => handleClose(tag)}>
|
<NewTagContainer
|
||||||
|
closable
|
||||||
|
key={tag}
|
||||||
|
onClose={(): void => handleClose(tag)}
|
||||||
|
className="tag-container"
|
||||||
|
>
|
||||||
<span
|
<span
|
||||||
onDoubleClick={(e): void => {
|
onDoubleClick={(e): void => {
|
||||||
setEditInputIndex(index);
|
setEditInputIndex(index);
|
||||||
@@ -87,32 +87,19 @@ function AddTags({ tags, setTags }: AddTagsProps): JSX.Element {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{inputVisible && (
|
<InputContainer>
|
||||||
<InputContainer lg={4}>
|
<Input
|
||||||
<Input
|
type="text"
|
||||||
type="text"
|
value={inputValue}
|
||||||
size="small"
|
rootClassName="tags-input"
|
||||||
value={inputValue}
|
placeholder="Start typing your tag name"
|
||||||
onChangeHandler={(event): void =>
|
onChangeHandler={(event): void =>
|
||||||
onChangeHandler(event.target.value, setInputValue)
|
onChangeHandler(event.target.value, setInputValue)
|
||||||
}
|
}
|
||||||
onBlurHandler={handleInputConfirm}
|
onBlurHandler={handleInputConfirm}
|
||||||
onPressEnterHandler={handleInputConfirm}
|
onPressEnterHandler={handleInputConfirm}
|
||||||
/>
|
/>
|
||||||
</InputContainer>
|
</InputContainer>
|
||||||
)}
|
|
||||||
|
|
||||||
{!inputVisible && (
|
|
||||||
<NewTagContainer icon={<PlusOutlined />} onClick={showInput}>
|
|
||||||
<Typography
|
|
||||||
style={{
|
|
||||||
fontSize: '12px',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
New Tag
|
|
||||||
</Typography>
|
|
||||||
</NewTagContainer>
|
|
||||||
)}
|
|
||||||
</TagsContainer>
|
</TagsContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import styled from 'styled-components';
|
|||||||
export const TagsContainer = styled.div`
|
export const TagsContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex-flow: wrap;
|
||||||
|
gap: 6px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const NewTagContainer = styled(Tag)`
|
export const NewTagContainer = styled(Tag)`
|
||||||
@@ -23,4 +25,6 @@ export const InputContainer = styled(Col)`
|
|||||||
> div {
|
> div {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
padding-left: 0px !important;
|
||||||
|
padding-right: 0px !important;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
.overview-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.overview-settings {
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid var(--bg-slate-500);
|
||||||
|
padding: 16px !important;
|
||||||
|
|
||||||
|
.name-icon-input {
|
||||||
|
display: flex;
|
||||||
|
.dashboard-image-input {
|
||||||
|
.ant-select-selector {
|
||||||
|
display: flex;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 6px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 2px 0px 0px 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
|
||||||
|
.ant-select-selection-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.list-item-image {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-robin-500);
|
||||||
|
box-shadow: 0px 0px 6px 0px rgba(78, 116, 248, 0.4);
|
||||||
|
}
|
||||||
|
.unsaved-changes {
|
||||||
|
color: var(--bg-robin-400);
|
||||||
|
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(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn {
|
||||||
|
margin: 0px !important;
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-image-input {
|
||||||
|
&.ant-select-dropdown {
|
||||||
|
padding: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-select-item {
|
||||||
|
padding: 0px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.ant-select-item-option-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.list-item-image {
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.overview-content {
|
||||||
|
.overview-settings {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.name-icon-input {
|
||||||
|
.dashboard-image-input {
|
||||||
|
.ant-select-selector {
|
||||||
|
border: 1px solid var(--bg-vanilla-200);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-name-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-200);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-name {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-text-area {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.overview-settings-footer {
|
||||||
|
border-top: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.unsaved {
|
||||||
|
.unsaved-dot {
|
||||||
|
background: var(--bg-robin-500);
|
||||||
|
}
|
||||||
|
.unsaved-changes {
|
||||||
|
color: var(--bg-robin-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.footer-action-btns {
|
||||||
|
.discard-btn {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
background-color: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn {
|
||||||
|
color: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,20 @@
|
|||||||
import { SaveOutlined } from '@ant-design/icons';
|
import './GeneralSettings.styles.scss';
|
||||||
import { Col, Input, Space, Typography } from 'antd';
|
|
||||||
|
import { Col, Input, Select, Space, Typography } from 'antd';
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import AddTags from 'container/NewDashboard/DashboardSettings/General/AddTags';
|
import AddTags from 'container/NewDashboard/DashboardSettings/General/AddTags';
|
||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
|
import { isEqual } from 'lodash-es';
|
||||||
|
import { Check, X } from 'lucide-react';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import { Button } from './styles';
|
import { Button } from './styles';
|
||||||
|
import { Base64Icons } from './utils';
|
||||||
|
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
function GeneralDashboardSettings(): JSX.Element {
|
function GeneralDashboardSettings(): JSX.Element {
|
||||||
const { selectedDashboard, setSelectedDashboard } = useDashboard();
|
const { selectedDashboard, setSelectedDashboard } = useDashboard();
|
||||||
@@ -17,13 +23,18 @@ function GeneralDashboardSettings(): JSX.Element {
|
|||||||
|
|
||||||
const selectedData = selectedDashboard?.data;
|
const selectedData = selectedDashboard?.data;
|
||||||
|
|
||||||
const { title = '', tags = [], description = '' } = selectedData || {};
|
const { title = '', tags = [], description = '', image = Base64Icons[0] } =
|
||||||
|
selectedData || {};
|
||||||
|
|
||||||
const [updatedTitle, setUpdatedTitle] = useState<string>(title);
|
const [updatedTitle, setUpdatedTitle] = useState<string>(title);
|
||||||
const [updatedTags, setUpdatedTags] = useState<string[]>(tags || []);
|
const [updatedTags, setUpdatedTags] = useState<string[]>(tags || []);
|
||||||
const [updatedDescription, setUpdatedDescription] = useState(
|
const [updatedDescription, setUpdatedDescription] = useState(
|
||||||
description || '',
|
description || '',
|
||||||
);
|
);
|
||||||
|
const [updatedImage, setUpdatedImage] = useState<string>(image);
|
||||||
|
const [numberOfUnsavedChanges, setNumberOfUnsavedChanges] = useState<number>(
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
const { t } = useTranslation('common');
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
@@ -40,6 +51,7 @@ function GeneralDashboardSettings(): JSX.Element {
|
|||||||
description: updatedDescription,
|
description: updatedDescription,
|
||||||
tags: updatedTags,
|
tags: updatedTags,
|
||||||
title: updatedTitle,
|
title: updatedTitle,
|
||||||
|
image: updatedImage,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -57,48 +69,138 @@ function GeneralDashboardSettings(): JSX.Element {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<Col>
|
let numberOfUnsavedChanges = 0;
|
||||||
<Space direction="vertical" style={{ width: '100%' }}>
|
if (!isEqual(updatedTitle, selectedData?.title)) {
|
||||||
<div>
|
numberOfUnsavedChanges += 1;
|
||||||
<Typography style={{ marginBottom: '0.5rem' }}>Name</Typography>
|
}
|
||||||
<Input
|
if (!isEqual(updatedDescription, selectedData?.description)) {
|
||||||
data-testid="dashboard-name"
|
numberOfUnsavedChanges += 1;
|
||||||
value={updatedTitle}
|
}
|
||||||
onChange={(e): void => setUpdatedTitle(e.target.value)}
|
if (!isEqual(updatedTags, selectedData?.tags)) {
|
||||||
/>
|
numberOfUnsavedChanges += 1;
|
||||||
</div>
|
}
|
||||||
|
if (!isEqual(updatedImage, selectedData?.image)) {
|
||||||
|
numberOfUnsavedChanges += 1;
|
||||||
|
}
|
||||||
|
setNumberOfUnsavedChanges(numberOfUnsavedChanges);
|
||||||
|
}, [
|
||||||
|
selectedData?.description,
|
||||||
|
selectedData?.image,
|
||||||
|
selectedData?.tags,
|
||||||
|
selectedData?.title,
|
||||||
|
updatedDescription,
|
||||||
|
updatedImage,
|
||||||
|
updatedTags,
|
||||||
|
updatedTitle,
|
||||||
|
]);
|
||||||
|
|
||||||
<div>
|
const discardHandler = (): void => {
|
||||||
<Typography style={{ marginBottom: '0.5rem' }}>Description</Typography>
|
setUpdatedTitle(title);
|
||||||
<Input.TextArea
|
setUpdatedImage(image);
|
||||||
data-testid="dashboard-desc"
|
setUpdatedTags(tags);
|
||||||
rows={5}
|
setUpdatedDescription(description);
|
||||||
value={updatedDescription}
|
};
|
||||||
onChange={(e): void => setUpdatedDescription(e.target.value)}
|
|
||||||
/>
|
return (
|
||||||
|
<div className="overview-content">
|
||||||
|
<Col className="overview-settings">
|
||||||
|
<Space
|
||||||
|
direction="vertical"
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '21px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Typography style={{ marginBottom: '0.5rem' }} className="dashboard-name">
|
||||||
|
Dashboard Name
|
||||||
|
</Typography>
|
||||||
|
<section className="name-icon-input">
|
||||||
|
<Select
|
||||||
|
defaultActiveFirstOption
|
||||||
|
data-testid="dashboard-image"
|
||||||
|
suffixIcon={null}
|
||||||
|
rootClassName="dashboard-image-input"
|
||||||
|
value={updatedImage}
|
||||||
|
onChange={(value: string): void => setUpdatedImage(value)}
|
||||||
|
>
|
||||||
|
{Base64Icons.map((icon) => (
|
||||||
|
<Option value={icon} key={icon}>
|
||||||
|
<img src={icon} alt="dashboard-icon" className="list-item-image" />
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<Input
|
||||||
|
data-testid="dashboard-name"
|
||||||
|
className="dashboard-name-input"
|
||||||
|
value={updatedTitle}
|
||||||
|
onChange={(e): void => setUpdatedTitle(e.target.value)}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Typography style={{ marginBottom: '0.5rem' }} className="dashboard-name">
|
||||||
|
Description
|
||||||
|
</Typography>
|
||||||
|
<Input.TextArea
|
||||||
|
data-testid="dashboard-desc"
|
||||||
|
rows={6}
|
||||||
|
value={updatedDescription}
|
||||||
|
className="description-text-area"
|
||||||
|
onChange={(e): void => setUpdatedDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Typography style={{ marginBottom: '0.5rem' }} className="dashboard-name">
|
||||||
|
Tags
|
||||||
|
</Typography>
|
||||||
|
<AddTags tags={updatedTags} setTags={setUpdatedTags} />
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</Col>
|
||||||
|
{numberOfUnsavedChanges > 0 && (
|
||||||
|
<div className="overview-settings-footer">
|
||||||
|
<div className="unsaved">
|
||||||
|
<div className="unsaved-dot" />
|
||||||
|
<Typography.Text className="unsaved-changes">
|
||||||
|
{numberOfUnsavedChanges} Unsaved change
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<div className="footer-action-btns">
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
margin: '16px 0',
|
||||||
|
}}
|
||||||
|
disabled={updateDashboardMutation.isLoading}
|
||||||
|
icon={<X size={14} />}
|
||||||
|
onClick={discardHandler}
|
||||||
|
type="text"
|
||||||
|
className="discard-btn"
|
||||||
|
>
|
||||||
|
Discard
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={{
|
||||||
|
margin: '16px 0',
|
||||||
|
}}
|
||||||
|
disabled={updateDashboardMutation.isLoading}
|
||||||
|
loading={updateDashboardMutation.isLoading}
|
||||||
|
icon={<Check size={14} />}
|
||||||
|
data-testid="save-dashboard-config"
|
||||||
|
onClick={onSaveHandler}
|
||||||
|
type="primary"
|
||||||
|
className="save-btn"
|
||||||
|
>
|
||||||
|
{t('save')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
)}
|
||||||
<Typography style={{ marginBottom: '0.5rem' }}>Tags</Typography>
|
</div>
|
||||||
<AddTags tags={updatedTags} setTags={setUpdatedTags} />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Button
|
|
||||||
style={{
|
|
||||||
margin: '16px 0',
|
|
||||||
}}
|
|
||||||
disabled={updateDashboardMutation.isLoading}
|
|
||||||
loading={updateDashboardMutation.isLoading}
|
|
||||||
icon={<SaveOutlined />}
|
|
||||||
data-testid="save-dashboard-config"
|
|
||||||
onClick={onSaveHandler}
|
|
||||||
type="primary"
|
|
||||||
>
|
|
||||||
{t('save')}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Space>
|
|
||||||
</Col>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -6,3 +6,485 @@
|
|||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.variable-item-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid var(--bg-slate-500);
|
||||||
|
|
||||||
|
.all-variables {
|
||||||
|
display: flex;
|
||||||
|
padding: 10px 16px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
.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% */
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-variables-btn:hover {
|
||||||
|
background-color: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-vanilla-400);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.variable-description-section {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-type-section {
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
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 var(--bg-slate-400);
|
||||||
|
}
|
||||||
|
.selected {
|
||||||
|
background: var(--bg-slate-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-values-section {
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
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(--bg-vanilla-400);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
|
||||||
|
.ant-select-selector {
|
||||||
|
width: 192px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiple-values-section {
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
.typography-variables {
|
||||||
|
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;
|
||||||
|
width: 339px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-option-section {
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
.typography-variables {
|
||||||
|
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;
|
||||||
|
width: 339px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-textbox-section {
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
width: 342px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-custom-section {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
.custom-collapse {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 3px 3px 0px 0px;
|
||||||
|
border: 1px solid var(--bg-slate-500);
|
||||||
|
|
||||||
|
.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(--bg-robin-400);
|
||||||
|
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(--bg-slate-500);
|
||||||
|
height: 108px;
|
||||||
|
margin-top: -20px;
|
||||||
|
border-collapse: collapse;
|
||||||
|
gap: 5px;
|
||||||
|
flex-flow: column;
|
||||||
|
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-robin-400);
|
||||||
|
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 {
|
||||||
|
height: 30px;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-slate-400);
|
||||||
|
background: var(--bg-slate-500);
|
||||||
|
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(--bg-robin-500);
|
||||||
|
background: var(--bg-robin-500);
|
||||||
|
width: 123px;
|
||||||
|
height: 34px;
|
||||||
|
padding: 4px 8px 4px 10px;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.variable-item-container {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.all-variables {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
.all-variables-btn {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-item-content {
|
||||||
|
.variable-name-section {
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.variable-description-section {
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-type-section {
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-slate-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-type-btn-group {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.variable-type-btn + .variable-type-btn {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-200);
|
||||||
|
}
|
||||||
|
.selected {
|
||||||
|
background: var(--bg-vanilla-200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-values-section {
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.typography-sort {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-select-selector {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
border: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.multiple-values-section {
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.all-option-section {
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-textbox-section {
|
||||||
|
.typography-variables {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.default-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-custom-section {
|
||||||
|
.custom-collapse {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-collapse-header {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variables-preview-section {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.preview-values {
|
||||||
|
.ant-tag {
|
||||||
|
color: var(--bg-slate-300);
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-item-footer {
|
||||||
|
.footer-btn-discard {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,20 +2,28 @@
|
|||||||
import './VariableItem.styles.scss';
|
import './VariableItem.styles.scss';
|
||||||
|
|
||||||
import { orange } from '@ant-design/colors';
|
import { orange } from '@ant-design/colors';
|
||||||
import { Button, Divider, 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 dashboardVariablesQuery from 'api/dashboard/variables/dashboardVariablesQuery';
|
||||||
|
import cx from 'classnames';
|
||||||
import Editor from 'components/Editor';
|
import Editor from 'components/Editor';
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
import { commaValuesParser } from 'lib/dashbaordVariables/customCommaValuesParser';
|
import { commaValuesParser } from 'lib/dashbaordVariables/customCommaValuesParser';
|
||||||
import sortValues from 'lib/dashbaordVariables/sortVariableValues';
|
import sortValues from 'lib/dashbaordVariables/sortVariableValues';
|
||||||
import { map } from 'lodash-es';
|
import { map } from 'lodash-es';
|
||||||
|
import {
|
||||||
|
ArrowLeft,
|
||||||
|
Check,
|
||||||
|
ClipboardType,
|
||||||
|
DatabaseZap,
|
||||||
|
LayoutList,
|
||||||
|
X,
|
||||||
|
} from 'lucide-react';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import {
|
import {
|
||||||
IDashboardVariable,
|
IDashboardVariable,
|
||||||
TSortVariableValuesType,
|
TSortVariableValuesType,
|
||||||
TVariableQueryType,
|
TVariableQueryType,
|
||||||
VariableQueryTypeArr,
|
|
||||||
VariableSortTypeArr,
|
VariableSortTypeArr,
|
||||||
} from 'types/api/dashboard/getAll';
|
} from 'types/api/dashboard/getAll';
|
||||||
import { v4 as generateUUID } from 'uuid';
|
import { v4 as generateUUID } from 'uuid';
|
||||||
@@ -79,7 +87,6 @@ function VariableItem({
|
|||||||
const [errorPreview, setErrorPreview] = useState<string | null>(null);
|
const [errorPreview, setErrorPreview] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPreviewValues([]);
|
|
||||||
if (queryType === 'CUSTOM') {
|
if (queryType === 'CUSTOM') {
|
||||||
setPreviewValues(
|
setPreviewValues(
|
||||||
sortValues(
|
sortValues(
|
||||||
@@ -88,6 +95,9 @@ function VariableItem({
|
|||||||
) as never,
|
) as never,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (queryType === 'QUERY') {
|
||||||
|
setPreviewValues((prev) => sortValues(prev, variableSortType) as never);
|
||||||
|
}
|
||||||
}, [
|
}, [
|
||||||
queryType,
|
queryType,
|
||||||
variableCustomValue,
|
variableCustomValue,
|
||||||
@@ -121,13 +131,16 @@ function VariableItem({
|
|||||||
|
|
||||||
// Fetches the preview values for the SQL variable query
|
// Fetches the preview values for the SQL variable query
|
||||||
const handleQueryResult = (response: any): void => {
|
const handleQueryResult = (response: any): void => {
|
||||||
if (response?.payload?.variableValues)
|
if (response?.payload?.variableValues) {
|
||||||
setPreviewValues(
|
setPreviewValues(
|
||||||
sortValues(
|
sortValues(
|
||||||
response.payload?.variableValues || [],
|
response.payload?.variableValues || [],
|
||||||
variableSortType,
|
variableSortType,
|
||||||
) as never,
|
) as never,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
setPreviewValues([]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const { isFetching: previewLoading, refetch: runQuery } = useQuery(
|
const { isFetching: previewLoading, refetch: runQuery } = useQuery(
|
||||||
@@ -169,219 +182,288 @@ function VariableItem({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="variable-item-container">
|
<>
|
||||||
<div className="variable-item-content">
|
<div className="variable-item-container">
|
||||||
<VariableItemRow>
|
<div className="all-variables">
|
||||||
<LabelContainer>
|
<Button
|
||||||
<Typography>Name</Typography>
|
type="text"
|
||||||
</LabelContainer>
|
className="all-variables-btn"
|
||||||
<div>
|
icon={<ArrowLeft size={14} />}
|
||||||
<Input
|
onClick={onCancel}
|
||||||
placeholder="Unique name of the variable"
|
|
||||||
style={{ width: 400 }}
|
|
||||||
value={variableName}
|
|
||||||
onChange={(e): void => {
|
|
||||||
setVariableName(e.target.value);
|
|
||||||
setErrorName(
|
|
||||||
!validateName(e.target.value) && e.target.value !== variableData.name,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<Typography.Text type="warning">
|
|
||||||
{errorName ? 'Variable name already exists' : ''}
|
|
||||||
</Typography.Text>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</VariableItemRow>
|
|
||||||
<VariableItemRow>
|
|
||||||
<LabelContainer>
|
|
||||||
<Typography>Description</Typography>
|
|
||||||
</LabelContainer>
|
|
||||||
|
|
||||||
<Input.TextArea
|
|
||||||
value={variableDescription}
|
|
||||||
placeholder="Write description of the variable"
|
|
||||||
style={{ width: 400 }}
|
|
||||||
onChange={(e): void => setVariableDescription(e.target.value)}
|
|
||||||
/>
|
|
||||||
</VariableItemRow>
|
|
||||||
<VariableItemRow>
|
|
||||||
<LabelContainer>
|
|
||||||
<Typography>Type</Typography>
|
|
||||||
</LabelContainer>
|
|
||||||
|
|
||||||
<Select
|
|
||||||
defaultActiveFirstOption
|
|
||||||
style={{ width: 400 }}
|
|
||||||
onChange={(e: TVariableQueryType): void => {
|
|
||||||
setQueryType(e);
|
|
||||||
}}
|
|
||||||
value={queryType}
|
|
||||||
>
|
>
|
||||||
<Option value={VariableQueryTypeArr[0]}>Query</Option>
|
All variables
|
||||||
<Option value={VariableQueryTypeArr[1]}>Textbox</Option>
|
</Button>
|
||||||
<Option value={VariableQueryTypeArr[2]}>Custom</Option>
|
</div>
|
||||||
</Select>
|
<div className="variable-item-content">
|
||||||
</VariableItemRow>
|
<VariableItemRow className="variable-name-section">
|
||||||
<Typography.Title
|
|
||||||
level={5}
|
|
||||||
style={{ marginTop: '1rem', marginBottom: '1rem' }}
|
|
||||||
>
|
|
||||||
Options
|
|
||||||
</Typography.Title>
|
|
||||||
{queryType === 'QUERY' && (
|
|
||||||
<div className="query-container">
|
|
||||||
<LabelContainer>
|
<LabelContainer>
|
||||||
<Typography>Query</Typography>
|
<Typography className="typography-variables">Name</Typography>
|
||||||
</LabelContainer>
|
</LabelContainer>
|
||||||
|
<div>
|
||||||
<div style={{ flex: 1, position: 'relative' }}>
|
<Input
|
||||||
<Editor
|
placeholder="Unique name of the variable"
|
||||||
language="sql"
|
value={variableName}
|
||||||
value={variableQueryValue}
|
className="name-input"
|
||||||
onChange={(e): void => setVariableQueryValue(e)}
|
onChange={(e): void => {
|
||||||
height="240px"
|
setVariableName(e.target.value);
|
||||||
options={{
|
setErrorName(
|
||||||
fontSize: 13,
|
!validateName(e.target.value) && e.target.value !== variableData.name,
|
||||||
wordWrap: 'on',
|
);
|
||||||
lineNumbers: 'off',
|
|
||||||
glyphMargin: false,
|
|
||||||
folding: false,
|
|
||||||
lineDecorationsWidth: 0,
|
|
||||||
lineNumbersMinChars: 0,
|
|
||||||
minimap: {
|
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<div>
|
||||||
|
<Typography.Text type="warning">
|
||||||
|
{errorName ? 'Variable name already exists' : ''}
|
||||||
|
</Typography.Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VariableItemRow>
|
||||||
|
<VariableItemRow className="variable-description-section">
|
||||||
|
<LabelContainer>
|
||||||
|
<Typography className="typography-variables">Description</Typography>
|
||||||
|
</LabelContainer>
|
||||||
|
|
||||||
|
<Input.TextArea
|
||||||
|
value={variableDescription}
|
||||||
|
placeholder="Enter a description for the variable"
|
||||||
|
className="description-input"
|
||||||
|
rows={3}
|
||||||
|
onChange={(e): void => setVariableDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
</VariableItemRow>
|
||||||
|
<VariableItemRow className="variable-type-section">
|
||||||
|
<LabelContainer>
|
||||||
|
<Typography className="typography-variables">Variable Type</Typography>
|
||||||
|
</LabelContainer>
|
||||||
|
|
||||||
|
<div className="variable-type-btn-group">
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="text"
|
||||||
size="small"
|
icon={<DatabaseZap size={14} />}
|
||||||
onClick={handleTestRunQuery}
|
className={cx(
|
||||||
style={{
|
// eslint-disable-next-line sonarjs/no-duplicate-string
|
||||||
position: 'absolute',
|
'variable-type-btn',
|
||||||
bottom: 0,
|
queryType === 'QUERY' ? 'selected' : '',
|
||||||
|
)}
|
||||||
|
onClick={(): void => {
|
||||||
|
setQueryType('QUERY');
|
||||||
|
setPreviewValues([]);
|
||||||
}}
|
}}
|
||||||
loading={previewLoading}
|
|
||||||
>
|
>
|
||||||
Test Run Query
|
Query
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<ClipboardType size={14} />}
|
||||||
|
className={cx(
|
||||||
|
'variable-type-btn',
|
||||||
|
queryType === 'TEXTBOX' ? 'selected' : '',
|
||||||
|
)}
|
||||||
|
onClick={(): void => {
|
||||||
|
setQueryType('TEXTBOX');
|
||||||
|
setPreviewValues([]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Textbox
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<LayoutList size={14} />}
|
||||||
|
className={cx(
|
||||||
|
'variable-type-btn',
|
||||||
|
queryType === 'CUSTOM' ? 'selected' : '',
|
||||||
|
)}
|
||||||
|
onClick={(): void => {
|
||||||
|
setQueryType('CUSTOM');
|
||||||
|
setPreviewValues([]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Custom
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{queryType === 'CUSTOM' && (
|
|
||||||
<VariableItemRow>
|
|
||||||
<LabelContainer>
|
|
||||||
<Typography>Values separated by comma</Typography>
|
|
||||||
</LabelContainer>
|
|
||||||
<Input.TextArea
|
|
||||||
value={variableCustomValue}
|
|
||||||
placeholder="1, 10, mykey, mykey:myvalue"
|
|
||||||
style={{ width: 400 }}
|
|
||||||
onChange={(e): void => {
|
|
||||||
setVariableCustomValue(e.target.value);
|
|
||||||
setPreviewValues(
|
|
||||||
sortValues(
|
|
||||||
commaValuesParser(e.target.value),
|
|
||||||
variableSortType,
|
|
||||||
) as never,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</VariableItemRow>
|
</VariableItemRow>
|
||||||
)}
|
{queryType === 'QUERY' && (
|
||||||
{queryType === 'TEXTBOX' && (
|
<div className="query-container">
|
||||||
<VariableItemRow>
|
|
||||||
<LabelContainer>
|
|
||||||
<Typography>Default Value</Typography>
|
|
||||||
</LabelContainer>
|
|
||||||
<Input
|
|
||||||
value={variableTextboxValue}
|
|
||||||
onChange={(e): void => {
|
|
||||||
setVariableTextboxValue(e.target.value);
|
|
||||||
}}
|
|
||||||
placeholder="Default value if any"
|
|
||||||
style={{ width: 400 }}
|
|
||||||
/>
|
|
||||||
</VariableItemRow>
|
|
||||||
)}
|
|
||||||
{(queryType === 'QUERY' || queryType === 'CUSTOM') && (
|
|
||||||
<>
|
|
||||||
<VariableItemRow>
|
|
||||||
<LabelContainer>
|
<LabelContainer>
|
||||||
<Typography>Preview of Values</Typography>
|
<Typography>Query</Typography>
|
||||||
</LabelContainer>
|
|
||||||
<div style={{ flex: 1 }}>
|
|
||||||
{errorPreview ? (
|
|
||||||
<Typography style={{ color: orange[5] }}>{errorPreview}</Typography>
|
|
||||||
) : (
|
|
||||||
map(previewValues, (value, idx) => (
|
|
||||||
<Tag key={`${value}${idx}`}>{value.toString()}</Tag>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</VariableItemRow>
|
|
||||||
<VariableItemRow>
|
|
||||||
<LabelContainer>
|
|
||||||
<Typography>Sort</Typography>
|
|
||||||
</LabelContainer>
|
</LabelContainer>
|
||||||
|
|
||||||
<Select
|
<div style={{ flex: 1, position: 'relative' }}>
|
||||||
defaultActiveFirstOption
|
<Editor
|
||||||
style={{ width: 400 }}
|
language="sql"
|
||||||
defaultValue={VariableSortTypeArr[0]}
|
value={variableQueryValue}
|
||||||
value={variableSortType}
|
onChange={(e): void => setVariableQueryValue(e)}
|
||||||
onChange={(value: TSortVariableValuesType): void =>
|
height="240px"
|
||||||
setVariableSortType(value)
|
options={{
|
||||||
}
|
fontSize: 13,
|
||||||
>
|
wordWrap: 'on',
|
||||||
<Option value={VariableSortTypeArr[0]}>Disabled</Option>
|
lineNumbers: 'off',
|
||||||
<Option value={VariableSortTypeArr[1]}>Ascending</Option>
|
glyphMargin: false,
|
||||||
<Option value={VariableSortTypeArr[2]}>Descending</Option>
|
folding: false,
|
||||||
</Select>
|
lineDecorationsWidth: 0,
|
||||||
</VariableItemRow>
|
lineNumbersMinChars: 0,
|
||||||
<VariableItemRow>
|
minimap: {
|
||||||
<LabelContainer>
|
enabled: false,
|
||||||
<Typography>Enable multiple values to be checked</Typography>
|
},
|
||||||
</LabelContainer>
|
}}
|
||||||
<Switch
|
/>
|
||||||
checked={variableMultiSelect}
|
<Button
|
||||||
onChange={(e): void => {
|
type="primary"
|
||||||
setVariableMultiSelect(e);
|
size="small"
|
||||||
if (!e) {
|
onClick={handleTestRunQuery}
|
||||||
setVariableShowALLOption(false);
|
style={{
|
||||||
}
|
position: 'absolute',
|
||||||
}}
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
loading={previewLoading}
|
||||||
|
>
|
||||||
|
Test Run Query
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{queryType === 'CUSTOM' && (
|
||||||
|
<VariableItemRow className="variable-custom-section">
|
||||||
|
<Collapse
|
||||||
|
collapsible="header"
|
||||||
|
rootClassName="custom-collapse"
|
||||||
|
defaultActiveKey={['1']}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
label: 'Options',
|
||||||
|
children: (
|
||||||
|
<Input.TextArea
|
||||||
|
value={variableCustomValue}
|
||||||
|
placeholder="Enter options separated by commas."
|
||||||
|
rootClassName="comma-input"
|
||||||
|
onChange={(e): void => {
|
||||||
|
setVariableCustomValue(e.target.value);
|
||||||
|
setPreviewValues(
|
||||||
|
sortValues(
|
||||||
|
commaValuesParser(e.target.value),
|
||||||
|
variableSortType,
|
||||||
|
) as never,
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
/>
|
/>
|
||||||
</VariableItemRow>
|
</VariableItemRow>
|
||||||
{variableMultiSelect && (
|
)}
|
||||||
<VariableItemRow>
|
{queryType === 'TEXTBOX' && (
|
||||||
|
<VariableItemRow className="variable-textbox-section">
|
||||||
|
<LabelContainer>
|
||||||
|
<Typography className="typography-variables">Default Value</Typography>
|
||||||
|
</LabelContainer>
|
||||||
|
<Input
|
||||||
|
value={variableTextboxValue}
|
||||||
|
className="default-input"
|
||||||
|
onChange={(e): void => {
|
||||||
|
setVariableTextboxValue(e.target.value);
|
||||||
|
}}
|
||||||
|
placeholder="Enter a default value (if any)..."
|
||||||
|
style={{ width: 400 }}
|
||||||
|
/>
|
||||||
|
</VariableItemRow>
|
||||||
|
)}
|
||||||
|
{(queryType === 'QUERY' || queryType === 'CUSTOM') && (
|
||||||
|
<>
|
||||||
|
<VariableItemRow className="variables-preview-section">
|
||||||
|
<LabelContainer style={{ width: '100%' }}>
|
||||||
|
<Typography className="typography-variables">
|
||||||
|
Preview of Values
|
||||||
|
</Typography>
|
||||||
|
</LabelContainer>
|
||||||
|
<div className="preview-values">
|
||||||
|
{errorPreview ? (
|
||||||
|
<Typography style={{ color: orange[5] }}>{errorPreview}</Typography>
|
||||||
|
) : (
|
||||||
|
map(previewValues, (value, idx) => (
|
||||||
|
<Tag key={`${value}${idx}`}>{value.toString()}</Tag>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</VariableItemRow>
|
||||||
|
<VariableItemRow className="sort-values-section">
|
||||||
<LabelContainer>
|
<LabelContainer>
|
||||||
<Typography>Include an option for ALL values</Typography>
|
<Typography className="typography-variables">Sort Values</Typography>
|
||||||
|
<Typography className="typography-sort">
|
||||||
|
Sort the query output values
|
||||||
|
</Typography>
|
||||||
|
</LabelContainer>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
defaultActiveFirstOption
|
||||||
|
defaultValue={VariableSortTypeArr[0]}
|
||||||
|
value={variableSortType}
|
||||||
|
onChange={(value: TSortVariableValuesType): void =>
|
||||||
|
setVariableSortType(value)
|
||||||
|
}
|
||||||
|
className="sort-input"
|
||||||
|
>
|
||||||
|
<Option value={VariableSortTypeArr[0]}>Disabled</Option>
|
||||||
|
<Option value={VariableSortTypeArr[1]}>Ascending</Option>
|
||||||
|
<Option value={VariableSortTypeArr[2]}>Descending</Option>
|
||||||
|
</Select>
|
||||||
|
</VariableItemRow>
|
||||||
|
<VariableItemRow className="multiple-values-section">
|
||||||
|
<LabelContainer>
|
||||||
|
<Typography className="typography-variables">
|
||||||
|
Enable multiple values to be checked
|
||||||
|
</Typography>
|
||||||
</LabelContainer>
|
</LabelContainer>
|
||||||
<Switch
|
<Switch
|
||||||
checked={variableShowALLOption}
|
checked={variableMultiSelect}
|
||||||
onChange={(e): void => setVariableShowALLOption(e)}
|
onChange={(e): void => {
|
||||||
|
setVariableMultiSelect(e);
|
||||||
|
if (!e) {
|
||||||
|
setVariableShowALLOption(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</VariableItemRow>
|
</VariableItemRow>
|
||||||
)}
|
{variableMultiSelect && (
|
||||||
</>
|
<VariableItemRow className="all-option-section">
|
||||||
)}
|
<LabelContainer>
|
||||||
|
<Typography className="typography-variables">
|
||||||
|
Include an option for ALL values
|
||||||
|
</Typography>
|
||||||
|
</LabelContainer>
|
||||||
|
<Switch
|
||||||
|
checked={variableShowALLOption}
|
||||||
|
onChange={(e): void => setVariableShowALLOption(e)}
|
||||||
|
/>
|
||||||
|
</VariableItemRow>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="variable-item-footer">
|
<div className="variable-item-footer">
|
||||||
<Divider />
|
|
||||||
<VariableItemRow>
|
<VariableItemRow>
|
||||||
<Button type="primary" onClick={handleSave} disabled={errorName}>
|
<Button
|
||||||
Save
|
type="default"
|
||||||
|
onClick={onCancel}
|
||||||
|
icon={<X size={14} />}
|
||||||
|
className="footer-btn-discard"
|
||||||
|
>
|
||||||
|
Discard
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="default" onClick={onCancel}>
|
<Button
|
||||||
Cancel
|
type="primary"
|
||||||
|
onClick={handleSave}
|
||||||
|
disabled={errorName}
|
||||||
|
icon={<Check size={14} />}
|
||||||
|
className="footer-btn-save"
|
||||||
|
>
|
||||||
|
Save Variable
|
||||||
</Button>
|
</Button>
|
||||||
</VariableItemRow>
|
</VariableItemRow>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import '../DashboardSettings.styles.scss';
|
import '../DashboardSettings.styles.scss';
|
||||||
|
|
||||||
import { blue, red } from '@ant-design/colors';
|
import { HolderOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import { MenuOutlined, PlusOutlined } from '@ant-design/icons';
|
|
||||||
import type { DragEndEvent, UniqueIdentifier } from '@dnd-kit/core';
|
import type { DragEndEvent, UniqueIdentifier } from '@dnd-kit/core';
|
||||||
import {
|
import {
|
||||||
DndContext,
|
DndContext,
|
||||||
@@ -18,7 +17,7 @@ import { RowProps } from 'antd/lib';
|
|||||||
import { convertVariablesToDbFormat } from 'container/NewDashboard/DashboardVariablesSelection/util';
|
import { convertVariablesToDbFormat } from 'container/NewDashboard/DashboardVariablesSelection/util';
|
||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
import { useNotifications } from 'hooks/useNotifications';
|
||||||
import { PencilIcon, TrashIcon } from 'lucide-react';
|
import { PenLine, Trash2 } from 'lucide-react';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
@@ -53,25 +52,33 @@ function TableRow({ children, ...props }: RowProps): JSX.Element {
|
|||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
<tr {...props} ref={setNodeRef} style={style} {...attributes}>
|
<tr {...props} ref={setNodeRef} style={style} {...attributes}>
|
||||||
{React.Children.map(children, (child) => {
|
{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, {
|
return React.cloneElement(child as React.ReactElement, {
|
||||||
children: (
|
children: (
|
||||||
<MenuOutlined
|
<div className="variable-name-drag">
|
||||||
ref={setActivatorNodeRef}
|
<HolderOutlined
|
||||||
style={{ touchAction: 'none', cursor: 'move' }}
|
ref={setActivatorNodeRef}
|
||||||
// eslint-disable-next-line react/jsx-props-no-spreading
|
style={{ touchAction: 'none', cursor: 'move' }}
|
||||||
{...listeners}
|
// eslint-disable-next-line react/jsx-props-no-spreading
|
||||||
/>
|
{...listeners}
|
||||||
|
/>
|
||||||
|
{child}
|
||||||
|
</div>
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
})}
|
})}
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function VariablesSetting(): JSX.Element {
|
function VariablesSetting({
|
||||||
|
variableViewModeRef,
|
||||||
|
}: {
|
||||||
|
variableViewModeRef: React.MutableRefObject<(() => void) | undefined>;
|
||||||
|
}): JSX.Element {
|
||||||
const variableToDelete = useRef<IDashboardVariable | null>(null);
|
const variableToDelete = useRef<IDashboardVariable | null>(null);
|
||||||
const [deleteVariableModal, setDeleteVariableModal] = useState(false);
|
const [deleteVariableModal, setDeleteVariableModal] = useState(false);
|
||||||
|
|
||||||
@@ -111,6 +118,13 @@ function VariablesSetting(): JSX.Element {
|
|||||||
setVariableViewMode(viewType);
|
setVariableViewMode(viewType);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (variableViewModeRef) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
variableViewModeRef.current = onDoneVariableViewMode;
|
||||||
|
}
|
||||||
|
}, [variableViewModeRef]);
|
||||||
|
|
||||||
const updateMutation = useUpdateDashboard();
|
const updateMutation = useUpdateDashboard();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -245,47 +259,42 @@ function VariablesSetting(): JSX.Element {
|
|||||||
!existingVariableNamesMap[name];
|
!existingVariableNamesMap[name];
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
|
||||||
key: 'sort',
|
|
||||||
width: '10%',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: 'Variable',
|
title: 'Variable',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
width: '40%',
|
width: '50%',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Description',
|
title: 'Description',
|
||||||
dataIndex: 'description',
|
width: '50%',
|
||||||
width: '35%',
|
|
||||||
key: 'description',
|
key: 'description',
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Actions',
|
|
||||||
width: '15%',
|
|
||||||
key: 'action',
|
|
||||||
render: (variable: IDashboardVariable): JSX.Element => (
|
render: (variable: IDashboardVariable): JSX.Element => (
|
||||||
<Space>
|
<div className="variable-description-actions">
|
||||||
<Button
|
<Typography.Text className="variable-description">
|
||||||
type="text"
|
{variable.description}
|
||||||
style={{ padding: 8, cursor: 'pointer', color: blue[5] }}
|
</Typography.Text>
|
||||||
onClick={(): void => onVariableViewModeEnter('EDIT', variable)}
|
<Space className="actions-btns">
|
||||||
>
|
<Button
|
||||||
<PencilIcon size={14} />
|
type="text"
|
||||||
</Button>
|
onClick={(): void => onVariableViewModeEnter('EDIT', variable)}
|
||||||
<Button
|
className="edit-variable-button"
|
||||||
type="text"
|
>
|
||||||
style={{ padding: 8, color: red[6], cursor: 'pointer' }}
|
<PenLine size={14} />
|
||||||
onClick={(): void => {
|
</Button>
|
||||||
if (variable) {
|
<Button
|
||||||
onVariableDeleteHandler(variable);
|
type="text"
|
||||||
}
|
onClick={(): void => {
|
||||||
}}
|
if (variable) {
|
||||||
>
|
onVariableDeleteHandler(variable);
|
||||||
<TrashIcon size={14} />
|
}
|
||||||
</Button>
|
}}
|
||||||
</Space>
|
className="delete-variable-button"
|
||||||
|
>
|
||||||
|
<Trash2 size={14} />
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -353,6 +362,10 @@ function VariablesSetting(): JSX.Element {
|
|||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'flex-end',
|
justifyContent: 'flex-end',
|
||||||
padding: '0.5rem 0',
|
padding: '0.5rem 0',
|
||||||
|
position: 'absolute',
|
||||||
|
top: '-56px',
|
||||||
|
right: '0px',
|
||||||
|
zIndex: '1',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
@@ -385,6 +398,7 @@ function VariablesSetting(): JSX.Element {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
dataSource={variablesTableData}
|
dataSource={variablesTableData}
|
||||||
|
className="dashboard-variable-settings-table"
|
||||||
/>
|
/>
|
||||||
</SortableContext>
|
</SortableContext>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
|
|||||||
@@ -1,19 +1,38 @@
|
|||||||
import { Tabs } from 'antd';
|
import './DashboardSettingsContent.styles.scss';
|
||||||
|
|
||||||
|
import { Button, Tabs } from 'antd';
|
||||||
|
import { Braces, Table } from 'lucide-react';
|
||||||
|
|
||||||
import GeneralDashboardSettings from './General';
|
import GeneralDashboardSettings from './General';
|
||||||
import VariablesSetting from './Variables';
|
import VariablesSetting from './Variables';
|
||||||
|
|
||||||
function DashboardSettingsContent(): JSX.Element {
|
function DashboardSettingsContent({
|
||||||
|
variableViewModeRef,
|
||||||
|
}: {
|
||||||
|
variableViewModeRef: React.MutableRefObject<(() => void) | undefined>;
|
||||||
|
}): JSX.Element {
|
||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
label: 'General',
|
label: (
|
||||||
|
<Button type="text" icon={<Table size="14" />} className="overview-btn">
|
||||||
|
Overview
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
key: 'general',
|
key: 'general',
|
||||||
children: <GeneralDashboardSettings />,
|
children: <GeneralDashboardSettings />,
|
||||||
},
|
},
|
||||||
{ label: 'Variables', key: 'variables', children: <VariablesSetting /> },
|
{
|
||||||
|
label: (
|
||||||
|
<Button type="text" icon={<Braces size={14} />} className="variables-btn">
|
||||||
|
Variables
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
key: 'variables',
|
||||||
|
children: <VariablesSetting variableViewModeRef={variableViewModeRef} />,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return <Tabs items={items} animated />;
|
return <Tabs items={items} animated className="settings-tabs" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DashboardSettingsContent;
|
export default DashboardSettingsContent;
|
||||||
|
|||||||
@@ -1,16 +1,63 @@
|
|||||||
.variable-name {
|
|
||||||
font-size: 0.8rem;
|
|
||||||
min-width: 100px;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.variable-item {
|
.variable-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.variable-name {
|
||||||
|
display: flex;
|
||||||
|
min-width: 56px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: 2px 0px 0px 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
color: var(--bg-robin-300);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
border-left: none;
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
}
|
||||||
|
|
||||||
.variable-select {
|
.variable-select {
|
||||||
.ant-select-dropdown {
|
.ant-select-dropdown {
|
||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.variable-item {
|
||||||
|
.variable-name {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
color: var(--bg-robin-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-value {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ function DashboardVariableSelection(): JSX.Element | null {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row style={{ display: 'flex', gap: '12px' }}>
|
||||||
{orderBasedSortedVariables &&
|
{orderBasedSortedVariables &&
|
||||||
Array.isArray(orderBasedSortedVariables) &&
|
Array.isArray(orderBasedSortedVariables) &&
|
||||||
orderBasedSortedVariables.length > 0 &&
|
orderBasedSortedVariables.length > 0 &&
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { VariableResponseProps } from 'types/api/dashboard/variables/query';
|
|||||||
import { popupContainer } from 'utils/selectPopupContainer';
|
import { popupContainer } from 'utils/selectPopupContainer';
|
||||||
|
|
||||||
import { variablePropsToPayloadVariables } from '../utils';
|
import { variablePropsToPayloadVariables } from '../utils';
|
||||||
import { SelectItemStyle, VariableContainer, VariableValue } from './styles';
|
import { SelectItemStyle } from './styles';
|
||||||
import { areArraysEqual } from './util';
|
import { areArraysEqual } from './util';
|
||||||
|
|
||||||
const ALL_SELECT_VALUE = '__ALL__';
|
const ALL_SELECT_VALUE = '__ALL__';
|
||||||
@@ -214,11 +214,11 @@ function VariableItem({
|
|||||||
}, [variableData.type, variableData.customValue]);
|
}, [variableData.type, variableData.customValue]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VariableContainer className="variable-item">
|
<div className="variable-item">
|
||||||
<Typography.Text className="variable-name" ellipsis>
|
<Typography.Text className="variable-name" ellipsis>
|
||||||
${variableData.name}
|
${variableData.name}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
<VariableValue>
|
<div className="variable-value">
|
||||||
{variableData.type === 'TEXTBOX' ? (
|
{variableData.type === 'TEXTBOX' ? (
|
||||||
<Input
|
<Input
|
||||||
placeholder="Enter value"
|
placeholder="Enter value"
|
||||||
@@ -283,8 +283,8 @@ function VariableItem({
|
|||||||
</Popover>
|
</Popover>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</VariableValue>
|
</div>
|
||||||
</VariableContainer>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import GridGraphLayout from 'container/GridCardLayout';
|
import GridGraphLayout from 'container/GridCardLayout';
|
||||||
import ComponentsSlider from 'container/NewDashboard/ComponentsSlider';
|
import { FullScreenHandle } from 'react-full-screen';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
|
||||||
|
|
||||||
import { GridComponentSliderContainer } from './styles';
|
import { GridComponentSliderContainer } from './styles';
|
||||||
|
|
||||||
function GridGraphs(): JSX.Element {
|
interface GridGraphsProps {
|
||||||
const { isDashboardSliderOpen } = useDashboard();
|
handle: FullScreenHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
function GridGraphs(props: GridGraphsProps): JSX.Element {
|
||||||
|
const { handle } = props;
|
||||||
return (
|
return (
|
||||||
<GridComponentSliderContainer>
|
<GridComponentSliderContainer>
|
||||||
{isDashboardSliderOpen && <ComponentsSlider />}
|
<GridGraphLayout handle={handle} />
|
||||||
|
|
||||||
<GridGraphLayout />
|
|
||||||
</GridComponentSliderContainer>
|
</GridComponentSliderContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
|
import { useFullScreenHandle } from 'react-full-screen';
|
||||||
|
|
||||||
import Description from './DashboardDescription';
|
import Description from './DashboardDescription';
|
||||||
import GridGraphs from './GridGraphs';
|
import GridGraphs from './GridGraphs';
|
||||||
|
|
||||||
function NewDashboard(): JSX.Element {
|
function NewDashboard(): JSX.Element {
|
||||||
|
const handle = useFullScreenHandle();
|
||||||
return (
|
return (
|
||||||
<>
|
<div style={{ overflowX: 'hidden' }}>
|
||||||
<Description />
|
<Description handle={handle} />
|
||||||
<GridGraphs />
|
<GridGraphs handle={handle} />
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
.query-section-left-container {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid var(--Slate-400, #1d212d);
|
||||||
|
background: var(--Ink-500, #0b0c0e);
|
||||||
|
|
||||||
|
.ant-card-body {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.query-section-left-container {
|
||||||
|
border-top: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
.query-header-container {
|
.query-header-container {
|
||||||
.action-btn {
|
padding: 0px 16px;
|
||||||
display: flex;
|
.action-btn {
|
||||||
align-items: center;
|
display: flex;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
}
|
justify-content: center;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ function ClickHouseQueryContainer(): JSX.Element | null {
|
|||||||
queryData={q}
|
queryData={q}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<QueryButton onClick={addQueryHandler} icon={<PlusOutlined />}>
|
<QueryButton
|
||||||
|
onClick={addQueryHandler}
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
style={{ margin: '0.4rem 1rem' }}
|
||||||
|
>
|
||||||
Query
|
Query
|
||||||
</QueryButton>
|
</QueryButton>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ function PromQLQueryContainer(): JSX.Element | null {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
)}
|
)}
|
||||||
<QueryButton onClick={addQueryHandler} icon={<PlusOutlined />}>
|
<QueryButton
|
||||||
|
onClick={addQueryHandler}
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
style={{ margin: '0.4rem 1rem' }}
|
||||||
|
>
|
||||||
Query
|
Query
|
||||||
</QueryButton>
|
</QueryButton>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -8,6 +8,15 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: 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 {
|
.prom-ql-icon {
|
||||||
height: 14px;
|
height: 14px;
|
||||||
@@ -17,6 +26,7 @@
|
|||||||
}
|
}
|
||||||
.ant-btn-default {
|
.ant-btn-default {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ant-tabs-tab-active {
|
.ant-tabs-tab-active {
|
||||||
@@ -27,16 +37,26 @@
|
|||||||
|
|
||||||
.ant-tabs-nav {
|
.ant-tabs-nav {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
|
.ant-tabs-nav-wrap {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-tabs-extra-content {
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.ant-tabs-nav::before {
|
.ant-tabs-nav::before {
|
||||||
border-bottom: none !important;
|
border-bottom: none !important;
|
||||||
}
|
}
|
||||||
.ant-tabs-nav-list {
|
.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 {
|
.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 {
|
.stage-run-query {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -46,11 +66,16 @@
|
|||||||
|
|
||||||
.lightMode {
|
.lightMode {
|
||||||
.dashboard-navigation {
|
.dashboard-navigation {
|
||||||
|
.nav-btns {
|
||||||
|
color: var(---bg-ink-300);
|
||||||
|
background-color: var(--bg-vanilla-200);
|
||||||
|
}
|
||||||
.ant-tabs-nav-list {
|
.ant-tabs-nav-list {
|
||||||
border: 1px solid var(--bg-vanilla-300);
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
}
|
}
|
||||||
.ant-tabs-tab + .ant-tabs-tab {
|
.ant-tabs-tab + .ant-tabs-tab {
|
||||||
border-left: 1px solid var(--bg-vanilla-200) !important;
|
border-left: 1px solid var(--bg-vanilla-100) !important;
|
||||||
}
|
}
|
||||||
.ant-tabs-tab-active {
|
.ant-tabs-tab-active {
|
||||||
.nav-btns {
|
.nav-btns {
|
||||||
|
|||||||
@@ -147,11 +147,10 @@ function QuerySection({
|
|||||||
{
|
{
|
||||||
key: EQueryType.QUERY_BUILDER,
|
key: EQueryType.QUERY_BUILDER,
|
||||||
label: (
|
label: (
|
||||||
<Tooltip title="Query Builder">
|
<Button className="nav-btns">
|
||||||
<Button className="nav-btns">
|
<Atom size={14} />
|
||||||
<Atom size={14} />
|
<Typography>Query Builder</Typography>
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
|
||||||
),
|
),
|
||||||
tab: <Typography>Query Builder</Typography>,
|
tab: <Typography>Query Builder</Typography>,
|
||||||
children: (
|
children: (
|
||||||
@@ -169,11 +168,10 @@ function QuerySection({
|
|||||||
{
|
{
|
||||||
key: EQueryType.QUERY_BUILDER,
|
key: EQueryType.QUERY_BUILDER,
|
||||||
label: (
|
label: (
|
||||||
<Tooltip title="Query Builder">
|
<Button className="nav-btns">
|
||||||
<Button className="nav-btns">
|
<Atom size={14} />
|
||||||
<Atom size={14} />
|
<Typography>Query Builder</Typography>
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
|
||||||
),
|
),
|
||||||
tab: <Typography>Query Builder</Typography>,
|
tab: <Typography>Query Builder</Typography>,
|
||||||
children: (
|
children: (
|
||||||
@@ -187,11 +185,10 @@ function QuerySection({
|
|||||||
{
|
{
|
||||||
key: EQueryType.CLICKHOUSE,
|
key: EQueryType.CLICKHOUSE,
|
||||||
label: (
|
label: (
|
||||||
<Tooltip title="ClickHouse">
|
<Button className="nav-btns">
|
||||||
<Button className="nav-btns">
|
<Terminal size={14} />
|
||||||
<Terminal size={14} />
|
<Typography>ClickHouse Query</Typography>
|
||||||
</Button>
|
</Button>
|
||||||
</Tooltip>
|
|
||||||
),
|
),
|
||||||
tab: <Typography>ClickHouse Query</Typography>,
|
tab: <Typography>ClickHouse Query</Typography>,
|
||||||
children: <ClickHouseQueryContainer />,
|
children: <ClickHouseQueryContainer />,
|
||||||
|
|||||||
@@ -1,28 +1,14 @@
|
|||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
|
|
||||||
import { Tag } from '../styles';
|
|
||||||
|
|
||||||
function QueryTypeTag({ queryType }: IQueryTypeTagProps): JSX.Element {
|
function QueryTypeTag({ queryType }: IQueryTypeTagProps): JSX.Element {
|
||||||
switch (queryType) {
|
switch (queryType) {
|
||||||
case EQueryType.QUERY_BUILDER:
|
case EQueryType.QUERY_BUILDER:
|
||||||
return (
|
return <span>Query Builder</span>;
|
||||||
<span>
|
|
||||||
<Tag color="geekblue">Query Builder</Tag>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
|
|
||||||
case EQueryType.CLICKHOUSE:
|
case EQueryType.CLICKHOUSE:
|
||||||
return (
|
return <span>ClickHouse Query</span>;
|
||||||
<span>
|
|
||||||
<Tag color="orange">ClickHouse Query</Tag>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
case EQueryType.PROM:
|
case EQueryType.PROM:
|
||||||
return (
|
return <span>PromQL</span>;
|
||||||
<span>
|
|
||||||
<Tag color="green">PromQL</Tag>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return <span />;
|
return <span />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
|
import { Spline } from 'lucide-react';
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
|
|
||||||
import QueryTypeTag from '../QueryTypeTag';
|
import QueryTypeTag from '../QueryTypeTag';
|
||||||
import { PlotTagWrapperStyled } from './styles';
|
|
||||||
|
|
||||||
interface IPlotTagProps {
|
interface IPlotTagProps {
|
||||||
queryType: EQueryType;
|
queryType: EQueryType;
|
||||||
@@ -15,9 +15,10 @@ function PlotTag({ queryType, panelType }: IPlotTagProps): JSX.Element | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlotTagWrapperStyled $panelType={panelType}>
|
<div className="plot-tag">
|
||||||
Plotted using <QueryTypeTag queryType={queryType} />
|
<Spline size={14} />
|
||||||
</PlotTagWrapperStyled>
|
Plotted with <QueryTypeTag queryType={queryType} />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
.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: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--Slate-400, #1d212d);
|
||||||
|
backdrop-filter: blur(6px);
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.widget-graph {
|
||||||
|
background-color: var(--bg-vanilla-100);
|
||||||
|
background-image: radial-gradient(var(--bg-vanilla-400) 1px, transparent 0);
|
||||||
|
background-size: 20px 20px;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
.plot-tag {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { QueryParams } from 'constants/query';
|
|||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import PanelWrapper from 'container/PanelWrapper/PanelWrapper';
|
import PanelWrapper from 'container/PanelWrapper/PanelWrapper';
|
||||||
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
import { CustomTimeType } from 'container/TopNav/DateTimeSelectionV2/config';
|
||||||
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||||
import GetMinMax from 'lib/getMinMax';
|
import GetMinMax from 'lib/getMinMax';
|
||||||
@@ -84,8 +85,24 @@ function WidgetGraph({
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={graphRef} style={{ height: '100%' }}>
|
<div
|
||||||
|
ref={graphRef}
|
||||||
|
style={{
|
||||||
|
height: '80%',
|
||||||
|
width: '80%',
|
||||||
|
margin: 'auto auto',
|
||||||
|
borderRadius: '3px',
|
||||||
|
border: isDarkMode
|
||||||
|
? '1px solid var(--bg-slate-500)'
|
||||||
|
: '1px solid var(--bg-vanilla-300)',
|
||||||
|
background: isDarkMode
|
||||||
|
? 'linear-gradient(0deg, rgba(171, 189, 255, 0.00) 0%, rgba(171, 189, 255, 0.00) 100%), #0B0C0E'
|
||||||
|
: 'var(--bg-vanilla-100)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
<PanelWrapper
|
<PanelWrapper
|
||||||
widget={selectedWidget}
|
widget={selectedWidget}
|
||||||
queryResponse={queryResponse}
|
queryResponse={queryResponse}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
import './WidgetGraph.styles.scss';
|
||||||
|
|
||||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||||
import { Card } from 'container/GridCardLayout/styles';
|
import { Card } from 'container/GridCardLayout/styles';
|
||||||
|
import DateTimeSelectionV2 from 'container/TopNav/DateTimeSelectionV2';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import { memo } from 'react';
|
import { memo } from 'react';
|
||||||
|
|
||||||
import { WidgetGraphContainerProps } from '../../types';
|
import { WidgetGraphContainerProps } from '../../types';
|
||||||
@@ -16,13 +20,22 @@ function WidgetGraph({
|
|||||||
}: WidgetGraphContainerProps): JSX.Element {
|
}: WidgetGraphContainerProps): JSX.Element {
|
||||||
const { currentQuery } = useQueryBuilder();
|
const { currentQuery } = useQueryBuilder();
|
||||||
|
|
||||||
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
if (selectedWidget === undefined) {
|
if (selectedWidget === undefined) {
|
||||||
return <Card $panelType={selectedGraph}>Invalid widget</Card>;
|
return (
|
||||||
|
<Card $panelType={selectedGraph} isDarkMode={isDarkMode}>
|
||||||
|
Invalid widget
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container $panelType={selectedGraph}>
|
<Container $panelType={selectedGraph} className="widget-graph">
|
||||||
<PlotTag queryType={currentQuery.queryType} panelType={selectedGraph} />
|
<div className="header">
|
||||||
|
<PlotTag queryType={currentQuery.queryType} panelType={selectedGraph} />
|
||||||
|
<DateTimeSelectionV2 showAutoRefresh={false} hideShareModal />
|
||||||
|
</div>
|
||||||
{queryResponse.error && (
|
{queryResponse.error && (
|
||||||
<AlertIconContainer color="red" title={queryResponse.error.message}>
|
<AlertIconContainer color="red" title={queryResponse.error.message}>
|
||||||
<InfoCircleOutlined />
|
<InfoCircleOutlined />
|
||||||
|
|||||||
@@ -12,13 +12,10 @@ export const Container = styled(Card)<Props>`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
padding: ${({ $panelType }): string =>
|
|
||||||
$panelType === PANEL_TYPES.TABLE || $panelType === PANEL_TYPES.LIST
|
|
||||||
? '0 0'
|
|
||||||
: '1.5rem 0'};
|
|
||||||
height: 60vh;
|
height: 60vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
padding: 0px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import './LeftContainer.styles.scss';
|
||||||
|
|
||||||
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
import { DEFAULT_ENTITY_VERSION } from 'constants/app';
|
||||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||||
@@ -97,7 +99,7 @@ function LeftContainer({
|
|||||||
setRequestData={setRequestData}
|
setRequestData={setRequestData}
|
||||||
selectedWidget={selectedWidget}
|
selectedWidget={selectedWidget}
|
||||||
/>
|
/>
|
||||||
<QueryContainer>
|
<QueryContainer className="query-section-left-container">
|
||||||
<QuerySection selectedGraph={selectedGraph} queryResponse={queryResponse} />
|
<QuerySection selectedGraph={selectedGraph} queryResponse={queryResponse} />
|
||||||
{selectedGraph === PANEL_TYPES.LIST && (
|
{selectedGraph === PANEL_TYPES.LIST && (
|
||||||
<ExplorerColumnsRenderer
|
<ExplorerColumnsRenderer
|
||||||
|
|||||||
@@ -3,11 +3,6 @@ import styled from 'styled-components';
|
|||||||
|
|
||||||
export const QueryContainer = styled(Card)`
|
export const QueryContainer = styled(Card)`
|
||||||
&&& {
|
&&& {
|
||||||
margin-top: 1rem;
|
|
||||||
min-height: 23.5%;
|
min-height: 23.5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-card-body {
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -2,3 +2,78 @@
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr max-content;
|
grid-template-columns: 1fr max-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-header {
|
||||||
|
display: flex;
|
||||||
|
height: 48px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
background: var(--bg-ink-500);
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0px 12px 0px 16px;
|
||||||
|
|
||||||
|
.left-header {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.discard-icon {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.configure-panel {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
letter-spacing: -0.07px;
|
||||||
|
border-left: 1px solid var(--bg-slate-500);
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn {
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
width: 121px;
|
||||||
|
padding: 4px 12px 4px 10px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--bg-robin-500);
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
text-align: center;
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 18px; /* 150% */
|
||||||
|
|
||||||
|
.ant-btn-icon {
|
||||||
|
margin-inline-end: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.edit-header {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-200);
|
||||||
|
|
||||||
|
.left-header {
|
||||||
|
.discard-icon {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.configure-panel {
|
||||||
|
color: var(--bg-slate-300);
|
||||||
|
border-left: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,414 @@
|
|||||||
|
.right-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
padding: 14px 14px 14px 12px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.purple-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: var(--bg-robin-400);
|
||||||
|
}
|
||||||
|
.header-text {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-description {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 12px 12px 16px 12px;
|
||||||
|
border-top: 1px solid var(--bg-slate-500);
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.typography {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px; /* 138.462% */
|
||||||
|
letter-spacing: 0.52px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-input {
|
||||||
|
display: flex;
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
flex: 1 0 0;
|
||||||
|
align-self: stretch;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px; /* 128.571% */
|
||||||
|
letter-spacing: -0.07px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-input {
|
||||||
|
border-style: unset;
|
||||||
|
.ant-input {
|
||||||
|
display: flex;
|
||||||
|
height: 80px;
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px; /* 128.571% */
|
||||||
|
letter-spacing: -0.07px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-config {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 12px 12px 16px 12px;
|
||||||
|
gap: 8px;
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
|
||||||
|
.typography {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px; /* 138.462% */
|
||||||
|
letter-spacing: 0.52px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-type-select {
|
||||||
|
.ant-select-selector {
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fill-gaps {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
padding: 12px;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
|
||||||
|
.fill-gaps-text {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px; /* 138.462% */
|
||||||
|
letter-spacing: 0.52px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-time-text {
|
||||||
|
margin-top: 16px;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px; /* 138.462% */
|
||||||
|
letter-spacing: 0.52px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.y-axis-unit-selector {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.heading {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 13px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 18px; /* 138.462% */
|
||||||
|
letter-spacing: 0.52px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
padding: 6px 6px 6px 8px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
align-self: stretch;
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
|
||||||
|
.ant-input {
|
||||||
|
background: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.soft-min-max {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-top: 4px;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
height: 32px;
|
||||||
|
align-items: center;
|
||||||
|
width: 50%;
|
||||||
|
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);
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
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: 50%;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
.input {
|
||||||
|
width: 50%;
|
||||||
|
border: none;
|
||||||
|
border-left: 1px solid var(--bg-slate-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alerts {
|
||||||
|
display: flex;
|
||||||
|
padding: 12px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid var(--bg-slate-500);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.left-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.bell-icon {
|
||||||
|
color: #c0c1c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alerts-text {
|
||||||
|
color: #c0c1c3;
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
letter-spacing: 0.14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.plus-icon {
|
||||||
|
color: #c0c1c3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-option {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
.icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.display {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.right-container {
|
||||||
|
background-color: var(--bg-vanilla-100);
|
||||||
|
.header {
|
||||||
|
.header-text {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-description {
|
||||||
|
border-top: 1px solid var(--bg-vanilla-300);
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.typography {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.description-input {
|
||||||
|
.ant-input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-config {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.typography {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-type-select {
|
||||||
|
.ant-select-selector {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-option {
|
||||||
|
.display {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.fill-gaps {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.fill-gaps-text {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-time-text {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.y-axis-unit-selector {
|
||||||
|
.heading {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-input {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.soft-min-max {
|
||||||
|
.container {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
.input {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alerts {
|
||||||
|
border-bottom: 1px solid var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.left-section {
|
||||||
|
.bell-icon {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.alerts-text {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.plus-icon {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-option {
|
||||||
|
.display {
|
||||||
|
color: var(--bg-ink-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,27 @@
|
|||||||
.color-selector-button {
|
.color-selector-space {
|
||||||
border: none;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-selector-light {
|
.color-selector-button {
|
||||||
border: 1px solid #d9d9d9;
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
box-shadow: none;
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.color-selector-button {
|
||||||
|
background-color: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
box-shadow: none;
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { DownOutlined } from '@ant-design/icons';
|
|||||||
import { Button, ColorPicker, Dropdown, Space } from 'antd';
|
import { Button, ColorPicker, Dropdown, Space } from 'antd';
|
||||||
import { Color } from 'antd/es/color-picker';
|
import { Color } from 'antd/es/color-picker';
|
||||||
import { MenuProps } from 'antd/lib';
|
import { MenuProps } from 'antd/lib';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
|
||||||
import useDebounce from 'hooks/useDebounce';
|
import useDebounce from 'hooks/useDebounce';
|
||||||
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
|
||||||
|
|
||||||
@@ -18,8 +17,6 @@ function ColorSelector({
|
|||||||
|
|
||||||
const debounceColor = useDebounce(colorFromPicker);
|
const debounceColor = useDebounce(colorFromPicker);
|
||||||
|
|
||||||
const isDarkMode = useIsDarkMode();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (debounceColor) {
|
if (debounceColor) {
|
||||||
setColor(debounceColor);
|
setColor(debounceColor);
|
||||||
@@ -69,11 +66,9 @@ function ColorSelector({
|
|||||||
<Dropdown menu={{ items }} trigger={['click']}>
|
<Dropdown menu={{ items }} trigger={['click']}>
|
||||||
<Button
|
<Button
|
||||||
onClick={(e): void => e.preventDefault()}
|
onClick={(e): void => e.preventDefault()}
|
||||||
className={
|
className="color-selector-button"
|
||||||
isDarkMode ? 'color-selector-button' : 'color-selector-button-light'
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Space>
|
<Space className="color-selector-space">
|
||||||
<CustomColor color={thresholdColor} />
|
<CustomColor color={thresholdColor} />
|
||||||
<DownOutlined />
|
<DownOutlined />
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -1,18 +1,29 @@
|
|||||||
.custom-color-container {
|
.custom-color-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 10px;
|
gap: 8px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.custom-color-typography-dark {
|
.custom-color-typography-dark {
|
||||||
color: #fff !important;
|
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 {
|
.custom-color-typography-light {
|
||||||
color: #000 !important;
|
color: #000 !important;
|
||||||
}
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
}
|
||||||
|
|
||||||
.custom-color-tag {
|
.custom-color-tag {
|
||||||
width: 20px;
|
width: 12px;
|
||||||
height: 20px;
|
height: 12px;
|
||||||
}
|
border-radius: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
.show-case-container {
|
.show-case-container {
|
||||||
padding: 5px 15px;
|
padding: 5px 15px;
|
||||||
border-radius: 5px;
|
display: inline-block;
|
||||||
display: inline-block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.show-case-dark {
|
.show-case-dark {
|
||||||
background-color: #141414;
|
background-color: #141414;
|
||||||
}
|
}
|
||||||
|
|
||||||
.show-case-light {
|
.show-case-light {
|
||||||
background-color: rgb(255, 255, 255);
|
background-color: rgb(255, 255, 255);
|
||||||
border: 1px solid #141414;
|
border: 1px solid #141414;
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,24 @@
|
|||||||
import './ShowCaseValue.styles.scss';
|
import './ShowCaseValue.styles.scss';
|
||||||
|
|
||||||
|
import cx from 'classnames';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
|
|
||||||
import { ShowCaseValueProps } from './types';
|
import { ShowCaseValueProps } from './types';
|
||||||
|
|
||||||
function ShowCaseValue({ width, value }: ShowCaseValueProps): JSX.Element {
|
function ShowCaseValue({
|
||||||
|
width,
|
||||||
|
value,
|
||||||
|
className = '',
|
||||||
|
}: ShowCaseValueProps): JSX.Element {
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={
|
className={cx(
|
||||||
isDarkMode
|
isDarkMode
|
||||||
? `show-case-container show-case-dark`
|
? `show-case-container show-case-dark`
|
||||||
: `show-case-container show-case-light`
|
: `show-case-container show-case-light`,
|
||||||
}
|
className,
|
||||||
|
)}
|
||||||
style={{ minWidth: width }}
|
style={{ minWidth: width }}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
|
|||||||
@@ -1,58 +1,427 @@
|
|||||||
.threshold-container {
|
.operator-input-root {
|
||||||
|
width: auto !important;
|
||||||
.threshold-card {
|
color: var(--bg-vanilla-400);
|
||||||
padding: 0px;
|
font-family: 'Space Mono';
|
||||||
border-radius: 10px;
|
font-size: 12px;
|
||||||
position: relative;
|
font-style: normal;
|
||||||
margin-top: 10px;
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
.threshold-card-container {
|
letter-spacing: 0.48px;
|
||||||
display: flex;
|
}
|
||||||
flex-direction: column;
|
.threshold-container {
|
||||||
gap: 10px;
|
margin-top: 12px;
|
||||||
}
|
|
||||||
|
.threshold-card-container {
|
||||||
.ant-typography {
|
display: flex;
|
||||||
font-size: 14px;
|
position: relative;
|
||||||
font-weight: 400;
|
flex-direction: column;
|
||||||
line-height: 22px;
|
align-items: flex-start;
|
||||||
}
|
gap: 12px;
|
||||||
|
flex-shrink: 0;
|
||||||
.ant-typograph-dark {
|
padding: 12px;
|
||||||
color: #FFFFFF73;
|
border-radius: 2px;
|
||||||
}
|
border: 1px solid var(--bg-slate-500);
|
||||||
|
background: var(--bg-ink-400);
|
||||||
.ant-typograph-light {
|
|
||||||
color: #00000073;
|
.edit-action-btns {
|
||||||
}
|
position: absolute;
|
||||||
|
right: -8px;
|
||||||
}
|
top: -14px;
|
||||||
|
display: none;
|
||||||
.threshold-card-dark {
|
|
||||||
background-color: #1F1F1F;
|
.ant-btn {
|
||||||
}
|
display: flex;
|
||||||
|
width: 24px;
|
||||||
.threshold-card-light {
|
height: 24px;
|
||||||
background-color: rgb(255, 255, 255);
|
padding: 4px;
|
||||||
}
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
.threshold-action-button {
|
gap: 10px;
|
||||||
position: absolute;
|
flex-shrink: 0;
|
||||||
right: 10px;
|
background: var(--bg-slate-400);
|
||||||
top: 10px;
|
}
|
||||||
}
|
|
||||||
|
.ant-btn + .ant-btn {
|
||||||
.threshold-action-icon {
|
border-left: 1px solid var(--bg-slate-200);
|
||||||
font-size: 16px;
|
}
|
||||||
}
|
|
||||||
|
.edit-btn {
|
||||||
.threshold-units-selector {
|
border-radius: 2px 0px 0px 2px;
|
||||||
display: flex;
|
}
|
||||||
align-items: center;
|
|
||||||
}
|
.delete-btn {
|
||||||
|
border-radius: 0px 2px 2px 0px;
|
||||||
.threshold-color-picker {
|
}
|
||||||
display: flex;
|
}
|
||||||
flex-direction: column;
|
|
||||||
}
|
.time-series-alerts {
|
||||||
|
display: flex;
|
||||||
|
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);
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
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(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-table-alerts {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.operator-input {
|
||||||
|
.ant-select-selector {
|
||||||
|
background-color: var(--bg-ink-300) !important;
|
||||||
|
min-width: 50px;
|
||||||
|
max-width: 150px;
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.typography {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
letter-spacing: 0.48px;
|
||||||
|
}
|
||||||
|
.typography-preview {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
letter-spacing: 0.48px;
|
||||||
|
background-color: var(--bg-ink-300) !important;
|
||||||
|
max-width: 150px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.threshold-units-selector {
|
||||||
|
display: flex;
|
||||||
|
border-radius: 2px 2px 0px 0px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
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;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-selection {
|
||||||
|
width: 50%;
|
||||||
|
border: none;
|
||||||
|
border-left: 1px solid var(--bg-slate-400);
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
|
||||||
|
.ant-select-selector {
|
||||||
|
border: none;
|
||||||
|
height: unset;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-selection-prev {
|
||||||
|
width: 50%;
|
||||||
|
border: none;
|
||||||
|
border-left: 1px solid var(--bg-slate-400);
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.thresholds-color-selector {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 0px 0px 2px 2px;
|
||||||
|
border: 1px solid var(--bg-slate-400);
|
||||||
|
border-top: none;
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
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: var(--bg-vanilla-100);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
|
||||||
|
.ant-btn {
|
||||||
|
box-shadow: none;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.color-format {
|
||||||
|
width: 50%;
|
||||||
|
border: none;
|
||||||
|
border-left: 1px solid var(--bg-slate-400);
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
|
||||||
|
.ant-select-selector {
|
||||||
|
border: none;
|
||||||
|
height: unset;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-format-prev {
|
||||||
|
width: 50%;
|
||||||
|
border: none;
|
||||||
|
border-left: 1px solid var(--bg-slate-400);
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
font-family: 'Space Mono';
|
||||||
|
font-size: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 16px; /* 133.333% */
|
||||||
|
background: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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(--bg-slate-400);
|
||||||
|
background: var(--bg-slate-500);
|
||||||
|
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(--bg-robin-500);
|
||||||
|
background: var(--bg-robin-500);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.threshold-card-container:hover {
|
||||||
|
.edit-action-btns {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.operator-input-root {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
.threshold-container {
|
||||||
|
.threshold-card-container {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.edit-action-btns {
|
||||||
|
.ant-btn {
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-btn + .ant-btn {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-series-alerts {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-100);
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-input {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.value-table-alerts {
|
||||||
|
.operator-input {
|
||||||
|
.ant-select-selector {
|
||||||
|
background-color: var(--bg-vanilla-300) !important;
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.typography {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
.typography-preview {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background-color: var(--bg-vanilla-300) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.threshold-units-selector {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.unit-input {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-selection {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-100);
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
|
||||||
|
.ant-select-selector {
|
||||||
|
background-color: var(--bg-vanilla-300);
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-selection-prev {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-100);
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.thresholds-color-selector {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
border-top: 1px solid var(--bg-vanilla-100);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
|
||||||
|
.color-selector {
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
border-top: 1px solid var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
.color-format {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-100);
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
|
||||||
|
.ant-select-selector {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-format-prev {
|
||||||
|
border-left: 1px solid var(--bg-vanilla-100);
|
||||||
|
color: var(--bg-ink-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.threshold-action-button {
|
||||||
|
.discard-btn {
|
||||||
|
border: 1px solid var(--bg-vanilla-300);
|
||||||
|
background: var(--bg-vanilla-300);
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-changes {
|
||||||
|
color: var(--bg-vanilla-100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,10 @@
|
|||||||
/* eslint-disable sonarjs/cognitive-complexity */
|
/* eslint-disable sonarjs/cognitive-complexity */
|
||||||
import './Threshold.styles.scss';
|
import './Threshold.styles.scss';
|
||||||
|
|
||||||
import { CheckOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
import { Button, Input, InputNumber, Select, Space, Typography } from 'antd';
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
Divider,
|
|
||||||
Input,
|
|
||||||
InputNumber,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
Typography,
|
|
||||||
} from 'antd';
|
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
|
import { Check, Pencil, Trash2, X } from 'lucide-react';
|
||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useDrag, useDrop, XYCoord } from 'react-dnd';
|
import { useDrag, useDrop, XYCoord } from 'react-dnd';
|
||||||
|
|
||||||
@@ -29,6 +21,7 @@ import { ThresholdProps } from './types';
|
|||||||
|
|
||||||
const wrapStyle = {
|
const wrapStyle = {
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
|
gap: '10px',
|
||||||
} as React.CSSProperties;
|
} as React.CSSProperties;
|
||||||
|
|
||||||
function Threshold({
|
function Threshold({
|
||||||
@@ -90,6 +83,16 @@ function Threshold({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const discardHandler = (): void => {
|
||||||
|
setIsEditMode(false);
|
||||||
|
setOperator(thresholdOperator);
|
||||||
|
setValue(thresholdValue);
|
||||||
|
setUnit(thresholdUnit);
|
||||||
|
setColor(thresholdColor);
|
||||||
|
setFormat(thresholdFormat);
|
||||||
|
setLabel(thresholdLabel);
|
||||||
|
setTableSelectedOption(thresholdTableOptions);
|
||||||
|
};
|
||||||
const editHandler = (): void => {
|
const editHandler = (): void => {
|
||||||
setIsEditMode(true);
|
setIsEditMode(true);
|
||||||
};
|
};
|
||||||
@@ -187,7 +190,6 @@ function Threshold({
|
|||||||
setLabel(event.target.value);
|
setLabel(event.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const backgroundColor = !isDarkMode ? '#ffffff' : '#141414';
|
|
||||||
const allowDragAndDrop = panelTypeVsDragAndDrop[selectedGraph];
|
const allowDragAndDrop = panelTypeVsDragAndDrop[selectedGraph];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -197,147 +199,165 @@ function Threshold({
|
|||||||
data-handler-id={handlerId}
|
data-handler-id={handlerId}
|
||||||
className="threshold-container"
|
className="threshold-container"
|
||||||
>
|
>
|
||||||
<Card
|
<div className="threshold-card-container">
|
||||||
className={
|
{!isEditMode && (
|
||||||
isDarkMode
|
<div className="edit-action-btns">
|
||||||
? `threshold-card threshold-card-dark`
|
<Button
|
||||||
: `threshold-card threshold-card-light`
|
type="text"
|
||||||
}
|
icon={<Pencil size={14} />}
|
||||||
>
|
className="edit-btn"
|
||||||
<div className="threshold-card-container">
|
onClick={editHandler}
|
||||||
<div className="threshold-action-button">
|
/>
|
||||||
{isEditMode ? (
|
<Button
|
||||||
<CheckOutlined onClick={saveHandler} />
|
type="text"
|
||||||
) : (
|
icon={<Trash2 size={14} />}
|
||||||
<EditOutlined className="threshold-action-icon" onClick={editHandler} />
|
className="delete-btn"
|
||||||
)}
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<DeleteOutlined
|
|
||||||
className="threshold-action-icon"
|
|
||||||
onClick={deleteHandler}
|
onClick={deleteHandler}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
)}
|
||||||
<Space
|
<div style={{ width: '100%' }}>
|
||||||
direction={
|
{selectedGraph === PANEL_TYPES.TIME_SERIES && (
|
||||||
selectedGraph === PANEL_TYPES.TABLE ? 'vertical' : 'horizontal'
|
<div className="time-series-alerts">
|
||||||
}
|
<Typography.Text className="label">Label</Typography.Text>
|
||||||
>
|
{isEditMode ? (
|
||||||
{selectedGraph === PANEL_TYPES.TIME_SERIES && (
|
<Input
|
||||||
<Space style={wrapStyle}>
|
defaultValue={label}
|
||||||
<Typography.Text>Label</Typography.Text>
|
onChange={handleLabelChange}
|
||||||
{isEditMode ? (
|
bordered={!isDarkMode}
|
||||||
<Input
|
className="label-input"
|
||||||
defaultValue={label}
|
/>
|
||||||
onChange={handleLabelChange}
|
) : (
|
||||||
bordered={!isDarkMode}
|
<ShowCaseValue value={label || 'none'} className="label-input" />
|
||||||
style={{ backgroundColor }}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ShowCaseValue width="180px" value={label || 'none'} />
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
)}
|
)}
|
||||||
{(selectedGraph === PANEL_TYPES.VALUE ||
|
</div>
|
||||||
selectedGraph === PANEL_TYPES.TABLE) && (
|
)}
|
||||||
<>
|
{(selectedGraph === PANEL_TYPES.VALUE ||
|
||||||
<Typography.Text>
|
selectedGraph === PANEL_TYPES.TABLE) && (
|
||||||
If value {selectedGraph === PANEL_TYPES.TABLE ? 'in' : 'is'}
|
<div className="value-table-alerts">
|
||||||
</Typography.Text>
|
<Typography.Text className="typography">
|
||||||
{isEditMode ? (
|
If value {selectedGraph === PANEL_TYPES.TABLE ? 'in' : 'is'}
|
||||||
<>
|
</Typography.Text>
|
||||||
{selectedGraph === PANEL_TYPES.TABLE && (
|
{isEditMode ? (
|
||||||
<Space style={wrapStyle}>
|
<div>
|
||||||
<Select
|
{selectedGraph === PANEL_TYPES.TABLE && (
|
||||||
style={{
|
<Space style={wrapStyle}>
|
||||||
minWidth: '150px',
|
|
||||||
backgroundColor,
|
|
||||||
borderRadius: '5px',
|
|
||||||
}}
|
|
||||||
defaultValue={tableSelectedOption}
|
|
||||||
options={tableOptions}
|
|
||||||
bordered={!isDarkMode}
|
|
||||||
showSearch
|
|
||||||
onChange={handleTableOptionsChange}
|
|
||||||
/>
|
|
||||||
<Typography.Text>is</Typography.Text>
|
|
||||||
</Space>
|
|
||||||
)}
|
|
||||||
<Select
|
<Select
|
||||||
style={{ minWidth: '73px', backgroundColor }}
|
defaultValue={tableSelectedOption}
|
||||||
defaultValue={operator}
|
options={tableOptions}
|
||||||
options={operatorOptions}
|
|
||||||
onChange={handleOperatorChange}
|
|
||||||
bordered={!isDarkMode}
|
bordered={!isDarkMode}
|
||||||
|
showSearch
|
||||||
|
onChange={handleTableOptionsChange}
|
||||||
|
rootClassName="operator-input-root"
|
||||||
|
className="operator-input"
|
||||||
/>
|
/>
|
||||||
</>
|
<Typography.Text className="typography">is</Typography.Text>
|
||||||
) : (
|
</Space>
|
||||||
<>
|
|
||||||
{selectedGraph === PANEL_TYPES.TABLE && (
|
|
||||||
<Space style={wrapStyle}>
|
|
||||||
<ShowCaseValue width="150px" value={tableSelectedOption} />
|
|
||||||
<Typography.Text>is</Typography.Text>
|
|
||||||
</Space>
|
|
||||||
)}
|
|
||||||
<ShowCaseValue width="49px" value={operator} />
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</>
|
<Select
|
||||||
)}
|
defaultValue={operator}
|
||||||
</Space>
|
options={operatorOptions}
|
||||||
</div>
|
onChange={handleOperatorChange}
|
||||||
<div className="threshold-units-selector">
|
bordered={!isDarkMode}
|
||||||
<Space style={wrapStyle}>
|
style={{ marginLeft: '10px' }}
|
||||||
{isEditMode ? (
|
rootClassName="operator-input-root"
|
||||||
<InputNumber
|
className="operator-input"
|
||||||
style={{ backgroundColor }}
|
/>
|
||||||
defaultValue={value}
|
</div>
|
||||||
onChange={handleValueChange}
|
|
||||||
bordered={!isDarkMode}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<ShowCaseValue width="60px" value={value} />
|
<div>
|
||||||
|
{selectedGraph === PANEL_TYPES.TABLE && (
|
||||||
|
<Space>
|
||||||
|
<ShowCaseValue
|
||||||
|
value={tableSelectedOption}
|
||||||
|
className="typography-preview"
|
||||||
|
/>
|
||||||
|
<Typography.Text
|
||||||
|
className="typography"
|
||||||
|
style={{ marginRight: '10px' }}
|
||||||
|
>
|
||||||
|
is
|
||||||
|
</Typography.Text>
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
|
<ShowCaseValue
|
||||||
|
width="50px"
|
||||||
|
value={operator}
|
||||||
|
className="typography-preview"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{isEditMode ? (
|
</div>
|
||||||
<Select
|
)}
|
||||||
style={{ minWidth: '200px', backgroundColor }}
|
|
||||||
bordered={!isDarkMode}
|
|
||||||
defaultValue={unit}
|
|
||||||
options={unitOptions}
|
|
||||||
onChange={handleUnitChange}
|
|
||||||
showSearch
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ShowCaseValue width="200px" value={unit} />
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<Space direction="vertical">
|
|
||||||
<Typography.Text>Show with</Typography.Text>
|
|
||||||
<Space style={wrapStyle}>
|
|
||||||
{isEditMode ? (
|
|
||||||
<>
|
|
||||||
<ColorSelector setColor={setColor} thresholdColor={color} />
|
|
||||||
<Select
|
|
||||||
style={{ minWidth: '100px', backgroundColor }}
|
|
||||||
defaultValue={format}
|
|
||||||
options={showAsOptions}
|
|
||||||
onChange={handlerFormatChange}
|
|
||||||
bordered={!isDarkMode}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<ShowCaseValue width="120px" value={<CustomColor color={color} />} />
|
|
||||||
<ShowCaseValue width="100px" value={format} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Space>
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
<div className="threshold-units-selector">
|
||||||
|
{isEditMode ? (
|
||||||
|
<InputNumber
|
||||||
|
defaultValue={value}
|
||||||
|
onChange={handleValueChange}
|
||||||
|
className="unit-input"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<ShowCaseValue value={value} className="unit-input" />
|
||||||
|
)}
|
||||||
|
{isEditMode ? (
|
||||||
|
<Select
|
||||||
|
defaultValue={unit}
|
||||||
|
options={unitOptions}
|
||||||
|
onChange={handleUnitChange}
|
||||||
|
showSearch
|
||||||
|
className="unit-selection"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<ShowCaseValue value={unit} className="unit-selection-prev" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="thresholds-color-selector">
|
||||||
|
{isEditMode ? (
|
||||||
|
<>
|
||||||
|
<div className="color-selector">
|
||||||
|
<ColorSelector setColor={setColor} thresholdColor={color} />
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
defaultValue={format}
|
||||||
|
options={showAsOptions}
|
||||||
|
onChange={handlerFormatChange}
|
||||||
|
rootClassName="color-format"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ShowCaseValue
|
||||||
|
value={<CustomColor color={color} />}
|
||||||
|
className="color-selector"
|
||||||
|
/>
|
||||||
|
<ShowCaseValue
|
||||||
|
width="100px"
|
||||||
|
value={format}
|
||||||
|
className="color-format-prev"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{isEditMode && (
|
||||||
|
<div className="threshold-action-button">
|
||||||
|
<Button
|
||||||
|
className="discard-btn"
|
||||||
|
icon={<X size={14} />}
|
||||||
|
onClick={discardHandler}
|
||||||
|
>
|
||||||
|
Discard
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
className="save-changes"
|
||||||
|
icon={<Check size={14} />}
|
||||||
|
onClick={saveHandler}
|
||||||
|
>
|
||||||
|
Save Changes
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,53 @@
|
|||||||
.threshold-selector-container {
|
.threshold-selector-container {
|
||||||
.threshold-selector-button {
|
padding: 12px;
|
||||||
margin-top: 20px;
|
padding-bottom: 80px;
|
||||||
width: 100%;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 10px 0;
|
|
||||||
height: 50px;
|
|
||||||
border-color: #1C64F2;
|
|
||||||
color: #1C64F2;
|
|
||||||
|
|
||||||
span {
|
.threshold-select {
|
||||||
font-size: 14px;
|
display: flex;
|
||||||
font-weight: 400;
|
align-items: center;
|
||||||
line-height: 22px;
|
justify-content: space-between;
|
||||||
letter-spacing: 0.5px;
|
|
||||||
}
|
.icon {
|
||||||
}
|
color: #c0c1c3;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: #c0c1c3;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
color: #c0c1c3;
|
||||||
|
font-family: Inter;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
letter-spacing: 0.14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.lightMode {
|
||||||
|
.threshold-selector-container {
|
||||||
|
.threshold-select {
|
||||||
|
.icon {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-section {
|
||||||
|
.icon {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
color: var(--bg-ink-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import './ThresholdSelector.styles.scss';
|
import './ThresholdSelector.styles.scss';
|
||||||
|
|
||||||
import { Button, Typography } from 'antd';
|
import { Typography } from 'antd';
|
||||||
import { ColumnsType } from 'antd/es/table';
|
import { ColumnsType } from 'antd/es/table';
|
||||||
import { Events } from 'constants/events';
|
import { Events } from 'constants/events';
|
||||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||||
|
import { Antenna, Plus } from 'lucide-react';
|
||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
@@ -52,7 +53,6 @@ function ThresholdSelector({
|
|||||||
|
|
||||||
const addThresholdHandler = (): void => {
|
const addThresholdHandler = (): void => {
|
||||||
setThresholds([
|
setThresholds([
|
||||||
...thresholds,
|
|
||||||
{
|
{
|
||||||
index: uuid(),
|
index: uuid(),
|
||||||
isEditEnabled: true,
|
isEditEnabled: true,
|
||||||
@@ -66,6 +66,7 @@ function ThresholdSelector({
|
|||||||
selectedGraph,
|
selectedGraph,
|
||||||
thresholdTableOptions: tableOptions[0]?.value || '',
|
thresholdTableOptions: tableOptions[0]?.value || '',
|
||||||
},
|
},
|
||||||
|
...thresholds,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,7 +80,13 @@ function ThresholdSelector({
|
|||||||
return (
|
return (
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<div className="threshold-selector-container">
|
<div className="threshold-selector-container">
|
||||||
<Typography.Text>Thresholds</Typography.Text>
|
<div className="threshold-select">
|
||||||
|
<div className="left-section">
|
||||||
|
<Antenna size={14} className="icon" />
|
||||||
|
<Typography.Text className="text">Thresholds</Typography.Text>
|
||||||
|
</div>
|
||||||
|
<Plus size={14} onClick={addThresholdHandler} className="icon" />
|
||||||
|
</div>
|
||||||
{thresholds.map((threshold, idx) => (
|
{thresholds.map((threshold, idx) => (
|
||||||
<Threshold
|
<Threshold
|
||||||
key={threshold.index}
|
key={threshold.index}
|
||||||
@@ -100,9 +107,6 @@ function ThresholdSelector({
|
|||||||
thresholdTableOptions={threshold.thresholdTableOptions}
|
thresholdTableOptions={threshold.thresholdTableOptions}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<Button className="threshold-selector-button" onClick={addThresholdHandler}>
|
|
||||||
+ Add threshold
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ export type ThresholdProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type ShowCaseValueProps = {
|
export type ShowCaseValueProps = {
|
||||||
width: string;
|
width?: string;
|
||||||
value: ReactNode;
|
value: ReactNode;
|
||||||
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CustomColorProps = {
|
export type CustomColorProps = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { AutoComplete, Col, Input, Typography } from 'antd';
|
import { AutoComplete, Input, Typography } from 'antd';
|
||||||
import { find } from 'lodash-es';
|
import { find } from 'lodash-es';
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
|
|
||||||
@@ -29,10 +29,11 @@ function YAxisUnitSelector({
|
|||||||
value: options.name,
|
value: options.name,
|
||||||
}));
|
}));
|
||||||
return (
|
return (
|
||||||
<Col style={{ marginBottom: 12, marginTop: 12 }}>
|
<div className="y-axis-unit-selector">
|
||||||
<Typography.Text>{fieldLabel}</Typography.Text>
|
<Typography.Text className="heading">{fieldLabel}</Typography.Text>
|
||||||
<AutoComplete
|
<AutoComplete
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
|
rootClassName="y-axis-root-popover"
|
||||||
options={options}
|
options={options}
|
||||||
defaultValue={findCategoryById(defaultValue)?.name}
|
defaultValue={findCategoryById(defaultValue)?.name}
|
||||||
onSelect={onSelectHandler}
|
onSelect={onSelectHandler}
|
||||||
@@ -45,9 +46,9 @@ function YAxisUnitSelector({
|
|||||||
return false;
|
return false;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Input size="large" placeholder="Unit" allowClear />
|
<Input placeholder="Unit" allowClear rootClassName="input" />
|
||||||
</AutoComplete>
|
</AutoComplete>
|
||||||
</Col>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
import { UploadOutlined } from '@ant-design/icons';
|
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||||
import {
|
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
||||||
Button,
|
import './RightContainer.styles.scss';
|
||||||
Divider,
|
|
||||||
Input,
|
import { Input, InputNumber, Select, Space, Switch, Typography } from 'antd';
|
||||||
InputNumber,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
Switch,
|
|
||||||
Typography,
|
|
||||||
} from 'antd';
|
|
||||||
import InputComponent from 'components/Input';
|
|
||||||
import TimePreference from 'components/TimePreferenceDropDown';
|
import TimePreference from 'components/TimePreferenceDropDown';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import GraphTypes, {
|
import GraphTypes, {
|
||||||
@@ -17,6 +10,7 @@ import GraphTypes, {
|
|||||||
} from 'container/NewDashboard/ComponentsSlider/menuItems';
|
} from 'container/NewDashboard/ComponentsSlider/menuItems';
|
||||||
import useCreateAlerts from 'hooks/queryBuilder/useCreateAlerts';
|
import useCreateAlerts from 'hooks/queryBuilder/useCreateAlerts';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import { ConciergeBell, Plus } from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
Dispatch,
|
Dispatch,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
@@ -35,7 +29,6 @@ import {
|
|||||||
panelTypeVsThreshold,
|
panelTypeVsThreshold,
|
||||||
panelTypeVsYAxisUnit,
|
panelTypeVsYAxisUnit,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
import { Container, Title } from './styles';
|
|
||||||
import ThresholdSelector from './Threshold/ThresholdSelector';
|
import ThresholdSelector from './Threshold/ThresholdSelector';
|
||||||
import { ThresholdProps } from './Threshold/types';
|
import { ThresholdProps } from './Threshold/types';
|
||||||
import { timePreferance } from './timeItems';
|
import { timePreferance } from './timeItems';
|
||||||
@@ -118,67 +111,72 @@ function RightContainer({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<div className="right-container">
|
||||||
<Title>Panel Type</Title>
|
<section className="header">
|
||||||
<Select
|
<div className="purple-dot" />
|
||||||
onChange={setGraphHandler}
|
<Typography.Text className="header-text">Panel details</Typography.Text>
|
||||||
value={selectedGraph}
|
</section>
|
||||||
style={{ width: '100%', marginBottom: 24 }}
|
<section className="name-description">
|
||||||
>
|
<Typography.Text className="typography">Name</Typography.Text>
|
||||||
{graphTypes.map((item) => (
|
<Input
|
||||||
<Option key={item.name} value={item.name}>
|
placeholder="Enter the panel name here..."
|
||||||
{item.display}
|
onChange={(event): void => onChangeHandler(setTitle, event.target.value)}
|
||||||
</Option>
|
value={title}
|
||||||
))}
|
rootClassName="name-input"
|
||||||
</Select>
|
/>
|
||||||
<Title>Panel Attributes</Title>
|
<Typography.Text className="typography">Description</Typography.Text>
|
||||||
|
<TextArea
|
||||||
|
placeholder="Enter the panel description here..."
|
||||||
|
bordered
|
||||||
|
allowClear
|
||||||
|
value={description}
|
||||||
|
onChange={(event): void =>
|
||||||
|
onChangeHandler(setDescription, event.target.value)
|
||||||
|
}
|
||||||
|
rootClassName="description-input"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
<section className="panel-config">
|
||||||
|
<Typography.Text className="typography">Panel Type</Typography.Text>
|
||||||
|
<Select
|
||||||
|
onChange={setGraphHandler}
|
||||||
|
value={selectedGraph}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
className="panel-type-select"
|
||||||
|
>
|
||||||
|
{graphTypes.map((item) => (
|
||||||
|
<Option key={item.name} value={item.name}>
|
||||||
|
<div className="select-option">
|
||||||
|
<div className="icon">{item.icon}</div>
|
||||||
|
<Typography.Text className="display">{item.display}</Typography.Text>
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
|
||||||
<InputComponent
|
{allowFillSpans && (
|
||||||
label="Panel Title"
|
<Space className="fill-gaps">
|
||||||
size="middle"
|
<Typography className="fill-gaps-text">Fill gaps</Typography>
|
||||||
placeholder="Title"
|
<Switch
|
||||||
labelOnTop
|
checked={isFillSpans}
|
||||||
onChangeHandler={(event): void =>
|
size="small"
|
||||||
onChangeHandler(setTitle, event.target.value)
|
onChange={(checked): void => setIsFillSpans(checked)}
|
||||||
}
|
/>
|
||||||
value={title}
|
</Space>
|
||||||
/>
|
)}
|
||||||
|
|
||||||
<Title light="true">Description</Title>
|
|
||||||
|
|
||||||
<TextArea
|
|
||||||
placeholder="Write something describing the panel"
|
|
||||||
bordered
|
|
||||||
allowClear
|
|
||||||
value={description}
|
|
||||||
onChange={(event): void =>
|
|
||||||
onChangeHandler(setDescription, event.target.value)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{allowFillSpans && (
|
|
||||||
<Space style={{ marginTop: 10 }} direction="vertical">
|
|
||||||
<Typography>Fill gaps</Typography>
|
|
||||||
|
|
||||||
<Switch
|
|
||||||
checked={isFillSpans}
|
|
||||||
onChange={(checked): void => setIsFillSpans(checked)}
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{allowPanelTimePreference && (
|
|
||||||
<Title light="true">Panel Time Preference</Title>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Space direction="vertical">
|
|
||||||
{allowPanelTimePreference && (
|
{allowPanelTimePreference && (
|
||||||
<TimePreference
|
<>
|
||||||
{...{
|
<Typography.Text className="panel-time-text">
|
||||||
selectedTime,
|
Panel Time Preference
|
||||||
setSelectedTime,
|
</Typography.Text>
|
||||||
}}
|
<TimePreference
|
||||||
/>
|
{...{
|
||||||
|
selectedTime,
|
||||||
|
setSelectedTime,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{allowYAxisUnit && (
|
{allowYAxisUnit && (
|
||||||
@@ -188,50 +186,51 @@ function RightContainer({
|
|||||||
fieldLabel={selectedGraphType === 'Value' ? 'Unit' : 'Y Axis Unit'}
|
fieldLabel={selectedGraphType === 'Value' ? 'Unit' : 'Y Axis Unit'}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{allowSoftMinMax && (
|
||||||
{allowCreateAlerts && (
|
<section className="soft-min-max">
|
||||||
<Button icon={<UploadOutlined />} onClick={onCreateAlertsHandler}>
|
<section className="container">
|
||||||
Create Alerts from Queries
|
<Typography.Text className="text">Soft Min</Typography.Text>
|
||||||
</Button>
|
<InputNumber
|
||||||
|
type="number"
|
||||||
|
value={softMin}
|
||||||
|
onChange={softMinHandler}
|
||||||
|
rootClassName="input"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
<section className="container">
|
||||||
|
<Typography.Text className="text">Soft Max</Typography.Text>
|
||||||
|
<InputNumber
|
||||||
|
value={softMax}
|
||||||
|
type="number"
|
||||||
|
rootClassName="input"
|
||||||
|
onChange={softMaxHandler}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</section>
|
||||||
|
|
||||||
{allowSoftMinMax && (
|
{allowCreateAlerts && (
|
||||||
<>
|
<section className="alerts" onClick={onCreateAlertsHandler}>
|
||||||
<Divider />
|
<div className="left-section">
|
||||||
<Typography.Text style={{ display: 'block', margin: '5px 0' }}>
|
<ConciergeBell size={14} className="bell-icon" />
|
||||||
Soft Min
|
<Typography.Text className="alerts-text">Alerts</Typography.Text>
|
||||||
</Typography.Text>
|
</div>
|
||||||
<InputNumber
|
<Plus size={14} className="plus-icon" />
|
||||||
type="number"
|
</section>
|
||||||
value={softMin}
|
|
||||||
style={{ display: 'block', width: '100%' }}
|
|
||||||
onChange={softMinHandler}
|
|
||||||
/>
|
|
||||||
<Typography.Text style={{ display: 'block', margin: '5px 0' }}>
|
|
||||||
Soft Max
|
|
||||||
</Typography.Text>
|
|
||||||
<InputNumber
|
|
||||||
value={softMax}
|
|
||||||
type="number"
|
|
||||||
style={{ display: 'block', width: '100%' }}
|
|
||||||
onChange={softMaxHandler}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{allowThreshold && (
|
{allowThreshold && (
|
||||||
<>
|
<section>
|
||||||
<Divider />
|
|
||||||
<ThresholdSelector
|
<ThresholdSelector
|
||||||
thresholds={thresholds}
|
thresholds={thresholds}
|
||||||
setThresholds={setThresholds}
|
setThresholds={setThresholds}
|
||||||
yAxisUnit={yAxisUnit}
|
yAxisUnit={yAxisUnit}
|
||||||
selectedGraph={selectedGraph}
|
selectedGraph={selectedGraph}
|
||||||
/>
|
/>
|
||||||
</>
|
</section>
|
||||||
)}
|
)}
|
||||||
</Container>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
/* eslint-disable sonarjs/cognitive-complexity */
|
/* eslint-disable sonarjs/cognitive-complexity */
|
||||||
import './NewWidget.styles.scss';
|
import './NewWidget.styles.scss';
|
||||||
|
|
||||||
import { LockFilled, WarningOutlined } from '@ant-design/icons';
|
import { WarningOutlined } from '@ant-design/icons';
|
||||||
import { Button, Modal, Space, Tooltip, Typography } from 'antd';
|
import { Button, Modal, Space, Tooltip, Typography } from 'antd';
|
||||||
import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn';
|
|
||||||
import { chartHelpMessage } from 'components/facingIssueBtn/util';
|
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
|
||||||
import { FeatureKeys } from 'constants/features';
|
import { FeatureKeys } from 'constants/features';
|
||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
@@ -14,11 +11,13 @@ import { DashboardShortcuts } from 'constants/shortcuts/DashboardShortcuts';
|
|||||||
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
import { useUpdateDashboard } from 'hooks/dashboard/useUpdateDashboard';
|
||||||
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
|
import { useKeyboardHotkeys } from 'hooks/hotkeys/useKeyboardHotkeys';
|
||||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||||
|
import useAxiosError from 'hooks/useAxiosError';
|
||||||
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
|
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
|
||||||
import { useNotifications } from 'hooks/useNotifications';
|
|
||||||
import useUrlQuery from 'hooks/useUrlQuery';
|
import useUrlQuery from 'hooks/useUrlQuery';
|
||||||
import history from 'lib/history';
|
import history from 'lib/history';
|
||||||
import { defaultTo, isUndefined } from 'lodash-es';
|
import { defaultTo, isUndefined } from 'lodash-es';
|
||||||
|
import { Check, X } from 'lucide-react';
|
||||||
import { DashboardWidgetPageParams } from 'pages/DashboardWidget';
|
import { DashboardWidgetPageParams } from 'pages/DashboardWidget';
|
||||||
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
import { useDashboard } from 'providers/Dashboard/Dashboard';
|
||||||
import {
|
import {
|
||||||
@@ -43,7 +42,6 @@ import RightContainer from './RightContainer';
|
|||||||
import { ThresholdProps } from './RightContainer/Threshold/types';
|
import { ThresholdProps } from './RightContainer/Threshold/types';
|
||||||
import TimeItems, { timePreferance } from './RightContainer/timeItems';
|
import TimeItems, { timePreferance } from './RightContainer/timeItems';
|
||||||
import {
|
import {
|
||||||
ButtonContainer,
|
|
||||||
Container,
|
Container,
|
||||||
LeftContainerWrapper,
|
LeftContainerWrapper,
|
||||||
PanelContainer,
|
PanelContainer,
|
||||||
@@ -245,7 +243,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
return { selectedWidget, preWidgets, afterWidgets };
|
return { selectedWidget, preWidgets, afterWidgets };
|
||||||
}, [selectedDashboard, query]);
|
}, [selectedDashboard, query]);
|
||||||
|
|
||||||
const { notifications } = useNotifications();
|
const handleError = useAxiosError();
|
||||||
|
|
||||||
const onClickSaveHandler = useCallback(() => {
|
const onClickSaveHandler = useCallback(() => {
|
||||||
if (!selectedDashboard) {
|
if (!selectedDashboard) {
|
||||||
@@ -328,11 +326,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
pathname: generatePath(ROUTES.DASHBOARD, { dashboardId }),
|
pathname: generatePath(ROUTES.DASHBOARD, { dashboardId }),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: handleError,
|
||||||
notifications.error({
|
|
||||||
message: SOMETHING_WENT_WRONG,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}, [
|
}, [
|
||||||
selectedDashboard,
|
selectedDashboard,
|
||||||
@@ -345,11 +339,11 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
currentQuery,
|
currentQuery,
|
||||||
afterWidgets,
|
afterWidgets,
|
||||||
updateDashboardMutation,
|
updateDashboardMutation,
|
||||||
|
handleError,
|
||||||
setSelectedDashboard,
|
setSelectedDashboard,
|
||||||
setToScrollWidgetId,
|
setToScrollWidgetId,
|
||||||
featureResponse,
|
featureResponse,
|
||||||
dashboardId,
|
dashboardId,
|
||||||
notifications,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const onClickDiscardHandler = useCallback(() => {
|
const onClickDiscardHandler = useCallback(() => {
|
||||||
@@ -427,52 +421,44 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<div className="facing-issue-btn-container">
|
<div className="edit-header">
|
||||||
<FacingIssueBtn
|
<div className="left-header">
|
||||||
attributes={{
|
<X size={14} onClick={onClickDiscardHandler} className="discard-icon" />
|
||||||
uuid: selectedDashboard?.uuid,
|
<Typography.Text className="configure-panel">
|
||||||
title: selectedDashboard?.data.title,
|
Configure panel
|
||||||
panelType: graphType,
|
</Typography.Text>
|
||||||
widgetId: query.get('widgetId'),
|
</div>
|
||||||
queryType: currentQuery.queryType,
|
{isSaveDisabled && (
|
||||||
screen: 'Dashboard list page',
|
<Tooltip title={MESSAGE.PANEL}>
|
||||||
}}
|
|
||||||
eventName="Dashboard: Facing Issues in dashboard"
|
|
||||||
buttonText="Need help with this chart?"
|
|
||||||
message={chartHelpMessage(selectedDashboard, graphType)}
|
|
||||||
onHoverText="Click here to get help in creating chart"
|
|
||||||
/>
|
|
||||||
<ButtonContainer>
|
|
||||||
{isSaveDisabled && (
|
|
||||||
<Tooltip title={MESSAGE.PANEL}>
|
|
||||||
<Button
|
|
||||||
icon={<LockFilled />}
|
|
||||||
type="primary"
|
|
||||||
disabled={isSaveDisabled}
|
|
||||||
onClick={onSaveDashboard}
|
|
||||||
>
|
|
||||||
Save Changes
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isSaveDisabled && (
|
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
data-testid="new-widget-save"
|
data-testid="new-widget-save"
|
||||||
loading={updateDashboardMutation.isLoading}
|
loading={updateDashboardMutation.isLoading}
|
||||||
disabled={isSaveDisabled}
|
disabled={isSaveDisabled}
|
||||||
onClick={onSaveDashboard}
|
onClick={onSaveDashboard}
|
||||||
|
className="save-btn"
|
||||||
>
|
>
|
||||||
Save Changes
|
Save Changes
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</Tooltip>
|
||||||
<Button onClick={onClickDiscardHandler}>Discard Changes</Button>
|
)}
|
||||||
</ButtonContainer>
|
{!isSaveDisabled && (
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
data-testid="new-widget-save"
|
||||||
|
loading={updateDashboardMutation.isLoading}
|
||||||
|
disabled={isSaveDisabled}
|
||||||
|
onClick={onSaveDashboard}
|
||||||
|
icon={<Check size={14} />}
|
||||||
|
className="save-btn"
|
||||||
|
>
|
||||||
|
Save Changes
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<PanelContainer>
|
<PanelContainer>
|
||||||
<LeftContainerWrapper flex={5}>
|
<LeftContainerWrapper isDarkMode={useIsDarkMode()}>
|
||||||
{selectedWidget && (
|
{selectedWidget && (
|
||||||
<LeftContainer
|
<LeftContainer
|
||||||
selectedGraph={graphType}
|
selectedGraph={graphType}
|
||||||
@@ -486,7 +472,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
)}
|
)}
|
||||||
</LeftContainerWrapper>
|
</LeftContainerWrapper>
|
||||||
|
|
||||||
<RightContainerWrapper flex={1}>
|
<RightContainerWrapper>
|
||||||
<RightContainer
|
<RightContainer
|
||||||
setGraphHandler={setGraphHandler}
|
setGraphHandler={setGraphHandler}
|
||||||
title={title}
|
title={title}
|
||||||
@@ -541,7 +527,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
|
|||||||
{!isQueryModified ? (
|
{!isQueryModified ? (
|
||||||
<Typography>
|
<Typography>
|
||||||
{t('your_graph_build_with')}{' '}
|
{t('your_graph_build_with')}{' '}
|
||||||
<QueryTypeTag queryType={currentQuery.queryType} />
|
<QueryTypeTag queryType={currentQuery.queryType} />{' '}
|
||||||
{t('dashboard_ok_confirm')}
|
{t('dashboard_ok_confirm')}
|
||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -4,22 +4,37 @@ import styled from 'styled-components';
|
|||||||
export const Container = styled.div`
|
export const Container = styled.div`
|
||||||
min-height: 78vh;
|
min-height: 78vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: 1rem;
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
overflow-y: hidden;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const RightContainerWrapper = styled(Col)`
|
export const RightContainerWrapper = styled(Col)`
|
||||||
&&& {
|
&&& {
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
margin-bottom: 1rem;
|
overflow-y: auto;
|
||||||
|
max-width: 400px;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0.1rem;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const LeftContainerWrapper = styled(Col)`
|
interface LeftContainerWrapperProps {
|
||||||
|
isDarkMode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LeftContainerWrapper = styled(Col)<LeftContainerWrapperProps>`
|
||||||
&&& {
|
&&& {
|
||||||
margin-right: 1rem;
|
width: 70%;
|
||||||
margin-bottom: 1rem;
|
overflow-y: auto;
|
||||||
max-width: 70%;
|
border-right: ${({ isDarkMode }): string =>
|
||||||
|
isDarkMode
|
||||||
|
? '1px solid var(--bg-slate-300)'
|
||||||
|
: '1px solid var(--bg-vanilla-300)'};
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0.1rem;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -32,6 +47,7 @@ export const ButtonContainer = styled.div`
|
|||||||
|
|
||||||
export const PanelContainer = styled.div`
|
export const PanelContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
overflow-y: auto;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const Tag = styled(AntDTag)`
|
export const Tag = styled(AntDTag)`
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user