[ARVADOS-WORKBENCH2] updated: 1.4.1-367-g51041db2
Git user
git at public.arvados.org
Mon Jun 29 20:06:18 UTC 2020
Summary of changes:
src/common/config.ts | 3 +
src/index.tsx | 20 ++++---
src/models/resource.ts | 3 +-
src/routes/routes.ts | 4 +-
.../ancestors-service/ancestors-service.ts | 5 +-
src/services/api/api-actions.ts | 2 +-
src/services/common-service/common-service.ts | 10 ++--
src/store/navigation/navigation-action.ts | 1 -
.../not-found-panel/not-found-panel-root.test.tsx | 69 ++++++++++++++++++++++
src/views/not-found-panel/not-found-panel-root.tsx | 40 +++++++++++--
src/views/not-found-panel/not-found-panel.tsx | 3 +-
11 files changed, 133 insertions(+), 27 deletions(-)
create mode 100644 src/views/not-found-panel/not-found-panel-root.test.tsx
via 51041db20a296235ca14c6cc73f1ff7f1db2c0b7 (commit)
from dd4004015ae711939d2474dd8c6e031b6be2d0ff (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
commit 51041db20a296235ca14c6cc73f1ff7f1db2c0b7
Author: Daniel Kutyła <daniel.kutyla at contractors.roche.com>
Date: Mon Jun 29 22:05:26 2020 +0200
14990: added collections hash / uuid check
Arvados-DCO-1.1-Signed-off-by: Daniel Kutyła <daniel.kutyla at contractors.roche.com>
diff --git a/src/common/config.ts b/src/common/config.ts
index 39f9fbd1..cf539f3d 100644
--- a/src/common/config.ts
+++ b/src/common/config.ts
@@ -23,6 +23,9 @@ export interface ClusterConfigJSON {
Scheme: string
}
};
+ Mail?: {
+ SupportEmailAddress: string;
+ };
Services: {
Controller: {
ExternalURL: string
diff --git a/src/index.tsx b/src/index.tsx
index 2cee0540..1a58dad1 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -103,15 +103,17 @@ fetchConfig()
progressFn: (id, working) => {
store.dispatch(progressIndicatorActions.TOGGLE_WORKING({ id, working }));
},
- errorFn: (id, error) => {
- console.error("Backend error:", error);
- store.dispatch(snackbarActions.OPEN_SNACKBAR({
- message: `${error.errors
- ? error.errors[0]
- : error.message}`,
- kind: SnackbarKind.ERROR,
- hideDuration: 8000})
- );
+ errorFn: (id, error, showSnackBar) => {
+ if (showSnackBar) {
+ console.error("Backend error:", error);
+ store.dispatch(snackbarActions.OPEN_SNACKBAR({
+ message: `${error.errors
+ ? error.errors[0]
+ : error.message}`,
+ kind: SnackbarKind.ERROR,
+ hideDuration: 8000})
+ );
+ }
}
});
const store = configureStore(history, services);
diff --git a/src/models/resource.ts b/src/models/resource.ts
index d8cdd4a0..371278e5 100644
--- a/src/models/resource.ts
+++ b/src/models/resource.ts
@@ -62,8 +62,9 @@ export enum ResourceObjectType {
}
export const RESOURCE_UUID_PATTERN = '[a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}';
+export const PORTABLE_DATA_HASH_PATTERN = '[a-f0-9]{32}\\+\\d+';
export const RESOURCE_UUID_REGEX = new RegExp("^" + RESOURCE_UUID_PATTERN + "$");
-export const COLLECTION_PDH_REGEX = /^[a-f0-9]{32}\+\d+$/;
+export const COLLECTION_PDH_REGEX = new RegExp("^" + PORTABLE_DATA_HASH_PATTERN + "$");
export const isResourceUuid = (uuid: string) =>
RESOURCE_UUID_REGEX.test(uuid);
diff --git a/src/routes/routes.ts b/src/routes/routes.ts
index ebab383f..452589f6 100644
--- a/src/routes/routes.ts
+++ b/src/routes/routes.ts
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0
import { matchPath } from 'react-router';
-import { ResourceKind, RESOURCE_UUID_PATTERN, extractUuidKind, COLLECTION_PDH_REGEX } from '~/models/resource';
+import { ResourceKind, RESOURCE_UUID_PATTERN, extractUuidKind, COLLECTION_PDH_REGEX, PORTABLE_DATA_HASH_PATTERN } from '~/models/resource';
import { getProjectUrl } from '~/models/project';
import { getCollectionUrl } from '~/models/collection';
import { Config } from '~/common/config';
@@ -46,7 +46,7 @@ export const Routes = {
GROUP_DETAILS: `/group/:id(${RESOURCE_UUID_PATTERN})`,
LINKS: '/links',
PUBLIC_FAVORITES: '/public-favorites',
- COLLECTIONS_CONTENT_ADDRESS: '/collections/:id',
+ COLLECTIONS_CONTENT_ADDRESS: `/collections/:id(${PORTABLE_DATA_HASH_PATTERN})`,
ALL_PROCESSES: '/all_processes',
NO_MATCH: '*',
};
diff --git a/src/services/ancestors-service/ancestors-service.ts b/src/services/ancestors-service/ancestors-service.ts
index 23e7729f..8f5b9032 100644
--- a/src/services/ancestors-service/ancestors-service.ts
+++ b/src/services/ancestors-service/ancestors-service.ts
@@ -27,7 +27,7 @@ export class AncestorService {
const service = this.getService(extractUuidObjectType(startUuid));
if (service) {
try {
- const resource = await service.get(startUuid);
+ const resource = await service.get(startUuid, false);
if (startUuid === endUuid) {
return [resource];
} else {
@@ -39,9 +39,8 @@ export class AncestorService {
} catch (e) {
return [];
}
- } else {
- return [];
}
+ return [];
}
private getService = (objectType?: string) => {
diff --git a/src/services/api/api-actions.ts b/src/services/api/api-actions.ts
index f986786d..00b18229 100644
--- a/src/services/api/api-actions.ts
+++ b/src/services/api/api-actions.ts
@@ -3,7 +3,7 @@
// SPDX-License-Identifier: AGPL-3.0
export type ProgressFn = (id: string, working: boolean) => void;
-export type ErrorFn = (id: string, error: any) => void;
+export type ErrorFn = (id: string, error: any, showSnackBar?: boolean) => void;
export interface ApiActions {
progressFn: ProgressFn;
diff --git a/src/services/common-service/common-service.ts b/src/services/common-service/common-service.ts
index 44233eb1..e00a3d7d 100644
--- a/src/services/common-service/common-service.ts
+++ b/src/services/common-service/common-service.ts
@@ -66,7 +66,7 @@ export class CommonService<T> {
}
}
- static defaultResponse<R>(promise: AxiosPromise<R>, actions: ApiActions, mapKeys = true): Promise<R> {
+ static defaultResponse<R>(promise: AxiosPromise<R>, actions: ApiActions, mapKeys = true, showErrors = true): Promise<R> {
const reqId = uuid();
actions.progressFn(reqId, true);
return promise
@@ -80,7 +80,7 @@ export class CommonService<T> {
.catch(({ response }) => {
actions.progressFn(reqId, false);
const errors = CommonService.mapResponseKeys(response) as Errors;
- actions.errorFn(reqId, errors);
+ actions.errorFn(reqId, errors, showErrors);
throw errors;
});
}
@@ -101,11 +101,13 @@ export class CommonService<T> {
);
}
- get(uuid: string) {
+ get(uuid: string, showErrors?: boolean) {
return CommonService.defaultResponse(
this.serverApi
.get<T>(this.resourceType + '/' + uuid),
- this.actions
+ this.actions,
+ true, // mapKeys
+ showErrors
);
}
diff --git a/src/store/navigation/navigation-action.ts b/src/store/navigation/navigation-action.ts
index cb2eb186..d663ae37 100644
--- a/src/store/navigation/navigation-action.ts
+++ b/src/store/navigation/navigation-action.ts
@@ -14,7 +14,6 @@ import { GROUPS_PANEL_LABEL } from '~/store/breadcrumbs/breadcrumbs-actions';
export const navigateTo = (uuid: string) =>
async (dispatch: Dispatch, getState: () => RootState) => {
const kind = extractUuidKind(uuid);
-
switch (kind) {
case ResourceKind.PROJECT:
case ResourceKind.USER:
diff --git a/src/views/not-found-panel/not-found-panel-root.test.tsx b/src/views/not-found-panel/not-found-panel-root.test.tsx
new file mode 100644
index 00000000..1d84a662
--- /dev/null
+++ b/src/views/not-found-panel/not-found-panel-root.test.tsx
@@ -0,0 +1,69 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import * as React from 'react';
+import { mount, configure } from 'enzyme';
+import * as Adapter from "enzyme-adapter-react-16";
+import { StyledComponentProps, MuiThemeProvider } from '@material-ui/core';
+import { ClusterConfigJSON } from '~/common/config';
+import { CustomTheme } from '~/common/custom-theme';
+import { NotFoundPanelRoot, NotFoundPanelRootDataProps, CssRules } from './not-found-panel-root';
+
+configure({ adapter: new Adapter() });
+
+describe('NotFoundPanelRoot', () => {
+ let props: NotFoundPanelRootDataProps & StyledComponentProps<CssRules>;
+
+ beforeEach(() => {
+ props = {
+ classes: {
+ root: 'root',
+ title: 'title',
+ active: 'active',
+ },
+ clusterConfig: {
+ Mail: {
+ SupportEmailAddress: 'support at example.com'
+ }
+ } as ClusterConfigJSON,
+ location: null,
+ };
+ });
+
+ it('should render component', () => {
+ // given
+ const expectedMessage = 'The page you requested was not found, email us us if you suspect this is a bug.';
+
+ // when
+ const wrapper = mount(
+ <MuiThemeProvider theme={CustomTheme}>
+ <NotFoundPanelRoot {...props} />
+ </MuiThemeProvider>
+ );
+
+ // then
+ expect(wrapper.find('p').text()).toEqual(expectedMessage);
+ });
+
+ it('should render component with additional message', () => {
+ // given
+ const hash = '123hash123';
+ const pathname = `/collections/${hash}`;
+
+ // setup
+ props.location = {
+ pathname,
+ } as any;
+
+ // when
+ const wrapper = mount(
+ <MuiThemeProvider theme={CustomTheme}>
+ <NotFoundPanelRoot {...props} />
+ </MuiThemeProvider>
+ );
+
+ // then
+ expect(wrapper.find('p').first().text()).toContain(hash);
+ });
+});
\ No newline at end of file
diff --git a/src/views/not-found-panel/not-found-panel-root.tsx b/src/views/not-found-panel/not-found-panel-root.tsx
index 7d8ed3fb..439807fd 100644
--- a/src/views/not-found-panel/not-found-panel-root.tsx
+++ b/src/views/not-found-panel/not-found-panel-root.tsx
@@ -3,11 +3,12 @@
// SPDX-License-Identifier: AGPL-3.0
import * as React from 'react';
+import { Location } from 'history';
import { StyleRulesCallback, WithStyles, withStyles, Paper, Grid } from '@material-ui/core';
-import { User } from "~/models/user";
import { ArvadosTheme } from '~/common/custom-theme';
+import { ClusterConfigJSON } from '~/common/config';
-type CssRules = 'root' | 'title';
+export type CssRules = 'root' | 'title' | 'active';
const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
root: {
@@ -18,23 +19,52 @@ const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
title: {
paddingLeft: theme.spacing.unit * 3,
paddingTop: theme.spacing.unit * 3,
+ paddingBottom: theme.spacing.unit * 3,
fontSize: '18px'
+ },
+ active: {
+ color: theme.customs.colors.green700,
+ textDecoration: 'none',
}
});
export interface NotFoundPanelRootDataProps {
- user?: User;
+ location: Location<any> | null;
+ clusterConfig: ClusterConfigJSON;
}
type NotFoundPanelRootProps = NotFoundPanelRootDataProps & WithStyles<CssRules>;
+const getAdditionalMessage = (location: Location | null) => {
+ if (!location) {
+ return null;
+ }
+
+ const { pathname } = location;
+
+ if (pathname.indexOf('collections') > -1) {
+ const uuidHash = pathname.replace('/collections/', '');
+
+ return (
+ <p>
+ Please make sure that provided UUID/ObjectHash '{uuidHash}' is valid.
+ </p>
+ );
+ }
+
+ return null;
+};
+
export const NotFoundPanelRoot = withStyles(styles)(
- ({ classes }: NotFoundPanelRootProps) =>
+ ({ classes, clusterConfig, location }: NotFoundPanelRootProps) =>
<Paper>
<Grid container justify="space-between" wrap="nowrap" alignItems="center">
<div className={classes.title}>
<h2>Not Found</h2>
- <p>The page you requested was not found.</p>
+ { getAdditionalMessage(location) }
+ <p>
+ The page you requested was not found, <a className={classes.active} href={`mailto:${clusterConfig.Mail!.SupportEmailAddress}`}>email us</a> us if you suspect this is a bug.
+ </p>
</div>
</Grid>
</Paper>
diff --git a/src/views/not-found-panel/not-found-panel.tsx b/src/views/not-found-panel/not-found-panel.tsx
index 9631c815..adfaf720 100644
--- a/src/views/not-found-panel/not-found-panel.tsx
+++ b/src/views/not-found-panel/not-found-panel.tsx
@@ -8,7 +8,8 @@ import { NotFoundPanelRoot, NotFoundPanelRootDataProps } from '~/views/not-found
const mapStateToProps = (state: RootState): NotFoundPanelRootDataProps => {
return {
- user: state.auth.user,
+ location: state.router.location,
+ clusterConfig: state.auth.config.clusterConfig,
};
};
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list