chore: Cleanup code related to MetadataBar, fix types (#31030)
This commit is contained in:
parent
f8adaf66c1
commit
abf3790ea6
|
|
@ -51,7 +51,7 @@ export type LastModified = {
|
||||||
export type Owner = {
|
export type Owner = {
|
||||||
type: MetadataType.Owner;
|
type: MetadataType.Owner;
|
||||||
createdBy: string;
|
createdBy: string;
|
||||||
owners?: string[];
|
owners?: string[] | string;
|
||||||
createdOn: string;
|
createdOn: string;
|
||||||
onClick?: (type: string) => void;
|
onClick?: (type: string) => void;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -23,27 +23,18 @@ import { styled } from '@superset-ui/core';
|
||||||
import { Tooltip, TooltipPlacement } from 'src/components/Tooltip';
|
import { Tooltip, TooltipPlacement } from 'src/components/Tooltip';
|
||||||
import { ContentType } from './ContentType';
|
import { ContentType } from './ContentType';
|
||||||
import { config } from './ContentConfig';
|
import { config } from './ContentConfig';
|
||||||
|
import {
|
||||||
export const MIN_NUMBER_ITEMS = 2;
|
HORIZONTAL_PADDING,
|
||||||
export const MAX_NUMBER_ITEMS = 6;
|
ICON_PADDING,
|
||||||
|
ICON_WIDTH,
|
||||||
const HORIZONTAL_PADDING = 12;
|
VERTICAL_PADDING,
|
||||||
const VERTICAL_PADDING = 8;
|
TEXT_MIN_WIDTH,
|
||||||
const ICON_PADDING = 8;
|
TEXT_MAX_WIDTH,
|
||||||
const SPACE_BETWEEN_ITEMS = 16;
|
SPACE_BETWEEN_ITEMS,
|
||||||
const ICON_WIDTH = 16;
|
ORDER,
|
||||||
const TEXT_MIN_WIDTH = 70;
|
MIN_NUMBER_ITEMS,
|
||||||
const TEXT_MAX_WIDTH = 150;
|
MAX_NUMBER_ITEMS,
|
||||||
const ORDER = {
|
} from './constants';
|
||||||
dashboards: 0,
|
|
||||||
table: 1,
|
|
||||||
sql: 2,
|
|
||||||
rows: 3,
|
|
||||||
tags: 4,
|
|
||||||
description: 5,
|
|
||||||
owner: 6,
|
|
||||||
lastModified: 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Bar = styled.div<{ count: number }>`
|
const Bar = styled.div<{ count: number }>`
|
||||||
${({ theme, count }) => `
|
${({ theme, count }) => `
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const MIN_NUMBER_ITEMS = 2;
|
||||||
|
export const MAX_NUMBER_ITEMS = 6;
|
||||||
|
|
||||||
|
export const HORIZONTAL_PADDING = 12;
|
||||||
|
export const VERTICAL_PADDING = 8;
|
||||||
|
export const ICON_PADDING = 8;
|
||||||
|
export const SPACE_BETWEEN_ITEMS = 16;
|
||||||
|
export const ICON_WIDTH = 16;
|
||||||
|
export const TEXT_MIN_WIDTH = 70;
|
||||||
|
export const TEXT_MAX_WIDTH = 150;
|
||||||
|
export const ORDER = {
|
||||||
|
dashboards: 0,
|
||||||
|
table: 1,
|
||||||
|
sql: 2,
|
||||||
|
rows: 3,
|
||||||
|
tags: 4,
|
||||||
|
description: 5,
|
||||||
|
owner: 6,
|
||||||
|
lastModified: 7,
|
||||||
|
};
|
||||||
|
|
@ -16,7 +16,8 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import MetadataBar, { MIN_NUMBER_ITEMS, MAX_NUMBER_ITEMS } from './MetadataBar';
|
import MetadataBar from './MetadataBar';
|
||||||
|
import { MIN_NUMBER_ITEMS, MAX_NUMBER_ITEMS } from './constants';
|
||||||
|
|
||||||
export type { MetadataBarProps } from './MetadataBar';
|
export type { MetadataBarProps } from './MetadataBar';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ import ConnectedHeaderActionsDropdown from 'src/dashboard/components/Header/Head
|
||||||
import PublishedStatus from 'src/dashboard/components/PublishedStatus';
|
import PublishedStatus from 'src/dashboard/components/PublishedStatus';
|
||||||
import UndoRedoKeyListeners from 'src/dashboard/components/UndoRedoKeyListeners';
|
import UndoRedoKeyListeners from 'src/dashboard/components/UndoRedoKeyListeners';
|
||||||
import PropertiesModal from 'src/dashboard/components/PropertiesModal';
|
import PropertiesModal from 'src/dashboard/components/PropertiesModal';
|
||||||
import getOwnerName from 'src/utils/getOwnerName';
|
|
||||||
import {
|
import {
|
||||||
UNDO_LIMIT,
|
UNDO_LIMIT,
|
||||||
SAVE_TYPE_OVERWRITE,
|
SAVE_TYPE_OVERWRITE,
|
||||||
|
|
@ -55,7 +54,6 @@ import setPeriodicRunner, {
|
||||||
stopPeriodicRender,
|
stopPeriodicRender,
|
||||||
} from 'src/dashboard/util/setPeriodicRunner';
|
} from 'src/dashboard/util/setPeriodicRunner';
|
||||||
import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions';
|
import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions';
|
||||||
import MetadataBar, { MetadataType } from 'src/components/MetadataBar';
|
|
||||||
import DashboardEmbedModal from '../EmbeddedModal';
|
import DashboardEmbedModal from '../EmbeddedModal';
|
||||||
import OverwriteConfirm from '../OverwriteConfirm';
|
import OverwriteConfirm from '../OverwriteConfirm';
|
||||||
import {
|
import {
|
||||||
|
|
@ -88,6 +86,7 @@ import { logEvent } from '../../../logger/actions';
|
||||||
import { dashboardInfoChanged } from '../../actions/dashboardInfo';
|
import { dashboardInfoChanged } from '../../actions/dashboardInfo';
|
||||||
import isDashboardLoading from '../../util/isDashboardLoading';
|
import isDashboardLoading from '../../util/isDashboardLoading';
|
||||||
import { useChartIds } from '../../util/charts/useChartIds';
|
import { useChartIds } from '../../util/charts/useChartIds';
|
||||||
|
import { useDashboardMetadataBar } from './useDashboardMetadataBar';
|
||||||
|
|
||||||
const extensionsRegistry = getExtensionsRegistry();
|
const extensionsRegistry = getExtensionsRegistry();
|
||||||
|
|
||||||
|
|
@ -472,32 +471,7 @@ const Header = () => {
|
||||||
setShowingEmbedModal(false);
|
setShowingEmbedModal(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const getMetadataItems = useCallback(
|
const metadataBar = useDashboardMetadataBar(dashboardInfo);
|
||||||
() => [
|
|
||||||
{
|
|
||||||
type: MetadataType.LastModified,
|
|
||||||
value: dashboardInfo.changed_on_delta_humanized,
|
|
||||||
modifiedBy:
|
|
||||||
getOwnerName(dashboardInfo.changed_by) || t('Not available'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: MetadataType.Owner,
|
|
||||||
createdBy: getOwnerName(dashboardInfo.created_by) || t('Not available'),
|
|
||||||
owners:
|
|
||||||
dashboardInfo.owners.length > 0
|
|
||||||
? dashboardInfo.owners.map(getOwnerName)
|
|
||||||
: t('None'),
|
|
||||||
createdOn: dashboardInfo.created_on_delta_humanized,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
|
||||||
dashboardInfo.changed_by,
|
|
||||||
dashboardInfo.changed_on_delta_humanized,
|
|
||||||
dashboardInfo.created_by,
|
|
||||||
dashboardInfo.created_on_delta_humanized,
|
|
||||||
dashboardInfo.owners,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
const userCanEdit =
|
const userCanEdit =
|
||||||
dashboardInfo.dash_edit_perm && !dashboardInfo.is_managed_externally;
|
dashboardInfo.dash_edit_perm && !dashboardInfo.is_managed_externally;
|
||||||
|
|
@ -579,15 +553,13 @@ const Header = () => {
|
||||||
visible={!editMode}
|
visible={!editMode}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
!editMode && !isEmbedded && (
|
!editMode && !isEmbedded && metadataBar,
|
||||||
<MetadataBar items={getMetadataItems()} tooltipPlacement="bottom" />
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
boundActionCreators.savePublished,
|
boundActionCreators.savePublished,
|
||||||
dashboardInfo.id,
|
dashboardInfo.id,
|
||||||
editMode,
|
editMode,
|
||||||
getMetadataItems,
|
metadataBar,
|
||||||
isEmbedded,
|
isEmbedded,
|
||||||
isPublished,
|
isPublished,
|
||||||
userCanEdit,
|
userCanEdit,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { t } from '@superset-ui/core';
|
||||||
|
import { DashboardInfo } from 'src/dashboard/types';
|
||||||
|
import MetadataBar, { MetadataType } from 'src/components/MetadataBar';
|
||||||
|
import getOwnerName from 'src/utils/getOwnerName';
|
||||||
|
|
||||||
|
export const useDashboardMetadataBar = (dashboardInfo: DashboardInfo) => {
|
||||||
|
const items = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
type: MetadataType.LastModified as const,
|
||||||
|
value: dashboardInfo.changed_on_delta_humanized,
|
||||||
|
modifiedBy:
|
||||||
|
getOwnerName(dashboardInfo.changed_by) || t('Not available'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: MetadataType.Owner as const,
|
||||||
|
createdBy: getOwnerName(dashboardInfo.created_by) || t('Not available'),
|
||||||
|
owners:
|
||||||
|
dashboardInfo.owners.length > 0
|
||||||
|
? dashboardInfo.owners.map(getOwnerName)
|
||||||
|
: t('None'),
|
||||||
|
createdOn: dashboardInfo.created_on_delta_humanized,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
dashboardInfo.changed_by,
|
||||||
|
dashboardInfo.changed_on_delta_humanized,
|
||||||
|
dashboardInfo.created_by,
|
||||||
|
dashboardInfo.created_on_delta_humanized,
|
||||||
|
dashboardInfo.owners,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return <MetadataBar items={items} tooltipPlacement="bottom" />;
|
||||||
|
};
|
||||||
|
|
@ -52,6 +52,9 @@ const initialState: { dashboardInfo: DashboardInfo } = {
|
||||||
conf: {},
|
conf: {},
|
||||||
},
|
},
|
||||||
crossFiltersEnabled: true,
|
crossFiltersEnabled: true,
|
||||||
|
created_on_delta_humanized: '',
|
||||||
|
changed_on_delta_humanized: '',
|
||||||
|
owners: [],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import Database from 'src/types/Database';
|
||||||
import { UrlParamEntries } from 'src/utils/urlUtils';
|
import { UrlParamEntries } from 'src/utils/urlUtils';
|
||||||
|
|
||||||
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
||||||
|
import Owner from 'src/types/Owner';
|
||||||
import { ChartState } from '../explore/types';
|
import { ChartState } from '../explore/types';
|
||||||
|
|
||||||
export type { Dashboard } from 'src/types/Dashboard';
|
export type { Dashboard } from 'src/types/Dashboard';
|
||||||
|
|
@ -139,6 +140,11 @@ export type DashboardInfo = {
|
||||||
};
|
};
|
||||||
crossFiltersEnabled: boolean;
|
crossFiltersEnabled: boolean;
|
||||||
filterBarOrientation: FilterBarOrientation;
|
filterBarOrientation: FilterBarOrientation;
|
||||||
|
created_on_delta_humanized: string;
|
||||||
|
changed_on_delta_humanized: string;
|
||||||
|
changed_by?: Owner;
|
||||||
|
created_by?: Owner;
|
||||||
|
owners: Owner[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChartsState = { [key: string]: Chart };
|
export type ChartsState = { [key: string]: Chart };
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Tooltip } from 'src/components/Tooltip';
|
import { Tooltip } from 'src/components/Tooltip';
|
||||||
import { css, logging, SupersetClient, t, tn } from '@superset-ui/core';
|
import { css, logging, SupersetClient, t } from '@superset-ui/core';
|
||||||
import { chartPropShape } from 'src/dashboard/util/propShapes';
|
import { chartPropShape } from 'src/dashboard/util/propShapes';
|
||||||
import AlteredSliceTag from 'src/components/AlteredSliceTag';
|
import AlteredSliceTag from 'src/components/AlteredSliceTag';
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
|
|
@ -29,10 +29,10 @@ import Icons from 'src/components/Icons';
|
||||||
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
import PropertiesModal from 'src/explore/components/PropertiesModal';
|
||||||
import { sliceUpdated } from 'src/explore/actions/exploreActions';
|
import { sliceUpdated } from 'src/explore/actions/exploreActions';
|
||||||
import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions';
|
import { PageHeaderWithActions } from 'src/components/PageHeaderWithActions';
|
||||||
import MetadataBar, { MetadataType } from 'src/components/MetadataBar';
|
|
||||||
import { setSaveChartModalVisibility } from 'src/explore/actions/saveModalActions';
|
import { setSaveChartModalVisibility } from 'src/explore/actions/saveModalActions';
|
||||||
import { applyColors, resetColors } from 'src/utils/colorScheme';
|
import { applyColors, resetColors } from 'src/utils/colorScheme';
|
||||||
import { useExploreAdditionalActionsMenu } from '../useExploreAdditionalActionsMenu';
|
import { useExploreAdditionalActionsMenu } from '../useExploreAdditionalActionsMenu';
|
||||||
|
import { useExploreMetadataBar } from './useExploreMetadataBar';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
actions: PropTypes.object.isRequired,
|
actions: PropTypes.object.isRequired,
|
||||||
|
|
@ -160,48 +160,7 @@ export const ExploreChartHeader = ({
|
||||||
metadata?.dashboards,
|
metadata?.dashboards,
|
||||||
);
|
);
|
||||||
|
|
||||||
const metadataBar = useMemo(() => {
|
const metadataBar = useExploreMetadataBar(metadata, slice);
|
||||||
if (!metadata) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const items = [];
|
|
||||||
items.push({
|
|
||||||
type: MetadataType.Dashboards,
|
|
||||||
title:
|
|
||||||
metadata.dashboards.length > 0
|
|
||||||
? tn(
|
|
||||||
'Added to 1 dashboard',
|
|
||||||
'Added to %s dashboards',
|
|
||||||
metadata.dashboards.length,
|
|
||||||
metadata.dashboards.length,
|
|
||||||
)
|
|
||||||
: t('Not added to any dashboard'),
|
|
||||||
description:
|
|
||||||
metadata.dashboards.length > 0
|
|
||||||
? t(
|
|
||||||
'You can preview the list of dashboards in the chart settings dropdown.',
|
|
||||||
)
|
|
||||||
: undefined,
|
|
||||||
});
|
|
||||||
items.push({
|
|
||||||
type: MetadataType.LastModified,
|
|
||||||
value: metadata.changed_on_humanized,
|
|
||||||
modifiedBy: metadata.changed_by || t('Not available'),
|
|
||||||
});
|
|
||||||
items.push({
|
|
||||||
type: MetadataType.Owner,
|
|
||||||
createdBy: metadata.created_by || t('Not available'),
|
|
||||||
owners: metadata.owners.length > 0 ? metadata.owners : t('None'),
|
|
||||||
createdOn: metadata.created_on_humanized,
|
|
||||||
});
|
|
||||||
if (slice?.description) {
|
|
||||||
items.push({
|
|
||||||
type: MetadataType.Description,
|
|
||||||
value: slice?.description,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return <MetadataBar items={items} tooltipPlacement="bottom" />;
|
|
||||||
}, [metadata, slice?.description]);
|
|
||||||
|
|
||||||
const oldSliceName = slice?.slice_name;
|
const oldSliceName = slice?.slice_name;
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { t, tn } from '@superset-ui/core';
|
||||||
|
import MetadataBar, { MetadataType } from 'src/components/MetadataBar';
|
||||||
|
import { ExplorePageInitialData } from 'src/explore/types';
|
||||||
|
|
||||||
|
export const useExploreMetadataBar = (
|
||||||
|
metadata: ExplorePageInitialData['metadata'],
|
||||||
|
slice: ExplorePageInitialData['slice'],
|
||||||
|
) =>
|
||||||
|
useMemo(() => {
|
||||||
|
if (!metadata) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const items = [];
|
||||||
|
if (metadata.dashboards) {
|
||||||
|
items.push({
|
||||||
|
type: MetadataType.Dashboards as const,
|
||||||
|
title:
|
||||||
|
metadata.dashboards.length > 0
|
||||||
|
? tn(
|
||||||
|
'Added to 1 dashboard',
|
||||||
|
'Added to %s dashboards',
|
||||||
|
metadata.dashboards.length,
|
||||||
|
metadata.dashboards.length,
|
||||||
|
)
|
||||||
|
: t('Not added to any dashboard'),
|
||||||
|
description:
|
||||||
|
metadata.dashboards.length > 0
|
||||||
|
? t(
|
||||||
|
'You can preview the list of dashboards in the chart settings dropdown.',
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
items.push({
|
||||||
|
type: MetadataType.LastModified as const,
|
||||||
|
value: metadata.changed_on_humanized,
|
||||||
|
modifiedBy: metadata.changed_by || t('Not available'),
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
type: MetadataType.Owner as const,
|
||||||
|
createdBy: metadata.created_by || t('Not available'),
|
||||||
|
owners: metadata.owners.length > 0 ? metadata.owners : t('None'),
|
||||||
|
createdOn: metadata.created_on_humanized,
|
||||||
|
});
|
||||||
|
if (slice?.description) {
|
||||||
|
items.push({
|
||||||
|
type: MetadataType.Description as const,
|
||||||
|
value: slice?.description,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return <MetadataBar items={items} tooltipPlacement="bottom" />;
|
||||||
|
}, [metadata, slice?.description]);
|
||||||
|
|
@ -82,6 +82,10 @@ export interface ExplorePageInitialData {
|
||||||
owners: string[];
|
owners: string[];
|
||||||
created_by?: string;
|
created_by?: string;
|
||||||
changed_by?: string;
|
changed_by?: string;
|
||||||
|
dashboards?: {
|
||||||
|
id: number;
|
||||||
|
dashboard_title: string;
|
||||||
|
}[];
|
||||||
};
|
};
|
||||||
saveAction?: SaveActionType | null;
|
saveAction?: SaveActionType | null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue