Skip to content

Commit

Permalink
Merge pull request #321 from swisstopo/feature/assets-253-verweise-in…
Browse files Browse the repository at this point in the history
…-gleicher-workgroup

Feature/assets 253 verweise in gleicher workgroup
  • Loading branch information
TIL-EBP authored Nov 7, 2024
2 parents 4590e79 + d3b50f8 commit 517eab7
Show file tree
Hide file tree
Showing 14 changed files with 121 additions and 21 deletions.
1 change: 1 addition & 0 deletions apps/client-asset-sg/src/app/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export const deAppTranslations = {
alternativeId: 'Alternativ-ID',
alternativeIdDescription: 'Beschreibung Alternativ-ID',
addNewAlternativeId: 'Neue Alternativ-ID hinzufügen',
referencesWarning: 'Um die Arbeitsgruppe zu ändern, müssen Sie erst alle Verweise entfernen.',
},
files: {
tabName: 'Dateien',
Expand Down
1 change: 1 addition & 0 deletions apps/client-asset-sg/src/app/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export const enAppTranslations: AppTranslations = {
alternativeId: 'Alternative ID',
alternativeIdDescription: 'Alternative ID Description',
addNewAlternativeId: 'Add new alternative ID',
referencesWarning: 'In order to change the workgroup, you must first remove all references.',
},
files: {
tabName: 'Files',
Expand Down
1 change: 1 addition & 0 deletions apps/client-asset-sg/src/app/i18n/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export const frAppTranslations: AppTranslations = {
alternativeId: 'ID alternative',
alternativeIdDescription: "Description d'ID alternative",
addNewAlternativeId: 'Ajouter une nouvelle ID alternative',
referencesWarning: 'Pour changer le groupe de travail, vous devez d’abord supprimer toutes les références.',
},
files: {
tabName: 'Fichiers',
Expand Down
1 change: 1 addition & 0 deletions apps/client-asset-sg/src/app/i18n/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export const itAppTranslations: AppTranslations = {
alternativeId: 'IT Alternativ-ID',
alternativeIdDescription: 'IT Beschreibung Alternativ-ID',
addNewAlternativeId: 'IT Neue Alternativ-ID hinzufügen',
referencesWarning: 'IT Um die Arbeitsgruppe zu ändern, müssen Sie erst alle Verweise entfernen.',
},
files: {
tabName: 'IT Dateien',
Expand Down
1 change: 1 addition & 0 deletions apps/client-asset-sg/src/app/i18n/rm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export const rmAppTranslations: AppTranslations = {
alternativeId: 'RM Alternativ-ID',
alternativeIdDescription: 'RM Beschreibung Alternativ-ID',
addNewAlternativeId: 'RM Neue Alternativ-ID hinzufügen',
referencesWarning: 'RM Um die Arbeitsgruppe zu ändern, müssen Sie erst alle Verweise entfernen.',
},
files: {
tabName: 'RM Dateien',
Expand Down
2 changes: 2 additions & 0 deletions apps/server-asset-sg/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { JwtMiddleware } from '@/core/middleware/jwt.middleware';
import { PrismaService } from '@/core/prisma.service';
import { AssetEditController } from '@/features/asset-edit/asset-edit.controller';
import { AssetEditRepo } from '@/features/asset-edit/asset-edit.repo';
import { AssetEditService } from '@/features/asset-edit/asset-edit.service';
import { AssetInfoRepo } from '@/features/assets/asset-info.repo';
import { AssetRepo } from '@/features/assets/asset.repo';
import { AssetsController } from '@/features/assets/assets.controller';
Expand Down Expand Up @@ -51,6 +52,7 @@ import { WorkgroupsController } from '@/features/workgroups/workgroups.controlle
provideElasticsearch,
AssetEditRepo,
AssetInfoRepo,
AssetEditService,
AssetRepo,
AssetSearchService,
AssetSyncService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ import { authorize } from '@/core/authorize';
import { CurrentUser } from '@/core/decorators/current-user.decorator';
import { ParseBody } from '@/core/decorators/parse.decorator';
import { AssetEditRepo } from '@/features/asset-edit/asset-edit.repo';
import { AssetEditService } from '@/features/asset-edit/asset-edit.service';
import { AssetSearchService } from '@/features/assets/search/asset-search.service';

@Controller('/asset-edit')
export class AssetEditController {
constructor(private readonly assetEditRepo: AssetEditRepo, private readonly assetSearchService: AssetSearchService) {}
constructor(
private readonly assetEditRepo: AssetEditRepo,
private readonly assetEditService: AssetEditService,
private readonly assetSearchService: AssetSearchService
) {}

@Get('/:id')
async show(@Param('id', ParseIntPipe) id: number, @CurrentUser() user: User): Promise<unknown> {
Expand All @@ -38,6 +43,8 @@ export class AssetEditController {
authorize(AssetEditPolicy, user).canCreate();
validatePatch(user, patch);

await this.assetEditService.validateReferencesOrThrow({ user, patch });

const asset = await this.assetEditRepo.create({ user, patch });
await this.assetSearchService.register(asset);
return AssetEditDetail.encode(asset);
Expand All @@ -56,6 +63,7 @@ export class AssetEditController {

authorize(AssetEditPolicy, user).canUpdate(record);
validatePatch(user, patch, record);
await this.assetEditService.validateReferencesOrThrow({ user, patch }, id);

const asset = await this.assetEditRepo.update(record.assetId, { user, patch });
if (asset === null) {
Expand Down
3 changes: 2 additions & 1 deletion apps/server-asset-sg/src/features/asset-edit/asset-edit.http
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ Content-Type: application/json
"titleOriginal": "My Cool Asset",
"titlePublic": "Our Cool Asset",
"typeNatRels": [],
"workgroupId": 1
"workgroupId": 1,
"assetFiles": []
}

### Update asset-edit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ export class AssetEditRepo implements Repo<AssetEditDetail, number, AssetEditDat
if (count === 0) {
return null;
}

// Run the update in a transaction, as it consists of multiple prisma queries.
// Note that all mutations within this transaction are no-ops if there is no asset for `id`.
await this.prismaService.$transaction(async () => {
Expand All @@ -127,7 +126,7 @@ export class AssetEditRepo implements Repo<AssetEditDetail, number, AssetEditDat
assetKindItemCode: data.patch.assetKindItemCode,
assetFormatItemCode: data.patch.assetFormatItemCode,
isNatRel: data.patch.isNatRel,
assetMainId: O.toUndefined(data.patch.assetMainId),
assetMainId: O.toNullable(data.patch.assetMainId),
lastProcessedDate: new Date(),
processor: data.user.email,
manCatLabelRefs: {
Expand Down
55 changes: 55 additions & 0 deletions apps/server-asset-sg/src/features/asset-edit/asset-edit.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import * as O from 'fp-ts/Option';

import { AssetEditData } from './asset-edit.repo';
import { PrismaService } from '@/core/prisma.service';

@Injectable()
export class AssetEditService {
constructor(private readonly prismaService: PrismaService) {}

public async validateReferencesOrThrow(data: AssetEditData, id?: number): Promise<void> {
// check if any of the siblings are in another workgroup
for (const assetYId of data.patch.siblingAssetIds) {
const siblingCandidate = await this.prismaService.asset.findUnique({
where: { assetId: assetYId },
select: { workgroupId: true },
});
if (siblingCandidate?.workgroupId !== data.patch.workgroupId) {
throw new HttpException(
'Sibling assets must be in the same workgroup as the edited asset',
HttpStatus.UNPROCESSABLE_ENTITY
);
}
}

// check if the parent asset is in another workgroup
const assetMainId = O.toUndefined(data.patch.assetMainId);
if (assetMainId) {
const assetMain = await this.prismaService.asset.findUnique({
where: { assetId: assetMainId },
select: { workgroupId: true },
});
if (assetMain?.workgroupId !== data.patch.workgroupId) {
throw new HttpException('Cannot assign parent asset from different workgroup', HttpStatus.UNPROCESSABLE_ENTITY);
}
}

// check if any of the subordinate assets are in another workgroup for exisiting assets
if (id) {
const childAssets = await this.prismaService.asset.findMany({
where: { assetMainId: id },
select: { workgroupId: true },
});

for (const child of childAssets) {
if (child.workgroupId !== data.patch.workgroupId) {
throw new HttpException(
'Child assets must be in the same workgroup as the parent asset',
HttpStatus.UNPROCESSABLE_ENTITY
);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
<div class="flex flex-column form-column mr-8">
<div class="flex flex-column bg-white mb-4 py-4 px-6 overflow-y-scroll">
<div class="font-bold mb-4" translate>workgroup.title</div>
<div *ngIf="showWarningForReferences" class="flex mb-2 bg-orange-01 px-3 py-2">
<svg-icon key="warning-filled" class="mr-3"></svg-icon>
{{ "edit.tabs.general.referencesWarning" | translate }}
</div>
<mat-form-field class="mb-2">
<mat-label translate>workgroup.title</mat-label>
<mat-select formControlName="workgroupId">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export class AssetEditorTabGeneralComponent implements OnInit {
description: new FormControl<string>('', { nonNullable: true }),
});

public showWarningForReferences = false;

public readonly state: RxState<AssetEditorTabGeneralState> = inject(RxState<AssetEditorTabGeneralState>);

public readonly _referenceDataVM$ = this.state.select('referenceDataVM');
Expand Down Expand Up @@ -174,6 +176,10 @@ export class AssetEditorTabGeneralComponent implements OnInit {
this.idForm.patchValue({ idId, id, description });
}
});
this.setDisabledStatusOfWorkgroup();
this.rootFormGroup.controls.references.valueChanges.pipe(untilDestroyed(this)).subscribe(() => {
this.setDisabledStatusOfWorkgroup();
});
this.ngOnInit$.next();
}

Expand Down Expand Up @@ -222,5 +228,19 @@ export class AssetEditorTabGeneralComponent implements OnInit {
this.idForm.patchValue({ id, description });
}

private setDisabledStatusOfWorkgroup() {
if (
this.rootFormGroup.getRawValue().references.siblingAssets.length > 0 ||
this.rootFormGroup.getRawValue().references.childAssets.length > 0 ||
this.rootFormGroup.getRawValue().references.assetMain
) {
this.form.controls.workgroupId.disable({ emitEvent: false });
this.showWarningForReferences = true;
} else {
this.form.controls.workgroupId.enable({ emitEvent: false });
this.showWarningForReferences = false;
}
}

public eqAssetLanguageEdit = eqAssetLanguageEdit;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@
<mat-form-field>
<mat-label>Typ</mat-label>
<mat-select formControlName="assetReferenceType">
<mat-option *ngIf="!(_addParentDisabled$ | push)" value="parent">{{
"edit.tabs.references.referenceType.parent" | translate
}}</mat-option>
<mat-option *ngIf="!(_addParentDisabled$ | push)" value="parent"
>{{ "edit.tabs.references.referenceType.parent" | translate }}
</mat-option>
<mat-option value="sibling">{{ "edit.tabs.references.referenceType.sibling" | translate }}</mat-option>
</mat-select>
</mat-form-field>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild, inject } from '@angular/core';
import { ChangeDetectionStrategy, Component, ElementRef, inject, OnInit, ViewChild } from '@angular/core';
import { FormBuilder, FormControl, FormGroupDirective, Validators } from '@angular/forms';
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { httpErrorResponseError } from '@asset-sg/client-shared';
import { unknownToUnknownError } from '@asset-sg/core';
import { AssetByTitle, LinkedAsset } from '@asset-sg/shared';
import { AssetByTitle, AssetEditDetail, LinkedAsset } from '@asset-sg/shared';
import { UntilDestroy } from '@ngneat/until-destroy';
import * as A from 'fp-ts/Array';
import * as E from 'fp-ts/Either';
import { flow, pipe } from 'fp-ts/function';
import * as D from 'io-ts/Decoder';
import {
Observable,
Subject,
catchError,
combineLatest,
debounceTime,
distinctUntilChanged,
map,
Observable,
of,
startWith,
Subject,
switchMap,
} from 'rxjs';

Expand Down Expand Up @@ -79,19 +79,25 @@ export class AssetEditorTabReferencesComponent implements OnInit {
this._authorSearchInput$.pipe(
debounceTime(300),
switchMap(
(value): Observable<LinkedAsset[]> =>
(value): Observable<AssetEditDetail[]> =>
value.length >= 3
? this._httpClient.get(`/api/asset-edit/search?title=${value}`).pipe(
catchError((err: HttpErrorResponse | unknown) =>
of(err instanceof HttpErrorResponse ? httpErrorResponseError(err) : unknownToUnknownError(err))
),
map(
flow(
D.array(AssetByTitle).decode,
E.getOrElseW(() => [])
? this._httpClient
.post(`/api/assets/search?limit=10`, {
text: value,
workgroupIds: [this.rootFormGroup.getRawValue().general.workgroupId],
})
.pipe(
map((res) => (res as { data: AssetEditDetail[] }).data),
catchError((err: HttpErrorResponse | unknown) =>
of(err instanceof HttpErrorResponse ? httpErrorResponseError(err) : unknownToUnknownError(err))
),
map(
flow(
D.array(AssetEditDetail).decode,
E.getOrElseW(() => [])
)
)
)
)
: of([])
)
),
Expand Down

0 comments on commit 517eab7

Please sign in to comment.