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-238 panel assets listing #261

Merged
merged 57 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
4fcb8c1
Add initial feature file tree
nathanfranklin Sep 19, 2024
fc2abec
Additional work on assets list
nathanfranklin Sep 20, 2024
ff4c6c9
Add sorting
nathanfranklin Sep 20, 2024
2f4123f
Improve doc
nathanfranklin Sep 20, 2024
9216df1
Improve styling and fix nodes of tree
nathanfranklin Sep 20, 2024
3fdc671
Add todo
nathanfranklin Sep 20, 2024
f16352b
Refactor and add test
nathanfranklin Sep 23, 2024
2f305e2
Refactor into new files
nathanfranklin Sep 23, 2024
2b05b08
Move FeatureFileNode into types
nathanfranklin Sep 23, 2024
1c00bfe
Use font awesome for folder icon
nathanfranklin Sep 23, 2024
b05a0c4
Fix spelling error
nathanfranklin Sep 23, 2024
2eeef58
Rework importing
nathanfranklin Sep 23, 2024
95175c4
Expand rows
nathanfranklin Sep 23, 2024
67c8351
Set witch of panel as 230px
nathanfranklin Sep 23, 2024
241cd2e
Remove todos
nathanfranklin Sep 23, 2024
44e1250
Ensure nodes are expanded at start
nathanfranklin Sep 24, 2024
3a87f28
Fix selection/hover and height of rows
nathanfranklin Oct 11, 2024
0333927
Fix expanding rows on refresh
nathanfranklin Oct 11, 2024
e66ebf3
Add selected feature to route and fix row spacing
nathanfranklin Oct 12, 2024
1f58828
Merge branch 'main' into task/WG-238-panel-assets-listing
nathanfranklin Oct 21, 2024
76d23a7
Add useDelete
sophia-massie Oct 21, 2024
244aa45
Add functionality for feature deletion
nathanfranklin Oct 22, 2024
70134f6
Refactor MapProject
nathanfranklin Oct 23, 2024
80c23b2
Fix todos
nathanfranklin Oct 23, 2024
8ea8522
Add isLoading to button
nathanfranklin Oct 23, 2024
c19870f
Allow user to export feature geojson to file
nathanfranklin Oct 24, 2024
5737561
Add feature icon in asset listing
nathanfranklin Oct 24, 2024
998e6bf
Refactor types related to feature icon
nathanfranklin Oct 24, 2024
e58e743
Add missing useDeleteFeature
nathanfranklin Oct 25, 2024
efa76b4
Add unit testing of getFeatureType
nathanfranklin Oct 25, 2024
ea5b2c9
Fix linting
nathanfranklin Oct 25, 2024
ab0e68e
Add AssetsPanel test
nathanfranklin Oct 25, 2024
a82eb91
Add FeatureFileTree unit test
nathanfranklin Oct 25, 2024
29b4d75
Bump testing-library/react to get rid of act warnings
nathanfranklin Oct 25, 2024
b4e8c91
Removed unused
nathanfranklin Oct 25, 2024
3d121ce
Add antd
nathanfranklin Oct 29, 2024
fba6261
Merge branch 'main' into task/WG-238-panel-assets-listing
nathanfranklin Oct 30, 2024
c3724f0
Switch to antd tree instead of react-table
nathanfranklin Oct 31, 2024
6bbcf71
Merge branch 'main' into task/WG-238-panel-assets-listing
nathanfranklin Oct 31, 2024
632d393
Fix accessibility-related warnings and fix unit tests
nathanfranklin Nov 1, 2024
d537889
Adjust width and overflow
nathanfranklin Nov 1, 2024
6aa69ca
Fix height issues
nathanfranklin Nov 1, 2024
29180da
Improve navbar
nathanfranklin Nov 1, 2024
5c10f64
Remove deprecated typs/antd.
nathanfranklin Nov 5, 2024
98b348a
Limit getting features to a single time
nathanfranklin Nov 5, 2024
bfd6a6f
Fix scaling of panel container
nathanfranklin Nov 5, 2024
f9bebe9
Rework tree to deal with virtual rendering issues
nathanfranklin Nov 5, 2024
6df48bf
Make nav bar scrolling when y overflows
nathanfranklin Nov 5, 2024
b5c7176
Make contents of project view take up space below nav/control bar
nathanfranklin Nov 6, 2024
feae104
Removed unneeded config and styles
nathanfranklin Nov 6, 2024
cf6123b
Move hazmapper globals to hazmapper.css
nathanfranklin Nov 6, 2024
7f79136
Add missing file
nathanfranklin Nov 6, 2024
4246b60
Merge branch 'main' into task/WG-238-panel-assets-listing
nathanfranklin Nov 11, 2024
64c9f48
Merge branch 'main' into task/WG-238-panel-assets-listing
nathanfranklin Nov 11, 2024
fdfa3dd
Update act import
nathanfranklin Nov 11, 2024
9e3c9e0
Merge branch 'task/WG-238-panel-assets-listing' of github.com:TACC-Cl…
nathanfranklin Nov 11, 2024
84f34a7
Fix bad merge
nathanfranklin Nov 11, 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
1,432 changes: 1,242 additions & 190 deletions react/package-lock.json

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,16 @@
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.21.0",
"@changey/react-leaflet-markercluster": "^4.0.0-rc1",
"@fortawesome/fontawesome-svg-core": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
"@reduxjs/toolkit": "^1.8.4",
"@tacc/core-components": "^0.0.3-beta.0",
"@tacc/core-styles": "^2.24.1",
"@turf/turf": "^6.5.0",
"@types/geojson": "^7946.0.14",
"@types/leaflet.markercluster": "^1.5.1",
"antd": "^5.21.6",
"axios": "^1.6.2",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jsx-a11y": "^6.6.1",
Expand Down
63 changes: 54 additions & 9 deletions react/src/__fixtures__/featuresFixture.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Point } from 'geojson';
import { FeatureCollection, AssetType } from '@hazmapper/types';

export const featureCollection = {
export const featureCollection: FeatureCollection = {
type: 'FeatureCollection',
features: [
{
id: 2053334,
id: 1,
project_id: 80,
type: 'Feature',
geometry: {
Expand All @@ -18,15 +19,15 @@ export const featureCollection = {
id: 2036568,
path: '80/f7c2afa2-f184-40a7-80be-0874a7db755e.jpeg',
uuid: 'f7c2afa2-f184-40a7-80be-0874a7db755e',
asset_type: 'image',
original_path: '/nathanf/image1.JPG',
asset_type: 'image' as AssetType,
original_path: '/foo/image1.JPG',
original_name: null,
display_path: '/nathanf/image1.JPG',
display_path: '/foo/image1.JPG',
},
],
},
{
id: 2053335,
id: 2,
project_id: 80,
type: 'Feature',
geometry: {
Expand All @@ -40,10 +41,54 @@ export const featureCollection = {
id: 2036569,
path: '80/5a3e7513-2740-4c0f-944d-7b497ceff2ea.jpeg',
uuid: '5a3e7513-2740-4c0f-944d-7b497ceff2ea',
asset_type: 'image',
original_path: '/nathanf/image1.JPG',
asset_type: 'image' as AssetType,
original_path: '/foo/image2.JPG',
original_name: null,
display_path: '/foo/image2.JPG',
},
],
},
],
};

export const featureCollectionWithNestedPaths: FeatureCollection = {
type: 'FeatureCollection',
features: [
{
id: 1,
project_id: 1,
type: 'Feature',
geometry: { type: 'Point', coordinates: [0, 0] } as Point,
properties: {},
styles: {},
assets: [
{
id: 1,
display_path: 'folder1/file1.jpg',
path: '',
uuid: '',
asset_type: 'image' as AssetType,
original_path: '',
original_name: null,
},
],
},
{
id: 2,
project_id: 1,
type: 'Feature',
geometry: { type: 'Point', coordinates: [0, 0] } as Point,
properties: {},
styles: {},
assets: [
{
id: 2,
display_path: 'folder1/subfolder/file2.rq',
path: '',
uuid: '',
asset_type: 'questionnaire' as AssetType,
original_path: '',
original_name: null,
display_path: '/nathanf/image1.JPG',
},
],
},
Expand Down
23 changes: 23 additions & 0 deletions react/src/components/AssetsPanel/AssetsPanel.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,27 @@
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
}

.topSection,
.bottomSection {
flex: 0 0 auto;
padding: 10px;
display: flex;
justify-content: center;
align-items: center;
}

.middleSection {
flex: 1 1 auto;
overflow: hidden;
min-height: 0;
display: flex;
flex-direction: column;
}

.middleSection > div {
flex: 1;
overflow: auto;
}
60 changes: 60 additions & 0 deletions react/src/components/AssetsPanel/AssetsPanel.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { act } from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import AssetsPanel from './AssetsPanel';
import { featureCollection } from '@hazmapper/__fixtures__/featuresFixture';
import { useFeatures } from '@hazmapper/hooks';

jest.mock('@hazmapper/hooks', () => ({
useFeatures: jest.fn(),
}));

// Mock FeatureFileTree component since it's a complex component and tested elswhere
jest.mock('@hazmapper/components/FeatureFileTree', () => {
return function MockFeatureFileTree() {
return <div data-testid="feature-file-tree">FeatureFileTree Component</div>;
};
});

describe('AssetsPanel', () => {
const defaultProps = {
featureCollection,
projectId: 1,
isPublic: false,
};

beforeEach(() => {
jest.clearAllMocks();

// Setup default mock implementation for useFeatures which is used for downloading geojson
(useFeatures as jest.Mock).mockReturnValue({
isLoading: false,
refetch: jest.fn(),
});
});

it('renders all main components', () => {
const { getByText } = render(<AssetsPanel {...defaultProps} />);

// Check for the presence of buttons
expect(getByText('Import from DesignSafe TODO/WG-387')).toBeDefined();
expect(getByText('Export to GeoJSON')).toBeDefined();
});

it('handles GeoJSON export correctly', async () => {
// Mock the useFeatures hook for download scenario
const mockRefetch = jest.fn();
(useFeatures as jest.Mock).mockReturnValue({
isLoading: false,
refetch: mockRefetch,
});

render(<AssetsPanel {...defaultProps} />);

// Click export button
await act(async () => {
fireEvent.click(screen.getByText('Export to GeoJSON'));
});
// Verify refetch was called
expect(mockRefetch).toHaveBeenCalled();
});
});
82 changes: 79 additions & 3 deletions react/src/components/AssetsPanel/AssetsPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,95 @@
import React from 'react';
import styles from './AssetsPanel.module.css';
import FeatureFileTree from '@hazmapper/components/FeatureFileTree';
import { FeatureCollection } from '@hazmapper/types';
import { Button } from '@tacc/core-components';
import { useFeatures } from '@hazmapper/hooks';

interface DownloadFeaturesButtonProps {
projectId: number;
isPublic: boolean;
}

const DownloadFeaturesButton: React.FC<DownloadFeaturesButtonProps> = ({
projectId,
isPublic,
}) => {
const { isLoading: isDownloading, refetch: triggerDownload } = useFeatures({
projectId,
isPublic,
assetTypes: [], // Empty array to get all features
options: {
enabled: false, // Only fetch when triggered by user clicking button
cacheTime: 0,
staleTime: 0,
onSuccess: (data: FeatureCollection) => {
// Create and trigger download
const blob = new Blob([JSON.stringify(data)], {
type: 'application/json',
});

const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `hazmapper.json`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the name of the download reflect the project name so that the user can differentiate downloads?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea 👍 Doing this in a follow on PR


document.body.appendChild(link);
link.click();

document.body.removeChild(link);
window.URL.revokeObjectURL(url);
},
},
});

return (
<Button isLoading={isDownloading} onClick={() => triggerDownload()}>
Export to GeoJSON
</Button>
);
};

interface Props {
/**
* Features of map
*/
featureCollection: FeatureCollection;

/**
* Whether or not the map project is public.
*/
isPublic: boolean;

/**
* active project id
*/
projectId: number;
}

/**
* A component that displays a map project (a map and related data)
* A panel component that displays info on feature assets
*/
const AssetsPanel: React.FC<Props> = ({ isPublic }) => {
const AssetsPanel: React.FC<Props> = ({
isPublic,
featureCollection,
projectId,
}) => {
return (
<div className={styles.root}>Assets Panel TODO, isPublic: {isPublic}</div>
<div className={styles.root}>
<div className={styles.topSection}>
<Button>Import from DesignSafe TODO/WG-387</Button>
</div>
<div className={styles.middleSection}>
<FeatureFileTree
projectId={projectId}
isPublic={isPublic}
featureCollection={featureCollection}
/>
</div>
<div className={styles.bottomSection}>
<DownloadFeaturesButton projectId={projectId} isPublic={isPublic} />
</div>
</div>
);
};

Expand Down
3 changes: 1 addition & 2 deletions react/src/components/DeleteMapModal/DeleteMapModal.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import React, { act } from 'react';
import { render, screen } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import { act } from 'react-dom/test-utils';
import { QueryClient, QueryClientProvider } from 'react-query';
import DeleteMapModal from './DeleteMapModal';
import { Provider } from 'react-redux';
Expand Down
57 changes: 57 additions & 0 deletions react/src/components/FeatureFileTree/FeatureFileTree.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
.root {
width: 100%;
overflow: visible;

:global(.ant-tree .ant-tree-treenode) {
margin-bottom: 0px !important; /*needed to ensure calculation of row hight is right */
}

/* Remove switcher space */
:global(.ant-tree-switcher) {
display: none;
}

/* Hovering over non-selected items */
:global(.ant-tree-node-content-wrapper:hover:not(.ant-tree-node-selected)) {
background-color: var(--global-color-accent--weak) !important;
}

/* Selected items (both normal and hover state) */ /*TODO*/
:global(.ant-tree-node-content-wrapper.ant-tree-node-selected) {
background-color: var(--global-color-accent--weak) !important;
}
}

.featureFileTree {
height: 100%;

:global(.ant-tree-node-content-wrapper) {
/*https://tacc-main.atlassian.net/browse/WG-390*/
font-size: var(--global-font-family--small);
font-family: var(--global-font-family--sans);
max-width: var(--hazmapper-panel-width); /* fixed width of panel*/
padding-left: 5px;
padding-right: 5px;
overflow: hidden;
}

/* Adjust indent size */
:global(.ant-tree-indent-unit) {
width: 8px;
}
}

.treeNode {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}

.fileName {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-left: 0.25em;
}
Loading
Loading