diff --git a/scripts/generate-nestjs-sdk.bash b/scripts/generate-nestjs-sdk.bash index 3c6b81f2e..c2a264ce5 100755 --- a/scripts/generate-nestjs-sdk.bash +++ b/scripts/generate-nestjs-sdk.bash @@ -1,6 +1,28 @@ #!/bin/bash # -# + +# Note: This script is meant to be run from the project root, e.g. +# ./scripts/generate-nestjs-sdk.bash +if [ ! -d "node_modules" ]; then + echo "Error: No node_modules folder found. This script is means to be run from the project root." + exit 1 +fi + +# This default is for when developing with a backend running directly on localhost +SWAGGER_API_URL="http://localhost:3000/explorer-json" +while [[ "$#" -gt 0 ]]; do + case "$1" in + --swagger-url) + shift + SWAGGER_API_URL=$1 + shift + ;; + *) + echo "Unknown argument: $1" + exit 1 + ;; + esac +done USER=`who am i | cut -d\ -f1` echo -e "\nUser running the script: ${USER}" @@ -8,6 +30,10 @@ echo -e "\nUser running the script: ${USER}" echo -e "\nCleanup old files..." rm -rf node_modules/@scicatproject/scicat-sdk-ts-angular rm -rf @scicatproject/scicat-sdk-ts-angular +rm local-api-for-generator.json + +echo -e "\nFetching the Swagger API from the back end..." +curl ${SWAGGER_API_URL} > local-api-for-generator.json echo -e "\nGenerating the new sdk..." @@ -17,14 +43,25 @@ echo -e "\nGenerating the new sdk..." ## docker run \ --rm \ - --add-host host.docker.internal:host-gateway \ -v "`pwd`:/local" \ - openapitools/openapi-generator-cli:v7.13.0 generate \ - -i http://host.docker.internal:3000/explorer-json \ + openapitools/openapi-generator-cli:v7.14.0 generate \ + -i /local/local-api-for-generator.json \ -g typescript-angular \ -o local/@scicatproject/scicat-sdk-ts-angular \ --additional-properties=ngVersion=19.0.0,npmName=@scicatproject/scicat-sdk-ts-angular,supportsES6=true,withInterfaces=true --skip-validate-spec +rm local-api-for-generator.json + +# Check if the docker command resulted in any output. +# If we don't do this, we'll try to cd into a missing folder, +# and then we'd be invoking 'npm run build' as root in the main project folder, +# which would create a bunch of stuff in ./dist belonging to root, +# causing problems for things like SciCat Live. +if [ ! -d "@scicatproject/scicat-sdk-ts-angular" ]; then + echo "Error: OpenApi output not found." + exit 1 +fi + REMOVE_NPM_LINK=0 if ! command -v npm 2>&1 1>/dev/null then @@ -46,17 +83,23 @@ echo -e "\nInstalling dependencies and building the sdk..." cd @scicatproject/scicat-sdk-ts-angular npm install npm run build - -echo -e "\nCopying the build files in node_modules..." cd ../.. -cp -rv @scicatproject/scicat-sdk-ts-angular/dist node_modules/@scicatproject/scicat-sdk-ts-angular + +if [ ! -d "@scicatproject/scicat-sdk-ts-angular/dist" ]; then + echo "Error: Build ouput not found." + exit 1 +fi + +echo -e "\nCopying the build files into node_modules..." +mkdir -p node_modules/@scicatproject/scicat-sdk-ts-angular +cp -rv @scicatproject/scicat-sdk-ts-angular/dist/ node_modules/@scicatproject/scicat-sdk-ts-angular/ echo -e "\nAdjusting ownership to user ${USER}" chown -Rv ${USER} node_modules/@scicatproject/scicat-sdk-ts-angular echo -e "\nFinal cleanup..." echo -e "Removing sdk folder" -rm -rfv @scicatproject +rm -rf @scicatproject if [ $REMOVE_NPM_LINK -eq 1 ]; then @@ -65,3 +108,4 @@ then rm -fv "/usr/local/bin/node" fi +echo -e "\nDone." \ No newline at end of file diff --git a/src/app/datasets/datafiles-actions/datafiles-action.component.ts b/src/app/datasets/datafiles-actions/datafiles-action.component.ts index e710dc544..c9f5c9a21 100644 --- a/src/app/datasets/datafiles-actions/datafiles-action.component.ts +++ b/src/app/datasets/datafiles-actions/datafiles-action.component.ts @@ -101,6 +101,8 @@ export class DatafilesActionComponent implements OnInit, OnChanges { this.prepare_disabled_condition(); const expr = this.disabled_condition; + // Note: 'with' has been deprecated and is considered harmful. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with const fn = new Function("ctx", `with (ctx) { return (${expr}); }`); return fn({ diff --git a/src/app/datasets/dataset-detail/dataset-detail-dynamic/dataset-detail-dynamic.component.ts b/src/app/datasets/dataset-detail/dataset-detail-dynamic/dataset-detail-dynamic.component.ts index 394ec88a5..bf803d56f 100644 --- a/src/app/datasets/dataset-detail/dataset-detail-dynamic/dataset-detail-dynamic.component.ts +++ b/src/app/datasets/dataset-detail/dataset-detail-dynamic/dataset-detail-dynamic.component.ts @@ -7,6 +7,7 @@ import { Subscription } from "rxjs"; import { showMessageAction } from "state-management/actions/user.actions"; import { selectCurrentAttachments, + selectCurrentDatasetExternalLinks, selectCurrentDataset, selectCurrentDatasetWithoutFileInfo, } from "state-management/selectors/datasets.selectors"; @@ -57,6 +58,7 @@ export class DatasetDetailDynamicComponent implements OnInit, OnDestroy { dataset$ = this.store.select(selectCurrentDataset); datasetWithout$ = this.store.select(selectCurrentDatasetWithoutFileInfo); attachments$ = this.store.select(selectCurrentAttachments); + externalLinks$ = this.store.select(selectCurrentDatasetExternalLinks); loading$ = this.store.select(selectIsLoading); show = false; diff --git a/src/app/datasets/dataset-detail/dataset-detail/_dataset-detail-theme.scss b/src/app/datasets/dataset-detail/dataset-detail/_dataset-detail-theme.scss index c38b8e686..2f9a59563 100644 --- a/src/app/datasets/dataset-detail/dataset-detail/_dataset-detail-theme.scss +++ b/src/app/datasets/dataset-detail/dataset-detail/_dataset-detail-theme.scss @@ -10,29 +10,33 @@ $header-3: map.get($color-config, "header-3"); $header-4: map.get($color-config, "header-4"); mat-card { - .general-header { + .dataset-general-header { background-color: mat.m2-get-color-from-palette($primary, "lighter"); } - .creator-header { + .dataset-creator-header { background-color: mat.m2-get-color-from-palette($header-1, "lighter"); } - .file-header { - background-color: mat.m2-get-color-from-palette($accent, "lighter"); + .dataset-file-header { + background-color: mat.m2-get-color-from-palette($header-2, "lighter"); } - .related-header { - background-color: mat.m2-get-color-from-palette($header-2, "lighter"); + .dataset-related-header { + background-color: mat.m2-get-color-from-palette($accent, "lighter"); } - .derived-header { + .dataset-derived-header { background-color: mat.m2-get-color-from-palette($header-3, "lighter"); } - .scientific-header { + .dataset-links-header { background-color: mat.m2-get-color-from-palette($header-4, "lighter"); } + + .dataset-scientific-header { + background-color: mat.m2-get-color-from-palette($header-1, "lighter"); + } } } diff --git a/src/app/datasets/dataset-detail/dataset-detail/dataset-detail.component.html b/src/app/datasets/dataset-detail/dataset-detail/dataset-detail.component.html index 7fe0851b5..1e7a2369d 100644 --- a/src/app/datasets/dataset-detail/dataset-detail/dataset-detail.component.html +++ b/src/app/datasets/dataset-detail/dataset-detail/dataset-detail.component.html @@ -26,7 +26,7 @@
- + description {{ "General Information" | translate }} @@ -167,7 +167,7 @@ - + person {{ "Creator Information" | translate }} @@ -207,7 +207,7 @@ - + folder {{ "File Information" | translate }} @@ -231,7 +231,7 @@ - + library_books {{ "Related Documents" | translate }} @@ -321,7 +321,7 @@ - +
analytics
@@ -346,11 +346,29 @@
+ + + link + {{ "Links" | translate }} + + + + + + + +
{{ externalLink.title }} + {{ externalLink.description }} +
+
+
+ - - science - {{ "Scientific Metadata" | translate }} + + science + {{ "Scientific Metadata" | translate }} { if (id) { this.resetTabs(); - // Fetch dataset details + // Fetch dataset details, as well as external links this.store.dispatch(fetchDatasetAction({ pid: id })); + this.store.dispatch(fetchExternalLinksAction({ pid: id })); this.fetchDataActions[TAB.details].loaded = true; } }), diff --git a/src/app/datasets/reduce/_reduce-theme.scss b/src/app/datasets/reduce/_reduce-theme.scss index 929810cb0..370abca18 100644 --- a/src/app/datasets/reduce/_reduce-theme.scss +++ b/src/app/datasets/reduce/_reduce-theme.scss @@ -6,11 +6,11 @@ $primary: map.get($color-config, "primary"); $accent: map.get($color-config, "accent"); mat-card { - .action-header { + .reduce-action-header { background-color: mat.m2-get-color-from-palette($primary, "lighter"); } - .derived-header { + .reduce-derived-header { background-color: mat.m2-get-color-from-palette($accent, "lighter"); } } diff --git a/src/app/datasets/reduce/reduce.component.html b/src/app/datasets/reduce/reduce.component.html index d70d7e645..717d801f9 100644 --- a/src/app/datasets/reduce/reduce.component.html +++ b/src/app/datasets/reduce/reduce.component.html @@ -2,7 +2,7 @@
- New Action + New Action @@ -176,7 +176,7 @@

Description

- + Derived Datasets diff --git a/src/app/publisheddata/publisheddata-details/_publisheddata-details-theme.scss b/src/app/publisheddata/publisheddata-details/_publisheddata-details-theme.scss index 45eb82c34..26e60621f 100644 --- a/src/app/publisheddata/publisheddata-details/_publisheddata-details-theme.scss +++ b/src/app/publisheddata/publisheddata-details/_publisheddata-details-theme.scss @@ -9,24 +9,24 @@ $accent: map.get($color-config, "accent"); $header-2: map.get($color-config, "header-2"); mat-card { - .status-header { + .publisheddata-status-header { background-color: mat.m2-get-color-from-palette($warn, "lighter"); } - .general-header { + .publisheddata-general-header { background-color: mat.m2-get-color-from-palette($primary, "lighter"); } - .creator-header { + .publisheddata-creator-header { background-color: mat.m2-get-color-from-palette($header-1, "lighter"); } - .file-header { - background-color: mat.m2-get-color-from-palette($accent, "lighter"); + .publisheddata-file-header { + background-color: mat.m2-get-color-from-palette($header-2, "lighter"); } - .related-header { - background-color: mat.m2-get-color-from-palette($header-2, "lighter"); + .publisheddata-related-header { + background-color: mat.m2-get-color-from-palette($accent, "lighter"); } } } diff --git a/src/app/publisheddata/publisheddata-details/publisheddata-details.component.html b/src/app/publisheddata/publisheddata-details/publisheddata-details.component.html index f47ce74ab..bd2f295f2 100644 --- a/src/app/publisheddata/publisheddata-details/publisheddata-details.component.html +++ b/src/app/publisheddata/publisheddata-details/publisheddata-details.component.html @@ -1,7 +1,7 @@
- +
info
@@ -57,7 +57,7 @@
- +
description
@@ -90,7 +90,7 @@
- +
person
@@ -139,7 +139,7 @@ publishedData.metadata?.dataDescription " > - +
folder
@@ -180,7 +180,7 @@
- +
library_books
diff --git a/src/app/shared/modules/table/table.component.html b/src/app/shared/modules/table/table.component.html index 2f5ce9868..fa54c3db0 100644 --- a/src/app/shared/modules/table/table.component.html +++ b/src/app/shared/modules/table/table.component.html @@ -53,16 +53,19 @@
+
{{ data[column.name] | date: column.dateFormat }}
+
{{ data[column.name] | dynamicPipe: column.pipe : [] }}
+
{{ data[column.name] }}
diff --git a/src/app/shared/modules/table/table.component.spec.ts b/src/app/shared/modules/table/table.component.spec.ts index 4c17ba388..6ce19d396 100644 --- a/src/app/shared/modules/table/table.component.spec.ts +++ b/src/app/shared/modules/table/table.component.spec.ts @@ -11,6 +11,8 @@ import { NO_ERRORS_SCHEMA } from "@angular/core"; import { MatCheckboxChange } from "@angular/material/checkbox"; import { TableModule } from "./table.module"; +// Jasmine testing framework descriptions for Angular component TableComponent + describe("TableComponent", () => { let component: TableComponent; let fixture: ComponentFixture; diff --git a/src/app/shared/modules/table/table.component.ts b/src/app/shared/modules/table/table.component.ts index c15679832..09a9f940a 100644 --- a/src/app/shared/modules/table/table.component.ts +++ b/src/app/shared/modules/table/table.component.ts @@ -9,6 +9,8 @@ import { import { SelectionModel } from "@angular/cdk/collections"; import { MatCheckboxChange } from "@angular/material/checkbox"; +// Accessory types and definition for Angular component TableComponent + export interface TableColumn { name: string; icon: string; diff --git a/src/app/shared/modules/table/table.module.ts b/src/app/shared/modules/table/table.module.ts index b3500ec84..65f2ddaea 100644 --- a/src/app/shared/modules/table/table.module.ts +++ b/src/app/shared/modules/table/table.module.ts @@ -11,6 +11,8 @@ import { MatPaginatorModule } from "@angular/material/paginator"; import { MatSortModule } from "@angular/material/sort"; import { MatTableModule } from "@angular/material/table"; +// NgModule declaration for Angular component TableComponent + @NgModule({ declarations: [TableComponent], imports: [ diff --git a/src/app/state-management/actions/datasets.actions.ts b/src/app/state-management/actions/datasets.actions.ts index 16b30d6e5..87ccb0475 100644 --- a/src/app/state-management/actions/datasets.actions.ts +++ b/src/app/state-management/actions/datasets.actions.ts @@ -6,6 +6,7 @@ import { OutputDatasetObsoleteDto, DatasetsControllerCreateV3Request, OutputAttachmentV3Dto, + ExternalLinkClass, } from "@scicatproject/scicat-sdk-ts-angular"; import { FacetCounts } from "state-management/state/datasets.store"; import { @@ -117,6 +118,18 @@ export const changeRelatedDatasetsPageAction = createAction( props<{ page: number; limit: number }>(), ); +export const fetchExternalLinksAction = createAction( + "[Dataset] Fetch External Links", + props<{ pid: string }>(), +); +export const fetchExternalLinksCompleteAction = createAction( + "[Dataset] Fetch External Links Complete", + props<{ externallinks: ExternalLinkClass[] }>(), +); +export const fetchExternalLinksFailedAction = createAction( + "[Dataset] Fetch External Links Failed", +); + export const prefillBatchAction = createAction("[Dataset] Prefill Batch"); export const prefillBatchCompleteAction = createAction( "[Dataset] Prefill Batch Complete", diff --git a/src/app/state-management/effects/datasets.effects.ts b/src/app/state-management/effects/datasets.effects.ts index 45e2d8ede..3a86fb479 100644 --- a/src/app/state-management/effects/datasets.effects.ts +++ b/src/app/state-management/effects/datasets.effects.ts @@ -9,6 +9,7 @@ import { OrigDatablock, OutputDatasetObsoleteDto, UpdateAttachmentV3Dto, + ExternalLinkClass, } from "@scicatproject/scicat-sdk-ts-angular"; import { Store } from "@ngrx/store"; import { @@ -165,6 +166,22 @@ export class DatasetEffects { ); }); + fetchExternalLinksOfDataset$ = createEffect(() => { + return this.actions$.pipe( + ofType(fromActions.fetchExternalLinksAction), + switchMap(({ pid }) => { + return this.datasetsService + .datasetsControllerFindExternalLinksByIdV3(pid) + .pipe( + map((externallinks: ExternalLinkClass[]) => + fromActions.fetchExternalLinksCompleteAction({ externallinks }), + ), + catchError(() => of(fromActions.fetchExternalLinksFailedAction())), + ); + }), + ); + }); + fetchOrigDatablocksOfDataset$ = createEffect(() => { return this.actions$.pipe( ofType(fromActions.fetchOrigDatablocksAction), @@ -398,6 +415,7 @@ export class DatasetEffects { fromActions.fetchOrigDatablocksAction, fromActions.fetchDatablocksAction, fromActions.fetchAttachmentsAction, + fromActions.fetchExternalLinksAction, fromActions.addDatasetAction, fromActions.updatePropertyAction, fromActions.addAttachmentAction, @@ -426,8 +444,8 @@ export class DatasetEffects { fromActions.fetchOrigDatablocksFailedAction, fromActions.fetchDatablocksCompleteAction, fromActions.fetchDatablocksFailedAction, - fromActions.fetchOrigDatablocksCompleteAction, - fromActions.fetchOrigDatablocksFailedAction, + fromActions.fetchExternalLinksCompleteAction, + fromActions.fetchExternalLinksFailedAction, fromActions.fetchAttachmentsCompleteAction, fromActions.fetchAttachmentsFailedAction, fromActions.addDatasetCompleteAction, diff --git a/src/app/state-management/reducers/datasets.reducer.ts b/src/app/state-management/reducers/datasets.reducer.ts index f470e3fc9..399e9d8a1 100644 --- a/src/app/state-management/reducers/datasets.reducer.ts +++ b/src/app/state-management/reducers/datasets.reducer.ts @@ -61,6 +61,16 @@ const reducer = createReducer( }, ), + on( + fromActions.fetchExternalLinksCompleteAction, + (state, { externallinks }) => { + return { + ...state, + currentSetExternalLinks: externallinks + }; + }, + ), + on(fromActions.fetchAttachmentsCompleteAction, (state, { attachments }) => { return { ...state, diff --git a/src/app/state-management/selectors/datasets.selectors.spec.ts b/src/app/state-management/selectors/datasets.selectors.spec.ts index 95b8ea6df..b7a5da24e 100644 --- a/src/app/state-management/selectors/datasets.selectors.spec.ts +++ b/src/app/state-management/selectors/datasets.selectors.spec.ts @@ -7,6 +7,7 @@ const initialDatasetState: DatasetState = { datasets: [], selectedSets: [], currentSet: dataset, + currentSetExternalLinks: [], relatedDatasets: [], relatedDatasetsCount: 0, totalCount: 0, @@ -70,6 +71,16 @@ describe("test dataset selectors", () => { }); }); + describe("selectCurrentDatasetExternalLinks", () => { + it("should select external links array for current dataset", () => { + expect( + fromDatasetSelectors.selectCurrentDatasetExternalLinks.projector( + initialDatasetState, + ), + ).toEqual([]); + }); + }); + describe("selectMetadataKeys", () => { it("should select the array of metadata keys", () => { expect( diff --git a/src/app/state-management/selectors/datasets.selectors.ts b/src/app/state-management/selectors/datasets.selectors.ts index fbd9a4590..63255c6fb 100644 --- a/src/app/state-management/selectors/datasets.selectors.ts +++ b/src/app/state-management/selectors/datasets.selectors.ts @@ -23,6 +23,11 @@ export const selectCurrentDataset = createSelector( (state) => state.currentSet, ); +export const selectCurrentDatasetExternalLinks = createSelector( + selectDatasetState, + (state) => state.currentSetExternalLinks, +); + export const selectCurrentDatasetWithoutFileInfo = createSelector( selectCurrentDataset, (currentSet) => { diff --git a/src/app/state-management/state/datasets.store.ts b/src/app/state-management/state/datasets.store.ts index bdc970eae..4519bc9ef 100644 --- a/src/app/state-management/state/datasets.store.ts +++ b/src/app/state-management/state/datasets.store.ts @@ -1,6 +1,6 @@ import { DatasetClass } from "@scicatproject/scicat-sdk-ts-angular"; import { DatasetFilters, ArchViewMode } from "state-management/models"; -import { OutputDatasetObsoleteDto } from "@scicatproject/scicat-sdk-ts-angular"; +import { OutputDatasetObsoleteDto, ExternalLinkClass } from "@scicatproject/scicat-sdk-ts-angular"; export interface DateTriple { year: number; @@ -26,6 +26,7 @@ export interface DatasetState { datasets: OutputDatasetObsoleteDto[]; selectedSets: OutputDatasetObsoleteDto[]; currentSet: OutputDatasetObsoleteDto | undefined; + currentSetExternalLinks: ExternalLinkClass[]; relatedDatasets: OutputDatasetObsoleteDto[]; relatedDatasetsCount: number; totalCount: number; @@ -54,6 +55,7 @@ export const initialDatasetState: DatasetState = { datasets: [], selectedSets: [], currentSet: undefined, + currentSetExternalLinks: [], relatedDatasets: [], relatedDatasetsCount: 0, totalCount: 0, diff --git a/src/app/theme.ts b/src/app/theme.ts index 6dcf13d3c..907d23285 100644 --- a/src/app/theme.ts +++ b/src/app/theme.ts @@ -38,11 +38,11 @@ export const light: Theme = { "--theme-header-2-lighter-contrast": "#000000", "--theme-header-2-darker": "#32846a", "--theme-header-2-darker-contrast": "#ffffff", - "--theme-header-3-default": "#ff7d00", + "--theme-header-3-default": "#662200", "--theme-header-3-default-contrast": "#ffffff", - "--theme-header-3-lighter": "#ffcb99", + "--theme-header-3-lighter": "#c1a699", "--theme-header-3-lighter-contrast": "#000000", - "--theme-header-3-darker": "#ff9732", + "--theme-header-3-darker": "#854e32", "--theme-header-3-darker-contrast": "#ffffff", "--theme-header-4-default": "#821482", "--theme-header-4-default-contrast": "#ffffff", diff --git a/src/assets/theme.json b/src/assets/theme.json index cdc519c89..49a015fd4 100644 --- a/src/assets/theme.json +++ b/src/assets/theme.json @@ -37,11 +37,11 @@ "--theme-header-2-lighter-contrast": "#000000", "--theme-header-2-darker": "#32846a", "--theme-header-2-darker-contrast": "#ffffff", - "--theme-header-3-default": "#ff7d00", + "--theme-header-3-default": "#662200", "--theme-header-3-default-contrast": "#ffffff", - "--theme-header-3-lighter": "#ffcb99", + "--theme-header-3-lighter": "#c1a699", "--theme-header-3-lighter-contrast": "#000000", - "--theme-header-3-darker": "#ff9732", + "--theme-header-3-darker": "#854e32", "--theme-header-3-darker-contrast": "#ffffff", "--theme-header-4-default": "#821482", "--theme-header-4-default-contrast": "#ffffff", diff --git a/src/styles.scss b/src/styles.scss index d9840e0ac..37443a557 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -210,7 +210,7 @@ $newcolor: map.merge( warn-2: $warn-2, header-1: $header-1, header-2: $header-2, - header-3: $header-4, + header-3: $header-3, header-4: $header-4, hover: $hover, )