Browse Source

Restrict creation of tags to unique names

pull/7635/head
Thomas Kaul 2 weeks ago
parent
commit
934c51b796
  1. 38
      apps/api/src/services/tag/tag.service.ts
  2. 22
      libs/ui/src/lib/tags-selector/tags-selector.component.ts

38
apps/api/src/services/tag/tag.service.ts

@ -15,17 +15,7 @@ export class TagService {
data
});
} catch (error) {
if (
error instanceof Prisma.PrismaClientKnownRequestError &&
error.code === 'P2002'
) {
throw new HttpException(
getReasonPhrase(StatusCodes.CONFLICT),
StatusCodes.CONFLICT
);
}
throw error;
throw this.getExceptionForError(error);
}
}
@ -135,10 +125,14 @@ export class TagService {
data: Prisma.TagUpdateInput;
where: Prisma.TagWhereUniqueInput;
}): Promise<Tag> {
return this.prismaService.tag.update({
data,
where
});
try {
return await this.prismaService.tag.update({
data,
where
});
} catch (error) {
throw this.getExceptionForError(error);
}
}
public async validateTagIds({
@ -194,4 +188,18 @@ export class TagService {
return this.validateTagIds({ tagIds, userId });
}
private getExceptionForError(error: unknown) {
if (
error instanceof Prisma.PrismaClientKnownRequestError &&
error.code === 'P2002'
) {
return new HttpException(
getReasonPhrase(StatusCodes.CONFLICT),
StatusCodes.CONFLICT
);
}
return error;
}
}

22
libs/ui/src/lib/tags-selector/tags-selector.component.ts

@ -81,8 +81,8 @@ export class GfTagsSelectorComponent
public constructor() {
this.tagInputControl.valueChanges
.pipe(takeUntilDestroyed())
.subscribe((value) => {
this.updateFilters(value ?? '');
.subscribe(() => {
this.updateFilters();
});
addIcons({ addCircleOutline, closeOutline });
@ -162,9 +162,8 @@ export class GfTagsSelectorComponent
this.updateFilters();
}
private filterTags(query: string = ''): SelectedTag[] {
const tags = this.tagsSelected() ?? [];
const tagIds = [...tags, ...(this.tagsReadOnly ?? [])].map(({ id }) => {
private filterTags(query: string): SelectedTag[] {
const tagIds = this.getTagsSelectedAndReadOnly().map(({ id }) => {
return id;
});
@ -180,7 +179,7 @@ export class GfTagsSelectorComponent
});
}
private getTagNameToCreate(query: string = ''): string | null {
private getTagNameToCreate(query: string): string | null {
const name = query.trim();
if (!name) {
@ -189,8 +188,7 @@ export class GfTagsSelectorComponent
const isExistingTagName = [
...(this.tagsAvailable ?? []),
...(this.tagsReadOnly ?? []),
...(this.tagsSelected() ?? [])
...this.getTagsSelectedAndReadOnly()
].some((tag) => {
return tag.name.toLowerCase() === name.toLowerCase();
});
@ -198,6 +196,10 @@ export class GfTagsSelectorComponent
return isExistingTagName ? null : name;
}
private getTagsSelectedAndReadOnly(): SelectedTag[] {
return [...this.tagsSelected(), ...(this.tagsReadOnly ?? [])];
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
private onChange = (_value: SelectedTag[]): void => {
// ControlValueAccessor onChange callback
@ -207,7 +209,9 @@ export class GfTagsSelectorComponent
// ControlValueAccessor onTouched callback
};
private updateFilters(query: string = '') {
private updateFilters() {
const query = this.tagInputControl.value ?? '';
this.filteredOptions.next(this.filterTags(query));
this.tagNameToCreate.set(this.getTagNameToCreate(query));
}

Loading…
Cancel
Save