diff --git a/react/src/components/Projects/ProjectListing.module.css b/react/src/components/Projects/ProjectListing.module.css new file mode 100644 index 00000000..554d5860 --- /dev/null +++ b/react/src/components/Projects/ProjectListing.module.css @@ -0,0 +1,50 @@ +.root { + display: flex; + width: 100%; +} +.projectList { + width: 100%; + table-layout: fixed; + padding: 10px; +} +.errorMessage { + width: 100%; + padding: 10px; +} +.projectList th { + background: #d0d0d0; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.projectList tr, +td { + width: 100%; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.projectList tr:hover td { + color: white; + background-color: var(--global-color-accent--light); +} +.projectList tr:hover td button { + color: white; +} +.mapColumn { + width: 42%; +} +.projectColumn { + width: 42%; +} +.buttonColumn { + width: 16%; + text-align: end; +} +.buttonColumn button { + max-width: 100%; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + justify-content: flex-start; +} diff --git a/react/src/components/Projects/ProjectListing.tsx b/react/src/components/Projects/ProjectListing.tsx index c8edc0ec..a99d5171 100644 --- a/react/src/components/Projects/ProjectListing.tsx +++ b/react/src/components/Projects/ProjectListing.tsx @@ -1,12 +1,14 @@ import React, { useState } from 'react'; import { useProjectsWithDesignSafeInformation } from '@hazmapper/hooks'; -import { Button, LoadingSpinner } from '@tacc/core-components'; +import { Button, LoadingSpinner, SectionMessage } from '@tacc/core-components'; +import { EmptyTablePlaceholder } from '../utils'; +import styles from './ProjectListing.module.css'; import CreateMapModal from '../CreateMapModal/CreateMapModal'; import DeleteMapModal from '../DeleteMapModal/DeleteMapModal'; import { Project } from '../../types'; import { useNavigate } from 'react-router-dom'; -export const ProjectListing: React.FC = () => { +const ProjectListing: React.FC = () => { const [isModalOpen, setIsModalOpen] = useState(false); const [selectedProjectForDeletion, setSelectedProjectForDeletion] = useState(null); @@ -20,67 +22,84 @@ export const ProjectListing: React.FC = () => { setIsModalOpen(!isModalOpen); }; - const { data, isLoading, isError } = useProjectsWithDesignSafeInformation(); + const { data, isLoading, isError, error } = + useProjectsWithDesignSafeInformation(); if (isLoading) { return ; } if (isError) { - return

Unable to retrieve projects

; + return ( +
+
+ + There was an error gathering your maps.{' '} + {error?.message ? error?.message : 'An unknown error occurred.'} +
+ + Click here to submit a ticket to DesignSafe. + +
+
+
+ ); } return ( - <> - +
+
- - - + + - {data?.map((proj) => ( - - - navigateToProject(proj.uuid)}> + + - - - ))} + + + + )) + ) : ( + + )}
MapProject + MapProject -
- {' '} - - - {' '} -
{proj.name} {proj.ds_project ? `${proj.ds_project?.value.projectId} | ${proj.ds_project?.value.title}` : '---------'} - - - - -
+ + +
+ + No maps found. +
+ {' '} + to get started. +
+
- {selectedProjectForDeletion && ( { project={selectedProjectForDeletion} /> )} - + ); }; + +export default ProjectListing; diff --git a/react/src/components/Projects/index.ts b/react/src/components/Projects/index.ts index d4d7f8d0..abef4bd4 100644 --- a/react/src/components/Projects/index.ts +++ b/react/src/components/Projects/index.ts @@ -1 +1 @@ -export { ProjectListing } from './ProjectListing'; +export { default } from './ProjectListing'; diff --git a/react/src/components/utils/EmptyTablePlaceholder.module.css b/react/src/components/utils/EmptyTablePlaceholder.module.css new file mode 100644 index 00000000..4f33ab91 --- /dev/null +++ b/react/src/components/utils/EmptyTablePlaceholder.module.css @@ -0,0 +1,12 @@ +/* Table Placeholder */ +.empty { + display: flex; + align-items: center; + justify-content: center; +} + +.empty > :first-child { + margin-top: 10px; + padding: 50px; + border: 1px solid var(--global-color-primary--dark); +} diff --git a/react/src/components/utils/EmptyTablePlaceholder.tsx b/react/src/components/utils/EmptyTablePlaceholder.tsx new file mode 100644 index 00000000..18c503d6 --- /dev/null +++ b/react/src/components/utils/EmptyTablePlaceholder.tsx @@ -0,0 +1,25 @@ +import { SectionMessage } from '@tacc/core-components'; +import styles from './EmptyTablePlaceholder.module.css'; +import React from 'react'; + +interface EmptyPlaceholderProps { + children?: React.ReactNode; + type: 'error' | 'warning' | 'info' | 'success'; +} + +export const EmptyTablePlaceholder: React.FC = ({ + children, + type, +}) => { + return ( +
+ {children ? ( + {children} + ) : ( + No data available. + )} +
+ ); +}; + +export default EmptyTablePlaceholder; diff --git a/react/src/components/utils/index.ts b/react/src/components/utils/index.ts new file mode 100644 index 00000000..bfe0cec0 --- /dev/null +++ b/react/src/components/utils/index.ts @@ -0,0 +1 @@ +export { default as EmptyTablePlaceholder } from './EmptyTablePlaceholder'; diff --git a/react/src/hazmapper.css b/react/src/hazmapper.css index 919c0f5c..4ca981c2 100644 --- a/react/src/hazmapper.css +++ b/react/src/hazmapper.css @@ -1,10 +1,7 @@ -@import url('@tacc/core-styles/dist/core-styles.base.css'); -@import url('@tacc/core-styles/dist/core-styles.portal.css'); - /* for hazmapper specific overwrites of base and portal styles" like, :root { - --global-color-accent--xx-light: blue; +--global-color-accent--xx-light: blue; } */ diff --git a/react/src/hooks/projects/useProjects.ts b/react/src/hooks/projects/useProjects.ts index 025cbc91..224f57c1 100644 --- a/react/src/hooks/projects/useProjects.ts +++ b/react/src/hooks/projects/useProjects.ts @@ -7,6 +7,10 @@ import { } from '@hazmapper/types'; import { useGet, useDelete } from '@hazmapper/requests'; +type QueryError = { + message?: string; +}; + export const useProjects = (): UseQueryResult => { const query = useGet({ endpoint: '/projects/', @@ -49,7 +53,8 @@ export const useDsProjects = (): UseQueryResult< }; export function useProjectsWithDesignSafeInformation(): UseQueryResult< - Project[] + Project[], + QueryError > { const dsProjectQuery = useDsProjects(); const projectQuery = useProjects(); @@ -77,8 +82,8 @@ export function useProjectsWithDesignSafeInformation(): UseQueryResult< isLoading: dsProjectQuery.isLoading || projectQuery.isLoading, isError: dsProjectQuery.error || projectQuery.error, isSuccess: dsProjectQuery.isSuccess && projectQuery.isSuccess, - error: dsProjectQuery.error || projectQuery.error, - } as UseQueryResult; + error: (dsProjectQuery.error || projectQuery.error) as QueryError, + } as UseQueryResult; } export const useDeleteProject = (projectId: number) => { diff --git a/react/src/index.css b/react/src/index.css index 70e3ac95..27f096d5 100644 --- a/react/src/index.css +++ b/react/src/index.css @@ -3,7 +3,7 @@ /* prettier-ignore */ @import url('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css') layer(foundation); -@import url('@tacc/core-styles/dist/core-styles.base.css'); /* layer(base);*/ -@import url('@tacc/core-styles/dist/core-styles.portal.css'); /* layer(base);*/ +@import url('@tacc/core-styles/dist/core-styles.base.css') layer(base); +@import url('@tacc/core-styles/dist/core-styles.portal.css') layer(base); @import url('./hazmapper.css') layer(project); diff --git a/react/src/pages/MainMenu/MainMenu.tsx b/react/src/pages/MainMenu/MainMenu.tsx index d3b5adf1..e9b50e6c 100644 --- a/react/src/pages/MainMenu/MainMenu.tsx +++ b/react/src/pages/MainMenu/MainMenu.tsx @@ -7,7 +7,7 @@ import { } from '@tacc/core-components'; import useAuthenticatedUser from '@hazmapper/hooks/user/useAuthenticatedUser'; import { SystemSelect } from '@hazmapper/components/Systems'; -import { ProjectListing } from '@hazmapper/components/Projects/ProjectListing'; +import ProjectListing from '@hazmapper/components/Projects/ProjectListing'; const MainMenu = () => { const {