diff --git a/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx b/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx index e44b338d5..1588248a2 100644 --- a/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx +++ b/frontend/app/components/Dashboard/components/DashboardList/DashboardList.tsx @@ -1,147 +1,224 @@ import { LockOutlined, TeamOutlined } from '@ant-design/icons'; -import { Empty, Switch, Table, TableColumnsType, Tag, Tooltip, Typography } from 'antd'; +import { + Empty, + Switch, + Table, + TableColumnsType, + Tag, + Tooltip, + Typography, +} from 'antd'; import { observer } from 'mobx-react-lite'; import React from 'react'; import { connect } from 'react-redux'; -import { withRouter } from 'react-router-dom'; +import { useHistory } from 'react-router'; import { checkForRecent } from 'App/date'; import { useStore } from 'App/mstore'; import Dashboard from 'App/mstore/types/dashboard'; import { dashboardSelected, withSiteId } from 'App/routes'; +import CreateDashboardButton from 'Components/Dashboard/components/CreateDashboardButton'; +import { ItemMenu, confirm } from 'UI'; import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG'; -import CreateDashboardButton from "Components/Dashboard/components/CreateDashboardButton"; -import { useHistory } from "react-router"; -import classNames from 'classnames'; + +import DashboardEditModal from '../DashboardEditModal'; function DashboardList({ siteId }: { siteId: string }) { - const { dashboardStore } = useStore(); - const list = dashboardStore.filteredList; - const dashboardsSearch = dashboardStore.filter.query; - const history = useHistory(); + const [focusTitle, setFocusedInput] = React.useState(true); + const [showEditModal, setShowEditModal] = React.useState(false); - // Define custom width and height for each scenario - const searchImageDimensions = { width: 60, height: 'auto' }; - const defaultImageDimensions = { width: 600, height: 'auto' }; + const { dashboardStore } = useStore(); + const list = dashboardStore.filteredList; + const dashboardsSearch = dashboardStore.filter.query; + const history = useHistory(); - const tableConfig: TableColumnsType = [ - { - title: 'Title', - dataIndex: 'name', - width: '25%', - sorter: (a, b) => a.name?.localeCompare(b.name), - sortDirections: ['ascend', 'descend'], - render: (t) =>
{t}
, - }, - { - title: 'Owner', - dataIndex: 'owner', - width: '16.67%', - sorter: (a, b) => a.owner?.localeCompare(b.owner), - sortDirections: ['ascend', 'descend'], - render: (owner) =>
{owner}
, - }, - { - title: 'Last Modified', - dataIndex: 'updatedAt', - width: '16.67%', - sorter: (a, b) => a.updatedAt.toMillis() - b.updatedAt.toMillis(), - sortDirections: ['ascend', 'descend'], - render: (date) => checkForRecent(date, 'LLL dd, yyyy, hh:mm a'), - }, - - { - title: ( -
-
Visibility
- - - dashboardStore.updateKey('filter', { - ...dashboardStore.filter, - showMine: !dashboardStore.filter.showMine, - })} checkedChildren={'Team'} unCheckedChildren={'Private'} /> - -
- ), - width: '16.67%', - dataIndex: 'isPublic', - render: (isPublic: boolean) => ( - : } bordered={false} className='rounded-lg'> - {isPublic ? 'Team' : 'Private'} - - ), - }, - ]; + // Define custom width and height for each scenario + const searchImageDimensions = { width: 60, height: 'auto' }; + const defaultImageDimensions = { width: 600, height: 'auto' }; - const emptyDescription = dashboardsSearch !== '' ? ( -
-
- - No matching results - -
- Try adjusting your search criteria or creating a new dashboard. -
-
-
- ) : ( -
-
- - Create your first dashboard. - -
- Organize your product and technical insights as cards in dashboards to see the bigger picture. -
-
- -
-
-
- ); + const onEdit = (id: string, isTitle: boolean) => { + const dashboard = dashboardStore.getDashboard(id); + if (!dashboard) return; + dashboardStore.initDashboard(dashboard); + setFocusedInput(isTitle); + setShowEditModal(true); + }; - const emptyImage = dashboardsSearch !== '' ? ICONS.NO_RESULTS : ICONS.NO_DASHBOARDS; - const imageDimensions = dashboardsSearch !== '' ? searchImageDimensions : defaultImageDimensions; + const onDelete = async (id: string) => { + const dashboard = dashboardStore.getDashboard(id); + if (!dashboard) return; + if ( + await confirm({ + header: 'Delete Dashboard', + confirmButton: 'Yes, delete', + confirmation: `Are you sure you want to permanently delete this Dashboard?`, + }) + ) { + void dashboardStore.deleteDashboard(dashboard); + } + }; - return ( - list.length === 0 && !dashboardStore.filter.showMine ? ( -
- } - imageStyle={{ - width: imageDimensions.width, - height: imageDimensions.height, - margin: 'auto', - padding: '2rem 0' - }} - description={emptyDescription} - /> -
- ) : ( - - `Showing ${range[0]}-${range[1]} of ${total} items`, - size: 'small', - }} - onRow={(record) => ({ - onClick: () => { - dashboardStore.selectDashboardById(record.dashboardId); - const path = withSiteId( - dashboardSelected(record.dashboardId), - siteId - ); - history.push(path); - }, - })} + const tableConfig: TableColumnsType = [ + { + title: 'Title', + dataIndex: 'name', + width: '25%', + sorter: (a, b) => a.name?.localeCompare(b.name), + sortDirections: ['ascend', 'descend'], + render: (t) =>
{t}
, + }, + { + title: 'Owner', + dataIndex: 'owner', + width: '16.67%', + sorter: (a, b) => a.owner?.localeCompare(b.owner), + sortDirections: ['ascend', 'descend'], + render: (owner) =>
{owner}
, + }, + { + title: 'Last Modified', + dataIndex: 'updatedAt', + width: '16.67%', + sorter: (a, b) => a.updatedAt.toMillis() - b.updatedAt.toMillis(), + sortDirections: ['ascend', 'descend'], + render: (date) => checkForRecent(date, 'LLL dd, yyyy, hh:mm a'), + }, + + { + title: ( +
+
Visibility
+ + + dashboardStore.updateKey('filter', { + ...dashboardStore.filter, + showMine: !dashboardStore.filter.showMine, + }) + } + checkedChildren={'Team'} + unCheckedChildren={'Private'} /> - ) + +
+ ), + width: '16.67%', + dataIndex: 'isPublic', + render: (isPublic: boolean) => ( + : } + bordered={false} + className="rounded-lg" + > + {isPublic ? 'Team' : 'Private'} + + ), + }, + + { + title: 'Options', + dataIndex: 'dashboardId', + width: '5%', + onCell: () => ({ onClick: (e) => e.stopPropagation() }), + render: (id) => ( + onEdit(id, true) }, + { + icon: 'users', + text: 'Visibility & Access', + onClick: () => onEdit(id, false), + }, + { icon: 'trash', text: 'Delete', onClick: () => onDelete(id) }, + ]} + /> + ), + }, + ]; + + const emptyDescription = + dashboardsSearch !== '' ? ( +
+
+ + No matching results + +
+ Try adjusting your search criteria or creating a new dashboard. +
+
+
+ ) : ( +
+
+ + Create your first dashboard. + +
+ Organize your product and technical insights as cards in dashboards + to see the bigger picture. +
+
+ +
+
+
); + + const emptyImage = + dashboardsSearch !== '' ? ICONS.NO_RESULTS : ICONS.NO_DASHBOARDS; + const imageDimensions = + dashboardsSearch !== '' ? searchImageDimensions : defaultImageDimensions; + + return list.length === 0 && !dashboardStore.filter.showMine ? ( +
+ } + imageStyle={{ + width: imageDimensions.width, + height: imageDimensions.height, + margin: 'auto', + padding: '2rem 0', + }} + description={emptyDescription} + /> +
+ ) : ( + <> +
+ `Showing ${range[0]}-${range[1]} of ${total} items`, + size: 'small', + }} + onRow={(record) => ({ + onClick: () => { + dashboardStore.selectDashboardById(record.dashboardId); + const path = withSiteId( + dashboardSelected(record.dashboardId), + siteId + ); + history.push(path); + }, + })} + /> + setShowEditModal(false)} + focusTitle={focusTitle} + /> + + ); } export default connect((state: any) => ({ - siteId: state.getIn(['site', 'siteId']), + siteId: state.getIn(['site', 'siteId']), }))(observer(DashboardList));