Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

task/WG-232-React-Listing-UI #268

Merged
merged 24 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
82ac31a
task/WG-232-React-Listing-UI-clean
sophia-massie Oct 3, 2024
8304f93
- Linting
sophia-massie Oct 3, 2024
b5c2a4e
- Adds better response and error handling.
sophia-massie Oct 3, 2024
e5a4817
- Linting
sophia-massie Oct 3, 2024
0ff0f14
- Addresses Type 'ReactNode' is not assignable to
sophia-massie Oct 3, 2024
d55959d
- Linting
sophia-massie Oct 3, 2024
dfa4af2
- Address changes - removed fontawesome,
sophia-massie Oct 28, 2024
50d748f
Merge branch 'main' into task/WG-232-React-Listing-UI-clean
sophia-massie Oct 30, 2024
555c8ae
- Addresses changes
sophia-massie Oct 30, 2024
16e3a3e
- Linting
sophia-massie Oct 30, 2024
ee9fc43
- Undoing unnecessary diff
sophia-massie Oct 30, 2024
99821f5
- Adds hover function
sophia-massie Oct 30, 2024
9a6dd50
- Fixes hover change to reduce diff
sophia-massie Oct 30, 2024
08c7f56
Merge branch 'main' into task/WG-232-React-Listing-UI-clean
sophia-massie Oct 30, 2024
3072b0c
- Adds placeholder for empty DS projects
sophia-massie Oct 30, 2024
dc21d68
Merge branch 'task/WG-232-React-Listing-UI-clean' of github.com:TACC-…
sophia-massie Oct 30, 2024
d9b2607
- Removes issue with width
sophia-massie Oct 30, 2024
bee9325
- Linting
sophia-massie Oct 30, 2024
9b7e5c4
Merge branch 'main' into task/WG-232-React-Listing-UI-clean
sophia-massie Nov 9, 2024
7a9db80
Merge branch 'main' into task/WG-232-React-Listing-UI-clean
sophia-massie Nov 9, 2024
ec0f60e
- Casts error message to avoid type issues
sophia-massie Nov 9, 2024
20a0b54
Merge branch 'main' into task/WG-232-React-Listing-UI-clean
sophia-massie Nov 14, 2024
fab0b14
- Ensures content fits within column containers
sophia-massie Nov 14, 2024
c90c18d
- Linting
sophia-massie Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions react/src/components/Projects/ProjectListing.module.css
Original file line number Diff line number Diff line change
@@ -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;
}
101 changes: 61 additions & 40 deletions react/src/components/Projects/ProjectListing.tsx
Original file line number Diff line number Diff line change
@@ -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<Project | null>(null);
Expand All @@ -20,74 +22,93 @@ export const ProjectListing: React.FC = () => {
setIsModalOpen(!isModalOpen);
};

const { data, isLoading, isError } = useProjectsWithDesignSafeInformation();
const { data, isLoading, isError, error } =
useProjectsWithDesignSafeInformation();

if (isLoading) {
return <LoadingSpinner />;
}

if (isError) {
return <h4>Unable to retrieve projects</h4>;
return (
sophia-massie marked this conversation as resolved.
Show resolved Hide resolved
<div className={styles.root}>
<div className={styles.errorMessage}>
<SectionMessage type="error">
There was an error gathering your maps.{' '}
{error?.message ? error?.message : 'An unknown error occurred.'}
<br />
<a
href="https://www.designsafe-ci.org/help/new-ticket/"
target="_blank"
rel="noreferrer"
>
Click here to submit a ticket to DesignSafe.
</a>
</SectionMessage>
</div>
</div>
);
}

return (
<>
<table>
<div className={styles.root}>
<table className={styles.projectList}>
<thead>
<tr>
<th>Map</th>
<th>Project</th>
<th>
<th className={styles.mapColumn}>Map</th>
<th className={styles.projectColumn}>Project</th>
<th className={styles.buttonColumn}>
<CreateMapModal isOpen={isModalOpen} toggle={toggleModal} />
<Button onClick={toggleModal} size="small">
<Button onClick={toggleModal} type="link" iconNameBefore="add">
Create a New Map
</Button>
</th>
</tr>
</thead>
<tbody>
{data?.map((proj) => (
<tr key={proj.id}>
<td>
{' '}
<Button
type="link"
onClick={() => navigateToProject(proj.uuid)}
>
{proj.name}
</Button>
</td>
<td>
{' '}
<Button
type="link"
onClick={() => navigateToProject(proj.uuid)}
>
{data && data?.length > 0 ? (
data.map((proj) => (
<tr key={proj.id} onClick={() => navigateToProject(proj.uuid)}>
<td className={styles.mapColumn}>{proj.name}</td>
<td className={styles.projectColumn}>
{proj.ds_project
? `${proj.ds_project?.value.projectId} |
${proj.ds_project?.value.title}`
: '---------'}
</Button>
</td>
<td>
<Button iconNameBefore="edit-document"></Button>
<Button
iconNameBefore="trash"
onClick={() => setSelectedProjectForDeletion(proj)}
></Button>
</td>
</tr>
))}
</td>
<td className={styles.buttonColumn}>
<Button type="link" iconNameBefore="edit-document"></Button>
<Button
type="link"
iconNameBefore="trash"
onClick={() => setSelectedProjectForDeletion(proj)}
></Button>
</td>
</tr>
))
) : (
<td colSpan={3}>
<EmptyTablePlaceholder type="info">
No maps found.
<br />
<Button type="link" onClick={toggleModal}>
Create New Map
</Button>{' '}
to get started.
</EmptyTablePlaceholder>
</td>
)}
</tbody>
</table>

{selectedProjectForDeletion && (
<DeleteMapModal
isOpen={!!selectedProjectForDeletion}
close={() => setSelectedProjectForDeletion(null)}
project={selectedProjectForDeletion}
/>
)}
</>
</div>
);
};

export default ProjectListing;
2 changes: 1 addition & 1 deletion react/src/components/Projects/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { ProjectListing } from './ProjectListing';
export { default } from './ProjectListing';
12 changes: 12 additions & 0 deletions react/src/components/utils/EmptyTablePlaceholder.module.css
Original file line number Diff line number Diff line change
@@ -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);
}
25 changes: 25 additions & 0 deletions react/src/components/utils/EmptyTablePlaceholder.tsx
Original file line number Diff line number Diff line change
@@ -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<EmptyPlaceholderProps> = ({
children,
type,
}) => {
return (
<div className={styles['empty']}>
{children ? (
<SectionMessage type={type}>{children}</SectionMessage>
) : (
<SectionMessage type={type}>No data available.</SectionMessage>
)}
</div>
);
};

export default EmptyTablePlaceholder;
1 change: 1 addition & 0 deletions react/src/components/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as EmptyTablePlaceholder } from './EmptyTablePlaceholder';
5 changes: 1 addition & 4 deletions react/src/hazmapper.css
Original file line number Diff line number Diff line change
@@ -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;
}
*/

Expand Down
11 changes: 8 additions & 3 deletions react/src/hooks/projects/useProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import {
} from '@hazmapper/types';
import { useGet, useDelete } from '@hazmapper/requests';

type QueryError = {
message?: string;
};

export const useProjects = (): UseQueryResult<Project[]> => {
const query = useGet<Project[]>({
endpoint: '/projects/',
Expand Down Expand Up @@ -49,7 +53,8 @@ export const useDsProjects = (): UseQueryResult<
};

export function useProjectsWithDesignSafeInformation(): UseQueryResult<
Project[]
Project[],
QueryError
> {
const dsProjectQuery = useDsProjects();
const projectQuery = useProjects();
Expand Down Expand Up @@ -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<Project[]>;
error: (dsProjectQuery.error || projectQuery.error) as QueryError,
} as UseQueryResult<Project[], QueryError>;
}

export const useDeleteProject = (projectId: number) => {
Expand Down
4 changes: 2 additions & 2 deletions react/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -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);
2 changes: 1 addition & 1 deletion react/src/pages/MainMenu/MainMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading