Skip to content
This repository was archived by the owner on Feb 26, 2025. It is now read-only.

Develop #1545

Merged
merged 7 commits into from
Sep 16, 2024
Merged

Develop #1545

Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions .github/workflows/review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: [pull_request]

jobs:
test-and-build:
runs-on: it
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
Expand Down Expand Up @@ -35,7 +35,7 @@ jobs:
run: |
docker build . --tag=nexus-web:fresh
- name: Start services
run: docker-compose -f ci/docker-compose.yml up -d && sleep 60
run: docker compose -f ci/docker-compose.yml up -d && sleep 60
- name: Copy nexus-web into Cypress container
# avoids permission issue where cypress writes screenshots to host with root as user
# which we can't then delete easily
Expand All @@ -55,4 +55,4 @@ jobs:
# --key ${{ secrets.CYPRESS_RECORD_KEY }}
- name: Cleanup Docker Containers
if: ${{ always() }}
run: docker-compose -f ci/docker-compose.yml down --rmi "local" --volumes
run: docker compose -f ci/docker-compose.yml down --rmi "local" --volumes
14 changes: 11 additions & 3 deletions src/shared/components/IDResolution/ResponseViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@ type Props = {
data: any;
header?: string;
showHeader?: boolean;
collapsed?: boolean;
style?: React.CSSProperties;
};

const ResponseViewer = ({ data, showHeader = false, header = '' }: Props) => {
const ResponseViewer = ({
data,
showHeader = false,
header = '',
collapsed = false,
style = {},
}: Props) => {
return (
<ReactJson
collapsed
collapsed={collapsed}
name={showHeader ? header : undefined}
src={data as object}
indentWidth={3}
iconStyle="square"
enableClipboard={false}
displayObjectSize={false}
displayDataTypes={false}
style={{ maxWidth: 'inherit', width: '600px' }}
style={{ maxWidth: 'inherit', width: '600px', ...style }}
/>
);
};
Expand Down
1 change: 1 addition & 0 deletions src/shared/components/Preview/PDFPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const PDFThumbnail = ({
file={url}
onLoadError={console.error}
renderMode="svg"
options={{ isEvalSupported: false }}
>
<Page
className="pdf-thumbnail-page"
Expand Down
167 changes: 167 additions & 0 deletions src/shared/containers/DataTableContainer.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import configureStore from '../store';
import { cleanup, render, screen, waitFor } from '../../utils/testUtil';
import DataTableContainer from './DataTableContainer';
import { notification } from 'antd';
import { getMockResource } from '__mocks__/handlers/DataExplorer/handlers';

describe('DataTableContainer.spec.tsx', () => {
const queryClient = new QueryClient();
Expand Down Expand Up @@ -421,6 +422,172 @@ describe('DataTableContainer - Selection', () => {
});
});

describe('DataTableContainer - Row Click', () => {
const queryClient = new QueryClient();
let dataTableContainer: JSX.Element;
let container: HTMLElement;
let rerender: (ui: React.ReactElement) => void;
let user: UserEvent;
let server: ReturnType<typeof setupServer>;
let component: RenderResult;
let nexus: ReturnType<typeof createNexusClient>;
let nexusSpy: jest.SpyInstance;

beforeAll(() => {
server = setupServer(
dashboardResource,
dashboardVocabulary,
fetchResourceForDownload
);

server.listen();
});

beforeEach(async () => {
const history = createMemoryHistory({});

nexus = createNexusClient({
fetch,
uri: deltaPath(),
});
const store = configureStore(history, { nexus }, {});
dataTableContainer = (
<Provider store={store}>
<Router history={history}>
<QueryClientProvider client={queryClient}>
<NexusProvider nexusClient={nexus}>
<DataTableContainer
orgLabel="bbp"
projectLabel="agents"
tableResourceId="https://dev.nise.bbp.epfl.ch/nexus/v1/resources/bbp/agents/_/8478b9ae-c50e-4178-8aae-16221f2c6937"
options={{
disableAddFromCart: true,
disableDelete: true,
disableEdit: true,
}}
/>
</NexusProvider>
</QueryClientProvider>
</Router>
</Provider>
);

component = render(dataTableContainer);

container = component.container;
rerender = component.rerender;
user = userEvent.setup();

nexusSpy = jest
.spyOn(nexus, 'httpGet')
.mockImplementation(request =>
request.path.toString().includes('format')
? Promise.resolve([getMockResource('doesnt-matter', {}, 'agents')])
: Promise.resolve(getMockResource('doesnt-matter', {}, 'agents'))
);
});

// reset any request handlers that are declared as a part of our tests
// (i.e. for testing one-time error scenarios)
afterEach(() => {
cleanup();
queryClient.clear();
localStorage.clear();
nexusSpy.mockClear();
});

afterAll(() => {
server.resetHandlers();
server.close();
});

const visibleTableRows = () => {
return container.querySelectorAll('table tbody tr.data-table-row');
};

const waitForTableRows = async (expectedRowsCount: number) => {
return await waitFor(() => {
const rows = visibleTableRows();
expect(rows.length).toEqual(expectedRowsCount);
return rows;
});
};

it('requests correct resource from delta when user clicks on row with revision in self', async () => {
const selfWithRevision =
'https://localhost:3000/resources/bbp/agents/_/persons%2Fc3358e61-7650-4954-99b7-f7572cbf5d5g?rev=30';

const resources = [getMockStudioResource('Malory', `${selfWithRevision}`)];

server.use(sparqlViewResultHandler(resources));
component.unmount();
rerender(dataTableContainer);
await waitForTableRows(1);

await user.click(screen.getByText('Malory'));
expect(nexusSpy).toHaveBeenLastCalledWith({
path: `${selfWithRevision}&format=expanded`,
headers: { Accept: 'application/json' },
});
});

it('requests correct resource from delta when user clicks on row with tag in self', async () => {
const selfWithTag =
'https://localhost:3000/resources/bbp/agents/_/persons%2Fc3358e61-7650-4954-99b7-f7572cbf5d5g?tag=30';

const resources = [getMockStudioResource('Malory', `${selfWithTag}`)];

server.use(sparqlViewResultHandler(resources));
component.unmount();
rerender(dataTableContainer);
await waitForTableRows(1);

await user.click(screen.getByText('Malory'));
expect(nexusSpy).toHaveBeenLastCalledWith({
path: `${selfWithTag}&format=expanded`,
headers: { Accept: 'application/json' },
});
});

it('requests correct resource from delta when user clicks on row with tag and revision in self', async () => {
const selfWithTagAndRev =
'https://localhost:3000/resources/bbp/agents/_/persons%2Fc3358e61-7650-4954-99b7-f7572cbf5d5g?tag=30&rev=2-';

const resources = [getMockStudioResource('Malory', `${selfWithTagAndRev}`)];

server.use(sparqlViewResultHandler(resources));
component.unmount();
rerender(dataTableContainer);
await waitForTableRows(1);

await user.click(screen.getByText('Malory'));
expect(nexusSpy).toHaveBeenLastCalledWith({
path: `${selfWithTagAndRev}&format=expanded`,
headers: { Accept: 'application/json' },
});
});

it('requests correct resource from delta when user clicks on row with no tag or revision in self', async () => {
const selfWithoutTagOrRev =
'https://localhost:3000/resources/bbp/agents/_/persons%2Fc3358e61-7650-4954-99b7-f7572cbf5d5g';

const resources = [
getMockStudioResource('Malory', `${selfWithoutTagOrRev}`),
];

server.use(sparqlViewResultHandler(resources));
component.unmount();
rerender(dataTableContainer);
await waitForTableRows(1);

await user.click(screen.getByText('Malory'));
expect(nexusSpy).toHaveBeenLastCalledWith({
path: `${selfWithoutTagOrRev}?format=expanded`,
headers: { Accept: 'application/json' },
});
});
});

const dashboardErrorResponse = {
'@context': 'https://bluebrain.github.io/nexus/contexts/error.json',
'@type': 'ResourceNotFound',
Expand Down
4 changes: 3 additions & 1 deletion src/shared/containers/DataTableContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,11 @@ const DataTableContainer: React.FC<DataTableProps> = ({
if (resource['@type'] === 'Project') {
return;
}
const url = new URL(selfUrl);
url.searchParams.set('format', 'expanded');
nexus
.httpGet({
path: `${selfUrl}?format=expanded`,
path: `${url.toString()}`,
headers: { Accept: 'application/json' },
})
.then((fullIdResponse: Resource) => {
Expand Down
104 changes: 62 additions & 42 deletions src/shared/containers/ResourceViewContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import VideoPluginContainer from './VideoPluginContainer/VideoPluginContainer';
import { useMutation } from 'react-query';

export const DEFAULT_ACTIVE_TAB_KEY = '#JSON';
import ResponseViewer from '../../shared/components/IDResolution/ResponseViewer';

export type PluginMapping = {
[pluginKey: string]: object;
Expand Down Expand Up @@ -707,48 +708,67 @@ const ResourceViewContainer: FC<{

<Spin spinning={busy}>
{!!error ? (
<Alert
message={
error.wasUpdated ? 'Resource updated with errors' : 'Error'
}
showIcon
closable
style={{ marginTop: 40 }}
type="error"
description={
<>
<Typography.Paragraph
ellipsis={{ rows: 2, expandable: true }}
>
{error.message}
</Typography.Paragraph>
{error.rejections && (
<Collapse bordered={false} ghost>
<Collapse.Panel key={1} header="More detail...">
<>
<ul>
{error.rejections.map((el, ix) => (
<li key={ix}>{el.reason}</li>
))}
</ul>

<p>
For further information please refer to the API
documentation,{' '}
<a
target="_blank"
href="https://bluebrainnexus.io/docs/delta/api"
>
https://bluebrainnexus.io/docs/delta/api
</a>
</p>
</>
</Collapse.Panel>
</Collapse>
)}
</>
}
/>
<>
<Alert
message={
error.wasUpdated ? 'Resource updated with errors' : 'Error'
}
showIcon
closable
style={{ marginTop: 40 }}
type="error"
description={
<>
<Typography.Paragraph
ellipsis={{ rows: 2, expandable: true }}
>
{error.message}
</Typography.Paragraph>
{error.rejections && (
<Collapse bordered={false} ghost>
<Collapse.Panel key={1} header="More detail...">
<>
<ul>
{error.rejections.map((el, ix) => (
<li key={ix}>{el.reason}</li>
))}
</ul>

<p>
For further information please refer to the API
documentation,{' '}
<a
target="_blank"
href="https://bluebrainnexus.io/docs/delta/api"
>
https://bluebrainnexus.io/docs/delta/api
</a>
</p>
</>
</Collapse.Panel>
</Collapse>
)}
</>
}
/>
<div
style={{
display: 'flex',
justifyContent: 'center',
marginTop: '28px',
}}
>
<ResponseViewer
data={error}
showHeader={false}
style={{
width: '1000px',
background: 'white',
padding: '10px',
}}
/>
</div>
</>
) : (
<>
{resource && (
Expand Down
3 changes: 1 addition & 2 deletions src/subapps/studioLegacy/containers/StudioContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import * as React from 'react';
import { Resource } from '@bbp/nexus-sdk';
import { useNexusContext, AccessControl } from '@bbp/react-nexus';
import { Empty, message } from 'antd';
import { omitBy } from 'lodash';
import { useHistory } from 'react-router';

import { omitBy } from 'lodash';
import EditStudio from '../components/EditStudio';
import StudioHeader from '../components/StudioHeader';
import StudioReactContext from '../contexts/StudioContext';
Expand Down
Loading