Skip to content

Commit

Permalink
Add Schema and Fields Description
Browse files Browse the repository at this point in the history
Sort Schema and Content by Name
  • Loading branch information
alexcibotari committed Oct 21, 2024
1 parent c60f590 commit b6e365e
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 50 deletions.
11 changes: 6 additions & 5 deletions src/app/features/spaces/contents/contents.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { filter, switchMap, tap } from 'rxjs/operators';
import { MatSort } from '@angular/material/sort';
import { MatPaginator } from '@angular/material/paginator';
import { NotificationService } from '@shared/services/notification.service';
import { Schema, SchemaType } from '@shared/models/schema.model';
import { Schema, SchemaType, sortSchema } from '@shared/models/schema.model';
import { SchemaService } from '@shared/services/schema.service';
import { combineLatest } from 'rxjs';
import {
Expand All @@ -16,6 +16,7 @@ import {
ContentFolderCreate,
ContentKind,
ContentUpdate,
sortContent,
} from '@shared/models/content.model';
import { ContentService } from '@shared/services/content.service';
import { ObjectUtils } from '@core/utils/object-utils.service';
Expand Down Expand Up @@ -90,10 +91,10 @@ export class ContentsComponent {
)
.subscribe({
next: ([schemas, contents]) => {
this.schemas = schemas;
this.schemasMapById = new Map(schemas.map(it => [it.id, it]));
this.contents = contents;
this.dataSource = new MatTableDataSource<Content>(contents);
this.schemas = schemas.sort(sortSchema);
this.schemasMapById = new Map(this.schemas.map(it => [it.id, it]));
this.contents = contents.sort(sortContent);
this.dataSource = new MatTableDataSource<Content>(this.contents);
this.dataSource.sort = this.sort();
this.dataSource.paginator = this.paginator();
this.isLoading.set(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
SchemaFieldOption,
SchemaFieldOptions,
SchemaType,
sortSchemaEnumValue,
} from '@shared/models/schema.model';
import { FormErrorHandlerService } from '@core/error-handler/form-error-handler.service';
import { AssetContent, ContentData, ContentDocument, ReferenceContent } from '@shared/models/content.model';
Expand Down Expand Up @@ -91,6 +92,10 @@ export class EditDocumentSchemaComponent implements OnInit, OnChanges {
this.schemas()
.filter(it => it.type === SchemaType.ENUM)
.map(it => it as SchemaEnum)
.map(it => {
it.values?.sort(sortSchemaEnumValue);
return it;
})
.map(it => [it.id, it]),
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,17 @@ <h2 mat-dialog-title>Create new Schema</h2>
<mat-form-field>
<mat-label>Type</mat-label>
<mat-select formControlName="type" required>
<mat-select-trigger>
@let selectedType = schemaTypeDescriptions[type];
<mat-icon>{{ selectedType.icon }}</mat-icon>
{{ selectedType.name }}
</mat-select-trigger>
@for (type of types; track type) {
<mat-option [value]="type"> {{ type }}</mat-option>
@let descriptor = schemaTypeDescriptions[type];
<mat-option [value]="type" [matTooltip]="descriptor.description">
<mat-icon>{{ descriptor.icon }}</mat-icon>
{{ descriptor.name }}
</mat-option>
}
</mat-select>
@if (form.controls['type'].errors; as errors) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { AddDialogModel } from './add-dialog.model';
import { SchemaValidator } from '@shared/validators/schema.validator';
import { FormErrorHandlerService } from '@core/error-handler/form-error-handler.service';
import { CommonValidator } from '@shared/validators/common.validator';
import { SchemaType } from '@shared/models/schema.model';
import { SchemaType, schemaTypeDescriptions } from '@shared/models/schema.model';
import { NameUtils } from '@core/utils/name-utils.service';
import { toSignal } from '@angular/core/rxjs-interop';

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

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

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

get type(): SchemaType {
return this.form.controls['type'].value;
}

normalizeId() {
if (this.form.value.slug) {
this.form.controls['id'].setValue(NameUtils.schemaId(this.form.value.id));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
(click)="selectComponent(index)"
[activated]="index === selectedFieldIdx"
[class.invalid]="field.invalid">
<mat-icon matListItemIcon class="type">{{ schemaFieldKindDescriptions[field.value.kind].icon }}</mat-icon>
@let descriptor = schemaFieldKindDescriptions[field.value.kind];
<mat-icon matListItemIcon class="type" [matTooltip]="descriptor.description">{{ descriptor.icon }}</mat-icon>
<span matListItemTitle>
{{ field.value.displayName }} <span class="field-id">#{{ field.value.name }}</span>
</span>
Expand Down
18 changes: 8 additions & 10 deletions src/app/features/spaces/schemas/schemas.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,16 @@
</mat-form-field>
</div>
<mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef mat-sort-header="id"> Id</mat-header-cell>
<mat-cell *matCellDef="let element"> {{ element.id }}</mat-cell>
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef mat-sort-header="type"> Type</mat-header-cell>
<mat-cell *matCellDef="let element">
@let descriptor = schemaTypeDescriptions[element.type];
<mat-icon [matTooltip]="descriptor.description">{{ descriptor.icon }}</mat-icon>
&nbsp; {{ descriptor.name }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header="name"> Name</mat-header-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header="displayName"> Name</mat-header-cell>
<mat-cell *matCellDef="let element">
{{ element.displayName }} &nbsp;<span class="schema-id">#{{ element.id }}</span>
</mat-cell>
Expand All @@ -69,12 +73,6 @@
</mat-chip-set>
</mat-cell>
</ng-container>
<ng-container matColumnDef="type">
<mat-header-cell *matHeaderCellDef mat-sort-header="type"> Type</mat-header-cell>
<mat-cell *matCellDef="let element">
<mat-icon>{{ schemaTypeIcons[element.type] }}</mat-icon> &nbsp; {{ element.type }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="createdAt">
<mat-header-cell *matHeaderCellDef mat-sort-header="createdAt"> Created At</mat-header-cell>
<mat-cell *matCellDef="let element" [matTooltip]="element.createdAt?.toDate() | date: 'medium'">
Expand Down
12 changes: 4 additions & 8 deletions src/app/features/spaces/schemas/schemas.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { NotificationService } from '@shared/services/notification.service';
import { SchemaService } from '@shared/services/schema.service';
import { ConfirmationDialogComponent } from '@shared/components/confirmation-dialog/confirmation-dialog.component';
import { ConfirmationDialogModel } from '@shared/components/confirmation-dialog/confirmation-dialog.model';
import { Schema, SchemaCreate, SchemaFieldKind, SchemaType } from '@shared/models/schema.model';
import { Schema, SchemaCreate, SchemaFieldKind, SchemaType, schemaTypeDescriptions, sortSchema } from '@shared/models/schema.model';
import { AddDialogComponent } from './add-dialog/add-dialog.component';
import { AddDialogModel } from './add-dialog/add-dialog.model';
import { ExportDialogComponent } from './export-dialog/export-dialog.component';
Expand All @@ -46,11 +46,7 @@ export class SchemasComponent implements OnInit {
// Inputs
spaceId = input.required<string>();

schemaTypeIcons: Record<SchemaType, string> = {
ROOT: 'margin',
NODE: 'polyline',
ENUM: 'list',
};
schemaTypeDescriptions = schemaTypeDescriptions;

dataSource: MatTableDataSource<Schema> = new MatTableDataSource<Schema>([]);
displayedColumns: string[] = ['type', 'name', 'description', 'labels', /*'createdAt',*/ 'updatedAt', 'actions'];
Expand Down Expand Up @@ -103,8 +99,8 @@ export class SchemasComponent implements OnInit {
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
next: schemas => {
this.schemas.set(schemas);
this.dataSource.data = schemas;
this.schemas.set(schemas.sort(sortSchema));
this.dataSource.data = this.schemas();
this.dataSource.filterPredicate = this.schemaFilterPredicate;
this.dataSource.sort = this.sort();
this.dataSource.paginator = this.paginator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
{{ selectedFieldKind.name }}
</mat-select-trigger>
@for (kind of fieldKinds; track kind) {
<mat-option [value]="kind">
<mat-icon>{{ schemaFieldKindDescriptions[kind].icon }}</mat-icon>
{{ schemaFieldKindDescriptions[kind].name }}
@let descriptor = schemaFieldKindDescriptions[kind];
<mat-option [value]="kind" [matTooltip]="descriptor.description">
<mat-icon>{{ descriptor.icon }}</mat-icon>
{{ descriptor.name }}
</mat-option>
}
</mat-select>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
schemaFieldKindDescriptions,
SchemaFieldOptionSelectable,
SchemaType,
sortSchema,
} from '@shared/models/schema.model';
import { MatSelectChange } from '@angular/material/select';
import { FormErrorHandlerService } from '@core/error-handler/form-error-handler.service';
Expand All @@ -32,8 +33,16 @@ export class EditFieldComponent implements OnInit {
selectedFieldKind = this.schemaFieldKindDescriptions[SchemaFieldKind.TEXT];
nameReadonly = true;
// Schemas
nodeSchemas = computed(() => this.schemas().filter(it => it.type === SchemaType.NODE));
enumSchemas = computed(() => this.schemas().filter(it => it.type === SchemaType.ENUM));
nodeSchemas = computed(() =>
this.schemas()
.filter(it => it.type === SchemaType.NODE)
.sort(sortSchema),
);
enumSchemas = computed(() =>
this.schemas()
.filter(it => it.type === SchemaType.ENUM)
.sort(sortSchema),
);

settingsStore = inject(LocalSettingsStore);

Expand Down
6 changes: 6 additions & 0 deletions src/app/shared/models/content.model.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { FieldValue, Timestamp } from '@angular/fire/firestore';
import { ValidationErrors } from '@angular/forms';

export function sortContent(a: Content, b: Content): number {
const aIsFolder = a.kind === ContentKind.FOLDER ? 0 : 1;
const bIsFolder = b.kind === ContentKind.FOLDER ? 0 : 1;
return `${aIsFolder}${a.name}`.localeCompare(`${bIsFolder}${b.name}`);
}

export interface ContentError {
contentId: string;
locale: string;
Expand Down
59 changes: 42 additions & 17 deletions src/app/shared/models/schema.model.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
import { Timestamp } from '@angular/fire/firestore';

export function sortSchema(a: Schema, b: Schema): number {
if (a.displayName && b.displayName) {
return a.displayName.localeCompare(b.displayName);
} else {
return a.id.localeCompare(b.id);
}
}

export function sortSchemaEnumValue(a: SchemaEnumValue, b: SchemaEnumValue): number {
return a.name.localeCompare(b.name);
}

export enum SchemaType {
ROOT = 'ROOT',
NODE = 'NODE',
ENUM = 'ENUM',
}

export interface FieldTypeDescription {
name: string;
description: string;
icon: string;
}

export const schemaTypeDescriptions: Record<SchemaType, FieldTypeDescription> = {
ROOT: { name: 'Root', icon: 'margin', description: 'Root schema, top level schema' },
NODE: { name: 'Node', icon: 'polyline', description: 'Node schema, nested schema' },
ENUM: { name: 'Enum', icon: 'list', description: 'Enum schema, list of values' },
};

export type Schema = SchemaComponent | SchemaEnum;

export interface SchemaBase {
Expand Down Expand Up @@ -76,27 +100,28 @@ export enum SchemaFieldKind {

export interface FieldKindDescription {
name: string;
description: string;
icon: string;
}

export const schemaFieldKindDescriptions: Record<SchemaFieldKind, FieldKindDescription> = {
TEXT: { name: 'Text', icon: 'title' },
TEXTAREA: { name: 'TextArea', icon: 'rtt' },
MARKDOWN: { name: 'Markdown', icon: 'functions' },
NUMBER: { name: 'Number', icon: 'pin' },
COLOR: { name: 'Color', icon: 'colorize' },
DATE: { name: 'Date', icon: 'event' },
DATETIME: { name: 'Date and Time', icon: 'schedule' },
BOOLEAN: { name: 'Boolean', icon: 'toggle_on' },
OPTION: { name: 'Single Option', icon: 'list' },
OPTIONS: { name: 'Multiple Options', icon: 'list' },
LINK: { name: 'Link', icon: 'link' },
REFERENCE: { name: 'Reference (One)', icon: 'link' },
REFERENCES: { name: 'References (Many)', icon: 'link' },
ASSET: { name: 'Asset ( One )', icon: 'attachment' },
ASSETS: { name: 'Assets ( Many )', icon: 'attachment' },
SCHEMA: { name: 'Schema ( One )', icon: 'polyline' },
SCHEMAS: { name: 'Schemas ( Many )', icon: 'polyline' },
TEXT: { name: 'Text', icon: 'title', description: 'Short text field, titles or headlines' },
TEXTAREA: { name: 'TextArea', icon: 'rtt', description: 'Long text field, description' },
MARKDOWN: { name: 'Markdown', icon: 'functions', description: 'Markdown text field, description' },
NUMBER: { name: 'Number', icon: 'pin', description: 'Number field, amount or quantity' },
COLOR: { name: 'Color', icon: 'colorize', description: 'Color field, background or text color' },
DATE: { name: 'Date', icon: 'event', description: 'Date field, calendar date picker' },
DATETIME: { name: 'Date and Time', icon: 'schedule', description: 'Date and time field, calendar date and time picker' },
BOOLEAN: { name: 'Boolean', icon: 'toggle_on', description: 'Boolean field, true or false' },
OPTION: { name: 'Option (One)', icon: 'list', description: 'Single selection field, dropdown' },
OPTIONS: { name: 'Options (Multiple)', icon: 'list', description: 'Multiple selection field, dropdown' },
LINK: { name: 'Link', icon: 'link', description: 'Link field, external URL or internal resource' },
REFERENCE: { name: 'Reference (One)', icon: 'link', description: 'Reference field, to a internal resource' },
REFERENCES: { name: 'References (Multiple)', icon: 'link', description: 'References field, to multiple internal resources' },
ASSET: { name: 'Asset (One)', icon: 'attachment', description: 'Asset field, image, video or file' },
ASSETS: { name: 'Assets (Multiple)', icon: 'attachment', description: 'Assets field, multiple images, videos or files' },
SCHEMA: { name: 'Schema (One)', icon: 'polyline', description: 'Schema field, to a internal schema' },
SCHEMAS: { name: 'Schemas (Multiple)', icon: 'polyline', description: 'Schemas field, to multiple internal schemas' },
};

export interface SchemaFieldBase {
Expand Down

0 comments on commit b6e365e

Please sign in to comment.