Skip to content

Commit

Permalink
support for tile duplication (#337)
Browse files Browse the repository at this point in the history
  • Loading branch information
balaji-jr authored Oct 3, 2024
1 parent c7c12a4 commit 59e05f8
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 7 deletions.
79 changes: 76 additions & 3 deletions src/pages/Dashboards/Dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Button, Divider, FileInput, Modal, Stack, Text } from '@mantine/core';
import { Box, Button, Divider, FileInput, Modal, Stack, Text, TextInput } from '@mantine/core';
import Toolbar from './Toolbar';
import 'react-grid-layout/css/styles.css';
import 'react-resizable/css/styles.css';
Expand All @@ -20,10 +20,10 @@ import { useDashboardsQuery } from '@/hooks/useDashboards';
import Tile from './Tile';
import { Layout } from 'react-grid-layout';
import { useAppStore } from '@/layouts/MainLayout/providers/AppProvider';
import { ImportDashboardType } from '@/@types/parseable/api/dashboards';
import { EditTileType, ImportDashboardType, Tile as TileType } from '@/@types/parseable/api/dashboards';
import { templates } from './assets/templates';

const { toggleCreateDashboardModal, toggleCreateTileModal, toggleDeleteTileModal, handlePaging, toggleImportDashboardModal } =
const { toggleCreateDashboardModal, toggleCreateTileModal, toggleDuplicateTileModal, toggleDeleteTileModal, handlePaging, toggleImportDashboardModal } =
dashboardsStoreReducers;

const TilesView = (props: { onLayoutChange: (layout: Layout[]) => void }) => {
Expand Down Expand Up @@ -319,6 +319,78 @@ const NoTilesView = () => {
);
};

const findTileByTileId = (tiles: TileType[], tileId: string | null) => {
return _.find(tiles, tile => tile.tile_id === tileId)
}

const DuplicateTileModal = () => {
const [duplicateTileModalOpen, setDashboardsStore] = useDashboardsStore(store => store.duplicateTileModalOpen)
const [editTileId] = useDashboardsStore(store => store.editTileId);
const [activeDashboard] = useDashboardsStore(store => store.activeDashboard)
const [inputValue, setInputValue] = useState<string>('');
const onClose = useCallback(() => {
setDashboardsStore((store) => toggleDuplicateTileModal(store, false, null));
}, []);

const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
}, []);
const { updateDashboard, isUpdatingDashboard } = useDashboardsQuery({});

const handleSubmit = useCallback(() => {
const currentTile = findTileByTileId(activeDashboard?.tiles || [], editTileId);
if (currentTile && activeDashboard) {
const currentOrder = currentTile.order;
const tempTiles = [...activeDashboard.tiles] as EditTileType[];
const duplicatedTile = _.omit({ ...currentTile, name: inputValue }, 'tile_id');
tempTiles.splice(currentOrder, 0, duplicatedTile);
const updatedTilesWithOrder = assignOrderToTiles(tempTiles);
return updateDashboard({
dashboard: { ...activeDashboard, tiles: updatedTilesWithOrder },
onSuccess: () => {
onClose();
},
});
}
}, [inputValue, editTileId, activeDashboard]);

useEffect(() => {
const currentTile = findTileByTileId(activeDashboard?.tiles || [], editTileId);
if (currentTile) {
setInputValue(currentTile?.name);
}
}, [editTileId]);

return (
<Modal
opened={duplicateTileModalOpen}
onClose={onClose}
size="auto"
centered
styles={{
body: { padding: '0 1rem 1rem 1rem', width: 400 },
header: { padding: '1rem', paddingBottom: '0.4rem' },
}}
title={<Text style={{ fontSize: '0.9rem', fontWeight: 600 }}>Duplicate Tile</Text>}>
<Stack>
<Stack gap={12}>
<TextInput value={inputValue} onChange={handleInputChange} />
</Stack>
<Stack style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end' }}>
<Box>
<Button onClick={onClose} variant="outline">
Cancel
</Button>
</Box>
<Box>
<Button onClick={handleSubmit} loading={isUpdatingDashboard} disabled={_.isEmpty(inputValue)}>Done</Button>
</Box>
</Stack>
</Stack>
</Modal>
);
};

const Dashboard = () => {
const [dashboards] = useDashboardsStore((store) => store.dashboards);
const layoutRef = useRef<Layout[]>([]);
Expand All @@ -333,6 +405,7 @@ const Dashboard = () => {
return (
<Stack style={{ flex: 1 }} gap={0}>
<DeleteTileModal />
<DuplicateTileModal/>
<Toolbar layoutRef={layoutRef} />
<ImportDashboardModal/>
<TilesView onLayoutChange={onLayoutChange} />
Expand Down
13 changes: 12 additions & 1 deletion src/pages/Dashboards/Tile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import classes from './styles/tile.module.css';
import {
IconAlertTriangle,
IconBraces,
IconCopyPlus,
IconDotsVertical,
IconGripVertical,
IconPencil,
Expand Down Expand Up @@ -71,7 +72,7 @@ const ParseableLogo = () => (
</div>
);

const { toggleCreateTileModal, toggleDeleteTileModal } = dashboardsStoreReducers;
const { toggleCreateTileModal, toggleDeleteTileModal, toggleDuplicateTileModal } = dashboardsStoreReducers;

const NoDataView = () => {
return (
Expand Down Expand Up @@ -171,6 +172,10 @@ function TileControls(props: { tile: TileType; data: TileQueryResponse }) {
setDashboardsStore((store) => toggleCreateTileModal(store, true, tile_id));
}, []);

const openDuplicateTileModal = useCallback(() => {
setDashboardsStore((store) => toggleDuplicateTileModal(store, true, tile_id));
}, []);

const openDeleteModal = useCallback(() => {
setDashboardsStore((store) => toggleDeleteTileModal(store, true, tile_id));
}, []);
Expand All @@ -197,6 +202,12 @@ function TileControls(props: { tile: TileType; data: TileQueryResponse }) {
leftSection={<IconPencil className={classes.tileCtrlItemIcon} size="1rem" stroke={1.2} />}>
<Text className={classes.tileCtrlItemText}>Edit</Text>
</Menu.Item>
<Menu.Item
className={classes.tileCtrlItem}
onClick={openDuplicateTileModal}
leftSection={<IconCopyPlus className={classes.tileCtrlItemIcon} size="1rem" stroke={1.2} />}>
<Text className={classes.tileCtrlItemText}>Duplicate</Text>
</Menu.Item>
<Menu.Item
className={classes.tileCtrlItem}
onClick={exportTileConfig}
Expand Down
17 changes: 14 additions & 3 deletions src/pages/Dashboards/providers/DashboardsProvider.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Dashboard, Tile, TileQueryResponse, tileSizeWidthMap } from '@/@types/parseable/api/dashboards';
import { Dashboard, EditTileType, Tile, TileQueryResponse, tileSizeWidthMap } from '@/@types/parseable/api/dashboards';
import initContext from '@/utils/initContext';
import _ from 'lodash';
import { Layout } from 'react-grid-layout';

export const TILES_PER_PAGE = 5;
export const TILES_PER_PAGE = 10;

export const sortTilesByOrder = (tiles: Tile[], idsByOrder: string[]): Tile[] => {
return _.chain(idsByOrder)
Expand All @@ -15,7 +15,7 @@ export const sortTilesByOrder = (tiles: Tile[], idsByOrder: string[]): Tile[] =>
.value();
};

export const assignOrderToTiles = (tiles: Tile[]) => {
export const assignOrderToTiles = (tiles: Tile[] | EditTileType[]) => {
return _.map(tiles, (tile, index) => {
return { ...tile, order: index + 1 };
});
Expand Down Expand Up @@ -77,6 +77,7 @@ type DashboardsStore = {
editDashboardModalOpen: boolean;
deleteDashboardModalOpen: boolean;
createTileFormOpen: boolean;
duplicateTileModalOpen: boolean;
vizEditorModalOpen: boolean;
allowDrag: boolean;
editTileId: string | null;
Expand All @@ -99,6 +100,7 @@ const initialState: DashboardsStore = {
deleteDashboardModalOpen: false,
createTileFormOpen: false,
vizEditorModalOpen: false,
duplicateTileModalOpen: false,
allowDrag: false,
editTileId: null,
tilesData: {},
Expand All @@ -118,6 +120,7 @@ type DashboardsStoreReducers = {
toggleEditDashboardModal: (store: DashboardsStore, val: boolean) => ReducerOutput;
selectDashboard: (store: DashboardsStore, dashboardId?: string | null, dashboard?: Dashboard) => ReducerOutput;
toggleCreateTileModal: (store: DashboardsStore, val: boolean, tileId?: string | null) => ReducerOutput;
toggleDuplicateTileModal: (store: DashboardsStore, val: boolean, tileId?: string | null) => ReducerOutput;
toggleVizEditorModal: (store: DashboardsStore, val: boolean) => ReducerOutput;
toggleAllowDrag: (store: DashboardsStore) => ReducerOutput;
toggleDeleteDashboardModal: (store: DashboardsStore, val: boolean) => ReducerOutput;
Expand Down Expand Up @@ -148,6 +151,13 @@ const toggleCreateTileModal = (_store: DashboardsStore, val: boolean, tileId: st
};
};

const toggleDuplicateTileModal = (_store: DashboardsStore, val: boolean, tileId: string | null = null) => {
return {
duplicateTileModalOpen: val,
editTileId: tileId,
};
};

const toggleVizEditorModal = (_store: DashboardsStore, val: boolean) => {
return {
vizEditorModalOpen: val,
Expand Down Expand Up @@ -275,6 +285,7 @@ const dashboardsStoreReducers: DashboardsStoreReducers = {
toggleImportTileModal,
toggleImportDashboardModal,
handlePaging,
toggleDuplicateTileModal
};

export { DashbaordsProvider, useDashboardsStore, dashboardsStoreReducers };

0 comments on commit 59e05f8

Please sign in to comment.