Skip to content

Commit b6e365e

Browse files
committed
Add Schema and Fields Description
Sort Schema and Content by Name
1 parent c60f590 commit b6e365e

File tree

11 files changed

+106
-50
lines changed

11 files changed

+106
-50
lines changed

src/app/features/spaces/contents/contents.component.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { filter, switchMap, tap } from 'rxjs/operators';
66
import { MatSort } from '@angular/material/sort';
77
import { MatPaginator } from '@angular/material/paginator';
88
import { NotificationService } from '@shared/services/notification.service';
9-
import { Schema, SchemaType } from '@shared/models/schema.model';
9+
import { Schema, SchemaType, sortSchema } from '@shared/models/schema.model';
1010
import { SchemaService } from '@shared/services/schema.service';
1111
import { combineLatest } from 'rxjs';
1212
import {
@@ -16,6 +16,7 @@ import {
1616
ContentFolderCreate,
1717
ContentKind,
1818
ContentUpdate,
19+
sortContent,
1920
} from '@shared/models/content.model';
2021
import { ContentService } from '@shared/services/content.service';
2122
import { ObjectUtils } from '@core/utils/object-utils.service';
@@ -90,10 +91,10 @@ export class ContentsComponent {
9091
)
9192
.subscribe({
9293
next: ([schemas, contents]) => {
93-
this.schemas = schemas;
94-
this.schemasMapById = new Map(schemas.map(it => [it.id, it]));
95-
this.contents = contents;
96-
this.dataSource = new MatTableDataSource<Content>(contents);
94+
this.schemas = schemas.sort(sortSchema);
95+
this.schemasMapById = new Map(this.schemas.map(it => [it.id, it]));
96+
this.contents = contents.sort(sortContent);
97+
this.dataSource = new MatTableDataSource<Content>(this.contents);
9798
this.dataSource.sort = this.sort();
9899
this.dataSource.paginator = this.paginator();
99100
this.isLoading.set(false);

src/app/features/spaces/contents/edit-document-schema/edit-document-schema.component.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
SchemaFieldOption,
2323
SchemaFieldOptions,
2424
SchemaType,
25+
sortSchemaEnumValue,
2526
} from '@shared/models/schema.model';
2627
import { FormErrorHandlerService } from '@core/error-handler/form-error-handler.service';
2728
import { AssetContent, ContentData, ContentDocument, ReferenceContent } from '@shared/models/content.model';
@@ -91,6 +92,10 @@ export class EditDocumentSchemaComponent implements OnInit, OnChanges {
9192
this.schemas()
9293
.filter(it => it.type === SchemaType.ENUM)
9394
.map(it => it as SchemaEnum)
95+
.map(it => {
96+
it.values?.sort(sortSchemaEnumValue);
97+
return it;
98+
})
9499
.map(it => [it.id, it]),
95100
),
96101
);

src/app/features/spaces/schemas/add-dialog/add-dialog.component.html

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,17 @@ <h2 mat-dialog-title>Create new Schema</h2>
2525
<mat-form-field>
2626
<mat-label>Type</mat-label>
2727
<mat-select formControlName="type" required>
28+
<mat-select-trigger>
29+
@let selectedType = schemaTypeDescriptions[type];
30+
<mat-icon>{{ selectedType.icon }}</mat-icon>
31+
{{ selectedType.name }}
32+
</mat-select-trigger>
2833
@for (type of types; track type) {
29-
<mat-option [value]="type"> {{ type }}</mat-option>
34+
@let descriptor = schemaTypeDescriptions[type];
35+
<mat-option [value]="type" [matTooltip]="descriptor.description">
36+
<mat-icon>{{ descriptor.icon }}</mat-icon>
37+
{{ descriptor.name }}
38+
</mat-option>
3039
}
3140
</mat-select>
3241
@if (form.controls['type'].errors; as errors) {

src/app/features/spaces/schemas/add-dialog/add-dialog.component.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { AddDialogModel } from './add-dialog.model';
55
import { SchemaValidator } from '@shared/validators/schema.validator';
66
import { FormErrorHandlerService } from '@core/error-handler/form-error-handler.service';
77
import { CommonValidator } from '@shared/validators/common.validator';
8-
import { SchemaType } from '@shared/models/schema.model';
8+
import { SchemaType, schemaTypeDescriptions } from '@shared/models/schema.model';
99
import { NameUtils } from '@core/utils/name-utils.service';
1010
import { toSignal } from '@angular/core/rxjs-interop';
1111

@@ -16,12 +16,13 @@ import { toSignal } from '@angular/core/rxjs-interop';
1616
changeDetection: ChangeDetectionStrategy.OnPush,
1717
})
1818
export class AddDialogComponent {
19+
schemaTypeDescriptions = schemaTypeDescriptions;
1920
types: string[] = Object.keys(SchemaType);
2021

2122
form: FormGroup = this.fb.group({
2223
displayName: this.fb.control<string | undefined>(undefined, SchemaValidator.DISPLAY_NAME),
23-
id: this.fb.control('', [...SchemaValidator.ID, CommonValidator.reservedName(this.data.reservedIds)]),
24-
type: this.fb.control(SchemaType.NODE, SchemaValidator.TYPE),
24+
id: this.fb.control<string | undefined>('', [...SchemaValidator.ID, CommonValidator.reservedName(this.data.reservedIds)]),
25+
type: this.fb.control<SchemaType>(SchemaType.NODE, SchemaValidator.TYPE),
2526
});
2627

2728
formDisplayNameValue = toSignal(this.form.controls['displayName'].valueChanges);
@@ -38,6 +39,10 @@ export class AddDialogComponent {
3839
});
3940
}
4041

42+
get type(): SchemaType {
43+
return this.form.controls['type'].value;
44+
}
45+
4146
normalizeId() {
4247
if (this.form.value.slug) {
4348
this.form.controls['id'].setValue(NameUtils.schemaId(this.form.value.id));

src/app/features/spaces/schemas/edit-comp/edit-comp.component.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
(click)="selectComponent(index)"
4545
[activated]="index === selectedFieldIdx"
4646
[class.invalid]="field.invalid">
47-
<mat-icon matListItemIcon class="type">{{ schemaFieldKindDescriptions[field.value.kind].icon }}</mat-icon>
47+
@let descriptor = schemaFieldKindDescriptions[field.value.kind];
48+
<mat-icon matListItemIcon class="type" [matTooltip]="descriptor.description">{{ descriptor.icon }}</mat-icon>
4849
<span matListItemTitle>
4950
{{ field.value.displayName }} <span class="field-id">#{{ field.value.name }}</span>
5051
</span>

src/app/features/spaces/schemas/schemas.component.html

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,16 @@
4343
</mat-form-field>
4444
</div>
4545
<mat-table [dataSource]="dataSource" matSort>
46-
<ng-container matColumnDef="id">
47-
<mat-header-cell *matHeaderCellDef mat-sort-header="id"> Id</mat-header-cell>
48-
<mat-cell *matCellDef="let element"> {{ element.id }}</mat-cell>
46+
<ng-container matColumnDef="type">
47+
<mat-header-cell *matHeaderCellDef mat-sort-header="type"> Type</mat-header-cell>
48+
<mat-cell *matCellDef="let element">
49+
@let descriptor = schemaTypeDescriptions[element.type];
50+
<mat-icon [matTooltip]="descriptor.description">{{ descriptor.icon }}</mat-icon>
51+
&nbsp; {{ descriptor.name }}
52+
</mat-cell>
4953
</ng-container>
5054
<ng-container matColumnDef="name">
51-
<mat-header-cell *matHeaderCellDef mat-sort-header="name"> Name</mat-header-cell>
55+
<mat-header-cell *matHeaderCellDef mat-sort-header="displayName"> Name</mat-header-cell>
5256
<mat-cell *matCellDef="let element">
5357
{{ element.displayName }} &nbsp;<span class="schema-id">#{{ element.id }}</span>
5458
</mat-cell>
@@ -69,12 +73,6 @@
6973
</mat-chip-set>
7074
</mat-cell>
7175
</ng-container>
72-
<ng-container matColumnDef="type">
73-
<mat-header-cell *matHeaderCellDef mat-sort-header="type"> Type</mat-header-cell>
74-
<mat-cell *matCellDef="let element">
75-
<mat-icon>{{ schemaTypeIcons[element.type] }}</mat-icon> &nbsp; {{ element.type }}
76-
</mat-cell>
77-
</ng-container>
7876
<ng-container matColumnDef="createdAt">
7977
<mat-header-cell *matHeaderCellDef mat-sort-header="createdAt"> Created At</mat-header-cell>
8078
<mat-cell *matCellDef="let element" [matTooltip]="element.createdAt?.toDate() | date: 'medium'">

src/app/features/spaces/schemas/schemas.component.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { NotificationService } from '@shared/services/notification.service';
2121
import { SchemaService } from '@shared/services/schema.service';
2222
import { ConfirmationDialogComponent } from '@shared/components/confirmation-dialog/confirmation-dialog.component';
2323
import { ConfirmationDialogModel } from '@shared/components/confirmation-dialog/confirmation-dialog.model';
24-
import { Schema, SchemaCreate, SchemaFieldKind, SchemaType } from '@shared/models/schema.model';
24+
import { Schema, SchemaCreate, SchemaFieldKind, SchemaType, schemaTypeDescriptions, sortSchema } from '@shared/models/schema.model';
2525
import { AddDialogComponent } from './add-dialog/add-dialog.component';
2626
import { AddDialogModel } from './add-dialog/add-dialog.model';
2727
import { ExportDialogComponent } from './export-dialog/export-dialog.component';
@@ -46,11 +46,7 @@ export class SchemasComponent implements OnInit {
4646
// Inputs
4747
spaceId = input.required<string>();
4848

49-
schemaTypeIcons: Record<SchemaType, string> = {
50-
ROOT: 'margin',
51-
NODE: 'polyline',
52-
ENUM: 'list',
53-
};
49+
schemaTypeDescriptions = schemaTypeDescriptions;
5450

5551
dataSource: MatTableDataSource<Schema> = new MatTableDataSource<Schema>([]);
5652
displayedColumns: string[] = ['type', 'name', 'description', 'labels', /*'createdAt',*/ 'updatedAt', 'actions'];
@@ -103,8 +99,8 @@ export class SchemasComponent implements OnInit {
10399
.pipe(takeUntilDestroyed(this.destroyRef))
104100
.subscribe({
105101
next: schemas => {
106-
this.schemas.set(schemas);
107-
this.dataSource.data = schemas;
102+
this.schemas.set(schemas.sort(sortSchema));
103+
this.dataSource.data = this.schemas();
108104
this.dataSource.filterPredicate = this.schemaFilterPredicate;
109105
this.dataSource.sort = this.sort();
110106
this.dataSource.paginator = this.paginator();

src/app/features/spaces/schemas/shared/edit-field/edit-field.component.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
{{ selectedFieldKind.name }}
2121
</mat-select-trigger>
2222
@for (kind of fieldKinds; track kind) {
23-
<mat-option [value]="kind">
24-
<mat-icon>{{ schemaFieldKindDescriptions[kind].icon }}</mat-icon>
25-
{{ schemaFieldKindDescriptions[kind].name }}
23+
@let descriptor = schemaFieldKindDescriptions[kind];
24+
<mat-option [value]="kind" [matTooltip]="descriptor.description">
25+
<mat-icon>{{ descriptor.icon }}</mat-icon>
26+
{{ descriptor.name }}
2627
</mat-option>
2728
}
2829
</mat-select>

src/app/features/spaces/schemas/shared/edit-field/edit-field.component.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
schemaFieldKindDescriptions,
99
SchemaFieldOptionSelectable,
1010
SchemaType,
11+
sortSchema,
1112
} from '@shared/models/schema.model';
1213
import { MatSelectChange } from '@angular/material/select';
1314
import { FormErrorHandlerService } from '@core/error-handler/form-error-handler.service';
@@ -32,8 +33,16 @@ export class EditFieldComponent implements OnInit {
3233
selectedFieldKind = this.schemaFieldKindDescriptions[SchemaFieldKind.TEXT];
3334
nameReadonly = true;
3435
// Schemas
35-
nodeSchemas = computed(() => this.schemas().filter(it => it.type === SchemaType.NODE));
36-
enumSchemas = computed(() => this.schemas().filter(it => it.type === SchemaType.ENUM));
36+
nodeSchemas = computed(() =>
37+
this.schemas()
38+
.filter(it => it.type === SchemaType.NODE)
39+
.sort(sortSchema),
40+
);
41+
enumSchemas = computed(() =>
42+
this.schemas()
43+
.filter(it => it.type === SchemaType.ENUM)
44+
.sort(sortSchema),
45+
);
3746

3847
settingsStore = inject(LocalSettingsStore);
3948

src/app/shared/models/content.model.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { FieldValue, Timestamp } from '@angular/fire/firestore';
22
import { ValidationErrors } from '@angular/forms';
33

4+
export function sortContent(a: Content, b: Content): number {
5+
const aIsFolder = a.kind === ContentKind.FOLDER ? 0 : 1;
6+
const bIsFolder = b.kind === ContentKind.FOLDER ? 0 : 1;
7+
return `${aIsFolder}${a.name}`.localeCompare(`${bIsFolder}${b.name}`);
8+
}
9+
410
export interface ContentError {
511
contentId: string;
612
locale: string;

src/app/shared/models/schema.model.ts

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
11
import { Timestamp } from '@angular/fire/firestore';
22

3+
export function sortSchema(a: Schema, b: Schema): number {
4+
if (a.displayName && b.displayName) {
5+
return a.displayName.localeCompare(b.displayName);
6+
} else {
7+
return a.id.localeCompare(b.id);
8+
}
9+
}
10+
11+
export function sortSchemaEnumValue(a: SchemaEnumValue, b: SchemaEnumValue): number {
12+
return a.name.localeCompare(b.name);
13+
}
14+
315
export enum SchemaType {
416
ROOT = 'ROOT',
517
NODE = 'NODE',
618
ENUM = 'ENUM',
719
}
820

21+
export interface FieldTypeDescription {
22+
name: string;
23+
description: string;
24+
icon: string;
25+
}
26+
27+
export const schemaTypeDescriptions: Record<SchemaType, FieldTypeDescription> = {
28+
ROOT: { name: 'Root', icon: 'margin', description: 'Root schema, top level schema' },
29+
NODE: { name: 'Node', icon: 'polyline', description: 'Node schema, nested schema' },
30+
ENUM: { name: 'Enum', icon: 'list', description: 'Enum schema, list of values' },
31+
};
32+
933
export type Schema = SchemaComponent | SchemaEnum;
1034

1135
export interface SchemaBase {
@@ -76,27 +100,28 @@ export enum SchemaFieldKind {
76100

77101
export interface FieldKindDescription {
78102
name: string;
103+
description: string;
79104
icon: string;
80105
}
81106

82107
export const schemaFieldKindDescriptions: Record<SchemaFieldKind, FieldKindDescription> = {
83-
TEXT: { name: 'Text', icon: 'title' },
84-
TEXTAREA: { name: 'TextArea', icon: 'rtt' },
85-
MARKDOWN: { name: 'Markdown', icon: 'functions' },
86-
NUMBER: { name: 'Number', icon: 'pin' },
87-
COLOR: { name: 'Color', icon: 'colorize' },
88-
DATE: { name: 'Date', icon: 'event' },
89-
DATETIME: { name: 'Date and Time', icon: 'schedule' },
90-
BOOLEAN: { name: 'Boolean', icon: 'toggle_on' },
91-
OPTION: { name: 'Single Option', icon: 'list' },
92-
OPTIONS: { name: 'Multiple Options', icon: 'list' },
93-
LINK: { name: 'Link', icon: 'link' },
94-
REFERENCE: { name: 'Reference (One)', icon: 'link' },
95-
REFERENCES: { name: 'References (Many)', icon: 'link' },
96-
ASSET: { name: 'Asset ( One )', icon: 'attachment' },
97-
ASSETS: { name: 'Assets ( Many )', icon: 'attachment' },
98-
SCHEMA: { name: 'Schema ( One )', icon: 'polyline' },
99-
SCHEMAS: { name: 'Schemas ( Many )', icon: 'polyline' },
108+
TEXT: { name: 'Text', icon: 'title', description: 'Short text field, titles or headlines' },
109+
TEXTAREA: { name: 'TextArea', icon: 'rtt', description: 'Long text field, description' },
110+
MARKDOWN: { name: 'Markdown', icon: 'functions', description: 'Markdown text field, description' },
111+
NUMBER: { name: 'Number', icon: 'pin', description: 'Number field, amount or quantity' },
112+
COLOR: { name: 'Color', icon: 'colorize', description: 'Color field, background or text color' },
113+
DATE: { name: 'Date', icon: 'event', description: 'Date field, calendar date picker' },
114+
DATETIME: { name: 'Date and Time', icon: 'schedule', description: 'Date and time field, calendar date and time picker' },
115+
BOOLEAN: { name: 'Boolean', icon: 'toggle_on', description: 'Boolean field, true or false' },
116+
OPTION: { name: 'Option (One)', icon: 'list', description: 'Single selection field, dropdown' },
117+
OPTIONS: { name: 'Options (Multiple)', icon: 'list', description: 'Multiple selection field, dropdown' },
118+
LINK: { name: 'Link', icon: 'link', description: 'Link field, external URL or internal resource' },
119+
REFERENCE: { name: 'Reference (One)', icon: 'link', description: 'Reference field, to a internal resource' },
120+
REFERENCES: { name: 'References (Multiple)', icon: 'link', description: 'References field, to multiple internal resources' },
121+
ASSET: { name: 'Asset (One)', icon: 'attachment', description: 'Asset field, image, video or file' },
122+
ASSETS: { name: 'Assets (Multiple)', icon: 'attachment', description: 'Assets field, multiple images, videos or files' },
123+
SCHEMA: { name: 'Schema (One)', icon: 'polyline', description: 'Schema field, to a internal schema' },
124+
SCHEMAS: { name: 'Schemas (Multiple)', icon: 'polyline', description: 'Schemas field, to multiple internal schemas' },
100125
};
101126

102127
export interface SchemaFieldBase {

0 commit comments

Comments
 (0)