mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-16 00:55:54 +08:00
feat: [SIG-546]: user with viewer roles can only view saved views (#4663)
* feat: [SIG-543]: Users with VIEWER access can create/edit/delete views for logs and traces * feat: [SIG-543]: remove extra code * feat: [SIG-543]: role changes in the save views toolbar * feat: [SIG-543]: role changes in the save views toolbar * feat: remove the save feature / dashboard / alert feature for viewer roles * feat: remove the save feature / dashboard / alert feature for viewer roles * fix: address review comments
This commit is contained in:
parent
49aba4fb1c
commit
6b87118fc6
@ -1,3 +1,6 @@
|
|||||||
|
.hide-update {
|
||||||
|
left: calc(50% - 41px) !important;
|
||||||
|
}
|
||||||
.explorer-update {
|
.explorer-update {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 16px;
|
bottom: 16px;
|
||||||
@ -23,6 +26,10 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ant-divider {
|
.ant-divider {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
@ -55,6 +62,10 @@
|
|||||||
|
|
||||||
.view-options,
|
.view-options,
|
||||||
.actions {
|
.actions {
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -102,6 +113,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-content {
|
.app-content {
|
||||||
|
@ -13,6 +13,7 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import cx from 'classnames';
|
||||||
import { getViewDetailsUsingViewKey } from 'components/ExplorerCard/utils';
|
import { getViewDetailsUsingViewKey } from 'components/ExplorerCard/utils';
|
||||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||||
import { QueryParams } from 'constants/query';
|
import { QueryParams } from 'constants/query';
|
||||||
@ -31,10 +32,14 @@ import { useNotifications } from 'hooks/useNotifications';
|
|||||||
import { mapCompositeQueryFromQuery } from 'lib/newQueryBuilder/queryBuilderMappers/mapCompositeQueryFromQuery';
|
import { mapCompositeQueryFromQuery } from 'lib/newQueryBuilder/queryBuilderMappers/mapCompositeQueryFromQuery';
|
||||||
import { Check, ConciergeBell, Disc3, Plus, X, XCircle } from 'lucide-react';
|
import { Check, ConciergeBell, Disc3, Plus, X, XCircle } from 'lucide-react';
|
||||||
import { CSSProperties, useCallback, useMemo, useRef, useState } from 'react';
|
import { CSSProperties, useCallback, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
import AppReducer from 'types/reducer/app';
|
||||||
|
import { USER_ROLES } from 'types/roles';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DATASOURCE_VS_ROUTES,
|
DATASOURCE_VS_ROUTES,
|
||||||
@ -43,6 +48,9 @@ import {
|
|||||||
saveNewViewHandler,
|
saveNewViewHandler,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
|
const allowedRoles = [USER_ROLES.ADMIN, USER_ROLES.AUTHOR, USER_ROLES.EDITOR];
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
function ExplorerOptions({
|
function ExplorerOptions({
|
||||||
disabled,
|
disabled,
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -71,6 +79,8 @@ function ExplorerOptions({
|
|||||||
setIsSaveModalOpen(false);
|
setIsSaveModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
|
|
||||||
const onCreateAlertsHandler = useCallback(() => {
|
const onCreateAlertsHandler = useCallback(() => {
|
||||||
history.push(
|
history.push(
|
||||||
`${ROUTES.ALERTS_NEW}?${QueryParams.compositeQuery}=${encodeURIComponent(
|
`${ROUTES.ALERTS_NEW}?${QueryParams.compositeQuery}=${encodeURIComponent(
|
||||||
@ -247,10 +257,17 @@ function ExplorerOptions({
|
|||||||
[isDarkMode],
|
[isDarkMode],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isEditDeleteSupported = allowedRoles.includes(role as string);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isQueryUpdated && (
|
{isQueryUpdated && (
|
||||||
<div className="explorer-update">
|
<div
|
||||||
|
className={cx(
|
||||||
|
isEditDeleteSupported ? '' : 'hide-update',
|
||||||
|
'explorer-update',
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Tooltip title="Clear this view" placement="top">
|
<Tooltip title="Clear this view" placement="top">
|
||||||
<Button
|
<Button
|
||||||
className="action-icon"
|
className="action-icon"
|
||||||
@ -258,10 +275,13 @@ function ExplorerOptions({
|
|||||||
icon={<X size={14} />}
|
icon={<X size={14} />}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Divider type="vertical" />
|
<Divider
|
||||||
|
type="vertical"
|
||||||
|
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||||
|
/>
|
||||||
<Tooltip title="Update this view" placement="top">
|
<Tooltip title="Update this view" placement="top">
|
||||||
<Button
|
<Button
|
||||||
className="action-icon"
|
className={cx('action-icon', isEditDeleteSupported ? ' ' : 'hidden')}
|
||||||
disabled={isViewUpdating}
|
disabled={isViewUpdating}
|
||||||
onClick={onUpdateQueryHandler}
|
onClick={onUpdateQueryHandler}
|
||||||
icon={<Disc3 size={14} />}
|
icon={<Disc3 size={14} />}
|
||||||
@ -323,15 +343,16 @@ function ExplorerOptions({
|
|||||||
<Button
|
<Button
|
||||||
shape="round"
|
shape="round"
|
||||||
onClick={handleSaveViewModalToggle}
|
onClick={handleSaveViewModalToggle}
|
||||||
|
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||||
disabled={viewsIsLoading || isRefetching}
|
disabled={viewsIsLoading || isRefetching}
|
||||||
>
|
>
|
||||||
<Disc3 size={16} /> Save this view
|
<Disc3 size={16} /> Save this view
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr className={isEditDeleteSupported ? '' : 'hidden'} />
|
||||||
|
|
||||||
<div className="actions">
|
<div className={cx('actions', isEditDeleteSupported ? '' : 'hidden')}>
|
||||||
<Tooltip title="Create Alerts">
|
<Tooltip title="Create Alerts">
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
@ -309,49 +309,52 @@ function DashboardsList(): JSX.Element {
|
|||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col
|
{createNewDashboard && (
|
||||||
span={6}
|
<Col
|
||||||
style={{
|
span={6}
|
||||||
display: 'flex',
|
style={{
|
||||||
justifyContent: 'flex-end',
|
display: 'flex',
|
||||||
}}
|
justifyContent: 'flex-end',
|
||||||
>
|
}}
|
||||||
<ButtonContainer>
|
|
||||||
<TextToolTip
|
|
||||||
{...{
|
|
||||||
text: `More details on how to create dashboards`,
|
|
||||||
url: 'https://signoz.io/docs/userguide/dashboards',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</ButtonContainer>
|
|
||||||
|
|
||||||
<Dropdown
|
|
||||||
menu={{ items: getMenuItems }}
|
|
||||||
disabled={isDashboardListLoading}
|
|
||||||
placement="bottomRight"
|
|
||||||
>
|
>
|
||||||
<NewDashboardButton
|
<ButtonContainer>
|
||||||
icon={<PlusOutlined />}
|
<TextToolTip
|
||||||
type="primary"
|
{...{
|
||||||
data-testid="create-new-dashboard"
|
text: `More details on how to create dashboards`,
|
||||||
loading={newDashboardState.loading}
|
url: 'https://signoz.io/docs/userguide/dashboards',
|
||||||
danger={newDashboardState.error}
|
}}
|
||||||
|
/>
|
||||||
|
</ButtonContainer>
|
||||||
|
|
||||||
|
<Dropdown
|
||||||
|
menu={{ items: getMenuItems }}
|
||||||
|
disabled={isDashboardListLoading}
|
||||||
|
placement="bottomRight"
|
||||||
>
|
>
|
||||||
{getText()}
|
<NewDashboardButton
|
||||||
</NewDashboardButton>
|
icon={<PlusOutlined />}
|
||||||
</Dropdown>
|
type="primary"
|
||||||
</Col>
|
data-testid="create-new-dashboard"
|
||||||
|
loading={newDashboardState.loading}
|
||||||
|
danger={newDashboardState.error}
|
||||||
|
>
|
||||||
|
{getText()}
|
||||||
|
</NewDashboardButton>
|
||||||
|
</Dropdown>
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
isDashboardListLoading,
|
isDashboardListLoading,
|
||||||
handleSearch,
|
handleSearch,
|
||||||
isFilteringDashboards,
|
isFilteringDashboards,
|
||||||
|
searchString,
|
||||||
|
createNewDashboard,
|
||||||
getMenuItems,
|
getMenuItems,
|
||||||
newDashboardState.loading,
|
newDashboardState.loading,
|
||||||
newDashboardState.error,
|
newDashboardState.error,
|
||||||
getText,
|
getText,
|
||||||
searchString,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,171 +1,170 @@
|
|||||||
.save-view-container {
|
.save-view-container {
|
||||||
margin-top: 70px;
|
margin-top: 70px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.save-view-content {
|
.save-view-content {
|
||||||
width: calc(100% - 30px);
|
width: calc(100% - 30px);
|
||||||
max-width: 736px;
|
max-width: 736px;
|
||||||
|
|
||||||
|
.title {
|
||||||
.title {
|
color: var(--bg-vanilla-100);
|
||||||
color: var(--bg-vanilla-100);
|
font-size: var(--font-size-lg);
|
||||||
font-size: var(--font-size-lg);
|
font-style: normal;
|
||||||
font-style: normal;
|
font-weight: var(--font-weight-normal);
|
||||||
font-weight: var(--font-weight-normal);
|
line-height: 28px; /* 155.556% */
|
||||||
line-height: 28px; /* 155.556% */
|
letter-spacing: -0.09px;
|
||||||
letter-spacing: -0.09px;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
color: var(---bg-vanilla-400);
|
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: var(--font-weight-normal);
|
|
||||||
line-height: 20px; /* 142.857% */
|
|
||||||
letter-spacing: -0.07px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-input-affix-wrapper {
|
|
||||||
margin-top: 16px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-table-row {
|
.subtitle {
|
||||||
.ant-table-cell {
|
color: var(---bg-vanilla-400);
|
||||||
padding: 0;
|
font-size: var(--font-size-sm);
|
||||||
border: none;
|
font-style: normal;
|
||||||
background: var(--bg-ink-500);
|
font-weight: var(--font-weight-normal);
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
}
|
letter-spacing: -0.07px;
|
||||||
.column-render {
|
}
|
||||||
margin: 8px 0 !important;
|
|
||||||
padding: 16px;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 1px solid var(--bg-slate-500);
|
|
||||||
background: var(--bg-ink-400);
|
|
||||||
|
|
||||||
.title-with-action {
|
.ant-input-affix-wrapper {
|
||||||
display: flex;
|
margin-top: 16px;
|
||||||
justify-content: space-between;
|
margin-bottom: 8px;
|
||||||
align-items: center;
|
}
|
||||||
|
|
||||||
.save-view-title {
|
.ant-table-row {
|
||||||
display: flex;
|
.ant-table-cell {
|
||||||
align-items: center;
|
padding: 0;
|
||||||
gap: 6px;
|
border: none;
|
||||||
.dot {
|
background: var(--bg-ink-500);
|
||||||
min-height: 6px;
|
}
|
||||||
min-width: 6px;
|
.column-render {
|
||||||
border-radius: 50%;
|
margin: 8px 0 !important;
|
||||||
}
|
padding: 16px;
|
||||||
.ant-typography {
|
border-radius: 6px;
|
||||||
color: var(--bg-vanilla-400);
|
border: 1px solid var(--bg-slate-500);
|
||||||
font-size: var(--font-size-sm);
|
background: var(--bg-ink-400);
|
||||||
font-style: normal;
|
|
||||||
font-weight: var(--font-weight-medium);
|
|
||||||
line-height: 20px;
|
|
||||||
letter-spacing: -0.07px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-btn {
|
.title-with-action {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
justify-content: space-between;
|
||||||
gap: 20px;
|
align-items: center;
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
.save-view-title {
|
||||||
.view-details {
|
display: flex;
|
||||||
margin-top: 8px;
|
align-items: center;
|
||||||
display: flex;
|
gap: 6px;
|
||||||
align-items: center;
|
.dot {
|
||||||
|
min-height: 6px;
|
||||||
|
min-width: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.ant-typography {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-medium);
|
||||||
|
line-height: 20px;
|
||||||
|
letter-spacing: -0.07px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.view-tag {
|
.action-btn {
|
||||||
width: 14px;
|
display: flex;
|
||||||
height: 14px;
|
align-items: center;
|
||||||
border-radius: 50px;
|
gap: 20px;
|
||||||
background: var(--bg-slate-300);
|
cursor: pointer;
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.tag-text {
|
.hidden {
|
||||||
color: var(--bg-vanilla-400);
|
display: none;
|
||||||
leading-trim: both;
|
}
|
||||||
text-edge: cap;
|
}
|
||||||
font-size: 10px;
|
}
|
||||||
font-style: normal;
|
.view-details {
|
||||||
font-weight: var(--font-weight-normal);
|
margin-top: 8px;
|
||||||
line-height: normal;
|
display: flex;
|
||||||
letter-spacing: -0.05px;
|
align-items: center;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.view-created-by {
|
.view-tag {
|
||||||
margin-left: 8px;
|
width: 14px;
|
||||||
}
|
height: 14px;
|
||||||
|
border-radius: 50px;
|
||||||
|
background: var(--bg-slate-300);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.view-created-at {
|
.tag-text {
|
||||||
margin-left: 24px;
|
color: var(--bg-vanilla-400);
|
||||||
display: flex;
|
leading-trim: both;
|
||||||
align-items: center;
|
text-edge: cap;
|
||||||
.ant-typography {
|
font-size: 10px;
|
||||||
margin-left: 6px;
|
font-style: normal;
|
||||||
color: var(--bg-vanilla-400);
|
font-weight: var(--font-weight-normal);
|
||||||
font-size: var(--font-size-sm);
|
line-height: normal;
|
||||||
font-style: normal;
|
letter-spacing: -0.05px;
|
||||||
font-weight: var(--font-weight-normal);
|
}
|
||||||
line-height: 18px; /* 128.571% */
|
}
|
||||||
letter-spacing: -0.07px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-pagination-item {
|
.view-created-by {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
display: flex;
|
.view-created-at {
|
||||||
justify-content: center;
|
margin-left: 24px;
|
||||||
align-items: center;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.ant-typography {
|
||||||
|
margin-left: 6px;
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
line-height: 18px; /* 128.571% */
|
||||||
|
letter-spacing: -0.07px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> a {
|
.ant-pagination-item {
|
||||||
color: var(--bg-vanilla-400);
|
display: flex;
|
||||||
font-variant-numeric: lining-nums tabular-nums slashed-zero;
|
justify-content: center;
|
||||||
font-feature-settings: 'dlig' on, 'salt' on, 'case' on, 'cpsp' on;
|
align-items: center;
|
||||||
font-size: var(--font-size-sm);
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: var(--font-weight-normal);
|
|
||||||
line-height: 20px; /* 142.857% */
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
> a {
|
||||||
|
color: var(--bg-vanilla-400);
|
||||||
|
font-variant-numeric: lining-nums tabular-nums slashed-zero;
|
||||||
|
font-feature-settings: 'dlig' on, 'salt' on, 'case' on, 'cpsp' on;
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
line-height: 20px; /* 142.857% */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.ant-pagination-item-active {
|
.ant-pagination-item-active {
|
||||||
background-color: var(--bg-robin-500);
|
background-color: var(--bg-robin-500);
|
||||||
> a {
|
> a {
|
||||||
color: var(--bg-ink-500) !important;
|
color: var(--bg-ink-500) !important;
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: var(--font-weight-medium);
|
font-weight: var(--font-weight-medium);
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete-view-modal {
|
.delete-view-modal {
|
||||||
width: calc(100% - 30px) !important; /* Adjust the 20px as needed */
|
width: calc(100% - 30px) !important; /* Adjust the 20px as needed */
|
||||||
max-width: 384px;
|
max-width: 384px;
|
||||||
.ant-modal-content {
|
.ant-modal-content {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid var(--bg-slate-500);
|
border: 1px solid var(--bg-slate-500);
|
||||||
background: var(--bg-ink-400);
|
background: var(--bg-ink-400);
|
||||||
box-shadow: 0px -4px 16px 2px rgba(0, 0, 0, 0.20);
|
box-shadow: 0px -4px 16px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
|
||||||
.ant-modal-header {
|
.ant-modal-header {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
@ -177,11 +176,11 @@
|
|||||||
|
|
||||||
.ant-typography {
|
.ant-typography {
|
||||||
color: var(--bg-vanilla-400);
|
color: var(--bg-vanilla-400);
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: var(--font-weight-normal);
|
font-weight: var(--font-weight-normal);
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
letter-spacing: -0.07px;
|
letter-spacing: -0.07px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.save-view-input {
|
.save-view-input {
|
||||||
@ -211,7 +210,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-modal-footer {
|
.ant-modal-footer {
|
||||||
@ -223,127 +221,126 @@
|
|||||||
.cancel-btn {
|
.cancel-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--bg-slate-500);
|
background: var(--bg-slate-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete-btn {
|
.delete-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background: var(--bg-cherry-500);
|
background: var(--bg-cherry-500);
|
||||||
margin-left: 12px;
|
margin-left: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete-btn:hover {
|
.delete-btn:hover {
|
||||||
color: var(--bg-vanilla-100);
|
color: var(--bg-vanilla-100);
|
||||||
background: var(--bg-cherry-600);
|
background: var(--bg-cherry-600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
color: var(--bg-vanilla-100);
|
color: var(--bg-vanilla-100);
|
||||||
font-size: var(--font-size-sm);
|
font-size: var(--font-size-sm);
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: var(--font-weight-medium);
|
font-weight: var(--font-weight-medium);
|
||||||
line-height: 20px; /* 142.857% */
|
line-height: 20px; /* 142.857% */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.lightMode {
|
.lightMode {
|
||||||
.save-view-container {
|
.save-view-container {
|
||||||
.save-view-content {
|
.save-view-content {
|
||||||
|
.title {
|
||||||
|
color: var(--bg-ink-500);
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.ant-table-row {
|
||||||
color: var(--bg-ink-500);
|
.ant-table-cell {
|
||||||
}
|
background: var(--bg-vanilla-200);
|
||||||
|
}
|
||||||
|
|
||||||
.ant-table-row {
|
&:hover {
|
||||||
.ant-table-cell {
|
.ant-table-cell {
|
||||||
background: var(--bg-vanilla-200);
|
background: var(--bg-vanilla-200) !important;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
.column-render {
|
||||||
.ant-table-cell {
|
border: 1px solid var(--bg-vanilla-200);
|
||||||
background: var(--bg-vanilla-200) !important;
|
background: var(--bg-vanilla-100);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.column-render {
|
.title-with-action {
|
||||||
border: 1px solid var(--bg-vanilla-200);
|
.save-view-title {
|
||||||
background: var(--bg-vanilla-100);
|
.ant-typography {
|
||||||
|
color: var(--bg-ink-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.title-with-action {
|
.action-btn {
|
||||||
.save-view-title {
|
.ant-typography {
|
||||||
.ant-typography {
|
color: var(--bg-ink-500);
|
||||||
color: var(--bg-ink-500);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn {
|
.view-details {
|
||||||
.ant-typography {
|
.view-tag {
|
||||||
color: var(--bg-ink-500);
|
background: var(--bg-vanilla-200);
|
||||||
}
|
.tag-text {
|
||||||
}
|
color: var(--bg-ink-500);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.view-details {
|
.view-created-by {
|
||||||
.view-tag {
|
color: var(--bg-ink-500);
|
||||||
background: var(--bg-vanilla-200);
|
}
|
||||||
.tag-text {
|
|
||||||
color: var(--bg-ink-500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.view-created-by {
|
.view-created-at {
|
||||||
color: var(--bg-ink-500);
|
.ant-typography {
|
||||||
}
|
color: var(--bg-ink-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.view-created-at {
|
.delete-view-modal {
|
||||||
.ant-typography {
|
.ant-modal-content {
|
||||||
color: var(--bg-ink-500);
|
border: 1px solid var(--bg-vanilla-200);
|
||||||
}
|
background: var(--bg-vanilla-100);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.delete-view-modal {
|
.ant-modal-header {
|
||||||
.ant-modal-content {
|
background: var(--bg-vanilla-100);
|
||||||
border: 1px solid var(--bg-vanilla-200);
|
|
||||||
background: var(--bg-vanilla-100);
|
|
||||||
|
|
||||||
.ant-modal-header {
|
.title {
|
||||||
background: var(--bg-vanilla-100);
|
color: var(--bg-ink-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.title {
|
.ant-modal-body {
|
||||||
color: var(--bg-ink-500);
|
.ant-typography {
|
||||||
}
|
color: var(--bg-ink-500);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-modal-body {
|
.save-view-input {
|
||||||
.ant-typography {
|
.ant-input {
|
||||||
color: var(--bg-ink-500);
|
background: var(--bg-vanilla-200);
|
||||||
}
|
color: var(--bg-ink-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.save-view-input {
|
.ant-modal-footer {
|
||||||
.ant-input {
|
.cancel-btn {
|
||||||
background: var(--bg-vanilla-200);
|
background: var(--bg-vanilla-300);
|
||||||
color: var(--bg-ink-500);
|
color: var(--bg-ink-400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.ant-modal-footer {
|
}
|
||||||
.cancel-btn {
|
|
||||||
background: var(--bg-vanilla-300);
|
|
||||||
color: var(--bg-ink-400);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -32,14 +32,20 @@ import {
|
|||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { ChangeEvent, useEffect, useState } from 'react';
|
import { ChangeEvent, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { AppState } from 'store/reducers';
|
||||||
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
|
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
|
||||||
import { ViewProps } from 'types/api/saveViews/types';
|
import { ViewProps } from 'types/api/saveViews/types';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
|
import AppReducer from 'types/reducer/app';
|
||||||
|
import { USER_ROLES } from 'types/roles';
|
||||||
|
|
||||||
import { ROUTES_VS_SOURCEPAGE, SOURCEPAGE_VS_ROUTES } from './constants';
|
import { ROUTES_VS_SOURCEPAGE, SOURCEPAGE_VS_ROUTES } from './constants';
|
||||||
import { deleteViewHandler } from './utils';
|
import { deleteViewHandler } from './utils';
|
||||||
|
|
||||||
|
const allowedRoles = [USER_ROLES.ADMIN, USER_ROLES.AUTHOR, USER_ROLES.EDITOR];
|
||||||
|
|
||||||
function SaveView(): JSX.Element {
|
function SaveView(): JSX.Element {
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
const sourcepage = ROUTES_VS_SOURCEPAGE[pathname];
|
const sourcepage = ROUTES_VS_SOURCEPAGE[pathname];
|
||||||
@ -61,6 +67,8 @@ function SaveView(): JSX.Element {
|
|||||||
setIsDeleteModalOpen(false);
|
setIsDeleteModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { role } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
|
|
||||||
const handleDeleteModelOpen = (uuid: string, name: string): void => {
|
const handleDeleteModelOpen = (uuid: string, name: string): void => {
|
||||||
setActiveViewKey(uuid);
|
setActiveViewKey(uuid);
|
||||||
setActiveViewName(name);
|
setActiveViewName(name);
|
||||||
@ -217,6 +225,9 @@ function SaveView(): JSX.Element {
|
|||||||
|
|
||||||
// Combine time and date
|
// Combine time and date
|
||||||
const formattedDateAndTime = `${formattedTime} ⎯ ${formattedDate}`;
|
const formattedDateAndTime = `${formattedTime} ⎯ ${formattedDate}`;
|
||||||
|
|
||||||
|
const isEditDeleteSupported = allowedRoles.includes(role as string);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="column-render">
|
<div className="column-render">
|
||||||
<div className="title-with-action">
|
<div className="title-with-action">
|
||||||
@ -234,11 +245,13 @@ function SaveView(): JSX.Element {
|
|||||||
<div className="action-btn">
|
<div className="action-btn">
|
||||||
<PenLine
|
<PenLine
|
||||||
size={14}
|
size={14}
|
||||||
|
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||||
onClick={(): void => handleEditModelOpen(view, bgColor)}
|
onClick={(): void => handleEditModelOpen(view, bgColor)}
|
||||||
/>
|
/>
|
||||||
<Compass size={14} onClick={(): void => handleRedirectQuery(view)} />
|
<Compass size={14} onClick={(): void => handleRedirectQuery(view)} />
|
||||||
<Trash2
|
<Trash2
|
||||||
size={14}
|
size={14}
|
||||||
|
className={isEditDeleteSupported ? '' : 'hidden'}
|
||||||
color={Color.BG_CHERRY_500}
|
color={Color.BG_CHERRY_500}
|
||||||
onClick={(): void => handleDeleteModelOpen(view.uuid, view.name)}
|
onClick={(): void => handleDeleteModelOpen(view.uuid, view.name)}
|
||||||
/>
|
/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user