Remove common module, add friendy name editing, add enum options editing, fix list option warning
Some checks failed
release-nightly / macos (push) Failing after 23s
release-nightly / web-demo (push) Failing after 4m25s

This commit is contained in:
2025-05-13 20:49:46 +09:30
parent dd8d1374ab
commit ec0f21cf16
20 changed files with 208 additions and 174 deletions

View File

@@ -1,5 +1,4 @@
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { CommonModule } from '@angular/common';
import { Component, signal, inject } from '@angular/core'; import { Component, signal, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
@@ -22,7 +21,6 @@ const mobileBreakpoints = [Breakpoints.Handset, Breakpoints.TabletPortrait];
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrl: './app.component.scss', styleUrl: './app.component.scss',
imports: [ imports: [
CommonModule,
EditorComponent, EditorComponent,
FileTreeComponent, FileTreeComponent,
MatButtonModule, MatButtonModule,

View File

@@ -7,7 +7,7 @@
<div class="editor-items"> <div class="editor-items">
@if(values()) { @for (item of selectedMessage().values; track $index) { @if(values()) { @for (item of selectedMessage().values; track $index) {
<app-proto-field <app-proto-field
[label]="item.name" [label]="item.friendlyName || item.name"
[configuration]="item.configuration" [configuration]="item.configuration"
[value]="values()[item.name]" [value]="values()[item.name]"
(valueChange)="updateValue(item.name, $event)" (valueChange)="updateValue(item.name, $event)"

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
Component, Component,
ElementRef, ElementRef,
@@ -31,7 +30,6 @@ type PreviewType = 'raw' | 'edit' | 'diff';
@Component({ @Component({
selector: 'app-editor', selector: 'app-editor',
imports: [ imports: [
CommonModule,
ProtoFieldComponent, ProtoFieldComponent,
MatButtonModule, MatButtonModule,
MatButtonToggleModule, MatButtonToggleModule,
@@ -102,17 +100,14 @@ export class EditorComponent {
} }
} }
}); });
effect( effect(() => {
() => {
const message = this.selectedMessage(); const message = this.selectedMessage();
this.values.set( this.values.set(
Object.fromEntries( Object.fromEntries(
message.values.map((value) => [[value.name, undefined]]) message.values.map((value) => [[value.name, undefined]])
) )
); );
}, });
{ allowSignalWrites: true }
);
effect(async () => { effect(async () => {
const selectedFile = this.selectedFile(); const selectedFile = this.selectedFile();

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
AfterViewInit, AfterViewInit,
ChangeDetectionStrategy, ChangeDetectionStrategy,
@@ -16,7 +15,6 @@ import { ProtoFieldComponent } from '../proto-field/proto-field.component';
@Component({ @Component({
selector: 'app-list-field', selector: 'app-list-field',
imports: [ imports: [
CommonModule,
MatButtonModule, MatButtonModule,
MatIconModule, MatIconModule,
forwardRef(() => ProtoFieldComponent), forwardRef(() => ProtoFieldComponent),
@@ -38,7 +36,7 @@ import { ProtoFieldComponent } from '../proto-field/proto-field.component';
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</button>`, </button>`,
styleUrl: './list-field.component.scss', styleUrl: './list-field.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ListFieldComponent { export class ListFieldComponent {
label = input<string>(); label = input<string>();

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@@ -18,7 +17,6 @@ const keyIsEmpty = (key: string | number) => key == null || key === '';
@Component({ @Component({
selector: 'app-map-field', selector: 'app-map-field',
imports: [ imports: [
CommonModule,
forwardRef(() => ProtoFieldComponent), forwardRef(() => ProtoFieldComponent),
MatIconModule, MatIconModule,
MatButtonModule, MatButtonModule,
@@ -45,7 +43,7 @@ const keyIsEmpty = (key: string | number) => key == null || key === '';
<mat-icon>add</mat-icon> <mat-icon>add</mat-icon>
</button>`, </button>`,
styleUrl: './map-field.component.scss', styleUrl: './map-field.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class MapFieldComponent { export class MapFieldComponent {
label = input<string>(); label = input<string>();
@@ -57,8 +55,7 @@ export class MapFieldComponent {
private changedInternal = false; private changedInternal = false;
constructor() { constructor() {
effect( effect(() => {
() => {
// TODO: Super hacky but can't really think of another way to keep these in sync // TODO: Super hacky but can't really think of another way to keep these in sync
// without removing an entry when the key gets blanked. Would need an alternate // without removing an entry when the key gets blanked. Would need an alternate
// design that updated on blur only perhaps // design that updated on blur only perhaps
@@ -70,9 +67,7 @@ export class MapFieldComponent {
if (values) { if (values) {
this.valuePairs.set(Object.entries(values)); this.valuePairs.set(Object.entries(values));
} }
}, });
{ allowSignalWrites: true }
);
} }
add() { add() {

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@@ -12,14 +11,14 @@ import { ProtoFieldComponent } from '../proto-field/proto-field.component';
@Component({ @Component({
selector: 'app-object-field', selector: 'app-object-field',
imports: [CommonModule, forwardRef(() => ProtoFieldComponent)], imports: [forwardRef(() => ProtoFieldComponent)],
template: `<h3> template: `<h3>
{{ label() }} ({{ configuration().messageDefinition.name }}) {{ label() }} ({{ configuration().messageDefinition.name }})
</h3> </h3>
<div> <div>
@for (item of configuration().messageDefinition.values; track $index) { @for (item of configuration().messageDefinition.values; track $index) {
<app-proto-field <app-proto-field
[label]="item.name" [label]="item.friendlyName || item.name"
[configuration]="item.configuration" [configuration]="item.configuration"
[value]="currentValue()[item.name]" [value]="currentValue()[item.name]"
(valueChange)="updateValue(item.name, $event)" (valueChange)="updateValue(item.name, $event)"
@@ -27,7 +26,7 @@ import { ProtoFieldComponent } from '../proto-field/proto-field.component';
} }
</div>`, </div>`,
styleUrl: './object-field.component.scss', styleUrl: './object-field.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ObjectFieldComponent { export class ObjectFieldComponent {
label = input<string>(); label = input<string>();

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@@ -29,7 +28,6 @@ import { StringFieldComponent } from '../string-field/string-field.component';
@Component({ @Component({
selector: 'app-proto-field', selector: 'app-proto-field',
imports: [ imports: [
CommonModule,
FormsModule, FormsModule,
ListFieldComponent, ListFieldComponent,
MapFieldComponent, MapFieldComponent,
@@ -57,14 +55,17 @@ import { StringFieldComponent } from '../string-field/string-field.component';
[min]="numericConfiguration().min ?? null" [min]="numericConfiguration().min ?? null"
[max]="numericConfiguration().max ?? null" [max]="numericConfiguration().max ?? null"
/> />
<mat-hint *ngIf="number.hasError('min')" @if(number.hasError('min')) {
<mat-hint
>Number should not be less than >Number should not be less than
{{ numericConfiguration().min }}</mat-hint {{ numericConfiguration().min }}</mat-hint
> >
<mat-hint *ngIf="number.hasError('max')" } @if(number.hasError('max')) {
<mat-hint
>Number should not greater than >Number should not greater than
{{ numericConfiguration().max }}</mat-hint {{ numericConfiguration().max }}</mat-hint
> >
}
</mat-form-field> </mat-form-field>
} @case (MessageTypeEnum.Boolean) { } @case (MessageTypeEnum.Boolean) {
<p> <p>
@@ -74,10 +75,11 @@ import { StringFieldComponent } from '../string-field/string-field.component';
<mat-form-field> <mat-form-field>
<mat-label>{{ label() }}</mat-label> <mat-label>{{ label() }}</mat-label>
<mat-select [(value)]="value"> <mat-select [(value)]="value">
@for(option of enumConfiguration().options; track
enumConfiguration()!.options) {
<mat-option>None</mat-option> <mat-option>None</mat-option>
<mat-option [value]="option">{{ option }}</mat-option> @for(option of enumConfiguration().options; track option) {
<mat-option [value]="option">{{
option.friendlyName || option.protoName
}}</mat-option>
} }
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@@ -101,7 +103,7 @@ import { StringFieldComponent } from '../string-field/string-field.component';
></app-object-field> ></app-object-field>
} @case (MessageTypeEnum.Raw) {}}`, } @case (MessageTypeEnum.Raw) {}}`,
styleUrl: './proto-field.component.scss', styleUrl: './proto-field.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ProtoFieldComponent { export class ProtoFieldComponent {
label = input<string>(); label = input<string>();

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@@ -14,7 +13,6 @@ import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
@Component({ @Component({
selector: 'app-string-field', selector: 'app-string-field',
imports: [ imports: [
CommonModule,
FormsModule, FormsModule,
MatFormFieldModule, MatFormFieldModule,
MatInputModule, MatInputModule,
@@ -44,7 +42,7 @@ import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
></ngx-monaco-editor> ></ngx-monaco-editor>
}`, }`,
styleUrl: './string-field.component.css', styleUrl: './string-field.component.css',
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class StringFieldComponent { export class StringFieldComponent {
label = input(); label = input();

View File

@@ -1,5 +1,4 @@
import { FlatTreeControl } from '@angular/cdk/tree'; import { FlatTreeControl } from '@angular/cdk/tree';
import { CommonModule } from '@angular/common';
import { import {
Component, Component,
ElementRef, ElementRef,
@@ -40,7 +39,7 @@ const collator = new Intl.Collator(undefined, { numeric: true });
@Component({ @Component({
selector: 'app-file-tree', selector: 'app-file-tree',
imports: [CommonModule, MatButtonModule, MatIconModule, MatTreeModule], imports: [MatButtonModule, MatIconModule, MatTreeModule],
templateUrl: './file-tree.component.html', templateUrl: './file-tree.component.html',
styleUrl: './file-tree.component.scss', styleUrl: './file-tree.component.scss',
}) })

View File

@@ -38,8 +38,13 @@ export interface ObjectMessage extends MessageConfiguration {
export interface RawMessage extends MessageConfiguration {} export interface RawMessage extends MessageConfiguration {}
export interface EnumMessageOption {
protoName: string;
friendlyName?: string;
}
export interface EnumMessage extends MessageConfiguration { export interface EnumMessage extends MessageConfiguration {
options: string[]; options: EnumMessageOption[];
} }
export interface MessageConfiguration { export interface MessageConfiguration {
@@ -90,11 +95,12 @@ export const RawMessage = (): RawMessage => ({ type: MessageTypeEnum.Raw });
export const EnumMessage = (options: string[]) => ({ export const EnumMessage = (options: string[]) => ({
type: MessageTypeEnum.Enum, type: MessageTypeEnum.Enum,
options, options: options.map((option) => ({ protoName: option })),
}); });
export interface ProtoMessageField<T extends MessageConfiguration> { export interface ProtoMessageField<T extends MessageConfiguration> {
name: string; name: string;
friendlyName?: string;
configuration: T; configuration: T;
} }
@@ -119,7 +125,9 @@ export const UnknownProto = (
): ProtoMessage => ({ ): ProtoMessage => ({
name, name,
fullName, fullName,
values: [{ name: 'Raw JSON', configuration: RawMessage() }], values: [
{ name: 'Raw JSON', friendlyName: 'Raw JSON', configuration: RawMessage() },
],
}); });
export const EDITABLE_MESSAGE_TYPES = [ export const EDITABLE_MESSAGE_TYPES = [

View File

@@ -1,13 +1,12 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, input } from '@angular/core'; import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import { import {
EnumMessage,
ListMessage, ListMessage,
MapMessage, MapMessage,
MessageConfiguration, MessageConfiguration,
MessageTypeEnum, MessageTypeEnum,
NumericMessage, NumericMessage,
ObjectMessage, ObjectMessage,
ProtoMessageField,
StringMessage, StringMessage,
} from '../../../model/proto-message.model'; } from '../../../model/proto-message.model';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
@@ -18,11 +17,11 @@ import { ListEditorFieldComponent } from '../list-editor-field/list-editor-field
import { MapEditorFieldComponent } from '../map-editor-field/map-editor-field.component'; import { MapEditorFieldComponent } from '../map-editor-field/map-editor-field.component';
import { ObjectEditorFieldComponent } from '../object-editor-field/object-editor-field.component'; import { ObjectEditorFieldComponent } from '../object-editor-field/object-editor-field.component';
import { StringEditorFieldComponent } from '../string-editor-field/string-editor-field.component'; import { StringEditorFieldComponent } from '../string-editor-field/string-editor-field.component';
import { EnumEditorFieldComponent } from '../enum-editor-field/enum-editor-field.component';
@Component({ @Component({
selector: 'app-definition-editor-field', selector: 'app-definition-editor-field',
imports: [ imports: [
CommonModule,
FormsModule, FormsModule,
ListEditorFieldComponent, ListEditorFieldComponent,
MapEditorFieldComponent, MapEditorFieldComponent,
@@ -31,6 +30,7 @@ import { StringEditorFieldComponent } from '../string-editor-field/string-editor
MatSelectModule, MatSelectModule,
ObjectEditorFieldComponent, ObjectEditorFieldComponent,
StringEditorFieldComponent, StringEditorFieldComponent,
EnumEditorFieldComponent,
], ],
template: ` @switch (fieldConfiguration().type) { template: ` @switch (fieldConfiguration().type) {
@case(MessageTypeEnum.String) { @case(MessageTypeEnum.String) {
@@ -48,9 +48,11 @@ import { StringEditorFieldComponent } from '../string-editor-field/string-editor
[(ngModel)]="configuration.min" [(ngModel)]="configuration.min"
[max]="configuration.max ?? null" [max]="configuration.max ?? null"
/> />
<mat-hint *ngIf="min.hasError('max')" @if(min.hasError('max')) {
<mat-hint
>Min should not be greater than {{ configuration.max }}</mat-hint >Min should not be greater than {{ configuration.max }}</mat-hint
> >
}
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Max</mat-label> <mat-label>Max</mat-label>
@@ -61,9 +63,9 @@ import { StringEditorFieldComponent } from '../string-editor-field/string-editor
[(ngModel)]="configuration.max" [(ngModel)]="configuration.max"
[min]="configuration.min ?? null" [min]="configuration.min ?? null"
/> />
<mat-hint *ngIf="max.hasError('min')" @if(max.hasError('min')) {
>Max should not be less than {{ configuration.min }}</mat-hint <mat-hint>Max should not be less than {{ configuration.min }}</mat-hint>
> }
</mat-form-field> </mat-form-field>
} @case (MessageTypeEnum.List) { } @case (MessageTypeEnum.List) {
<app-list-editor-field <app-list-editor-field
@@ -77,6 +79,10 @@ import { StringEditorFieldComponent } from '../string-editor-field/string-editor
<app-object-editor-field <app-object-editor-field
[field]="objectConfiguration(fieldConfiguration())" [field]="objectConfiguration(fieldConfiguration())"
></app-object-editor-field> ></app-object-editor-field>
} @case(MessageTypeEnum.Enum) {
<app-enum-editor-field
[configuration]="enumConfiguration(fieldConfiguration())"
></app-enum-editor-field>
} }`, } }`,
styleUrl: './definition-editor-field.component.css', styleUrl: './definition-editor-field.component.css',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
@@ -104,5 +110,9 @@ export class DefinitionEditorFieldComponent {
return configuration as ObjectMessage; return configuration as ObjectMessage;
} }
protected enumConfiguration(configuration: MessageConfiguration) {
return configuration as EnumMessage;
}
protected readonly MessageTypeEnum = MessageTypeEnum; protected readonly MessageTypeEnum = MessageTypeEnum;
} }

View File

@@ -0,0 +1,3 @@
mat-form-field {
display: block;
}

View File

@@ -1,9 +1,7 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { import {
EDITABLE_MESSAGE_TYPES,
ListMessage, ListMessage,
MessageConfiguration, MessageConfiguration,
MessageTypeEnum, MessageTypeEnum,
@@ -11,13 +9,18 @@ import {
ProtoMessage, ProtoMessage,
} from '../../model/proto-message.model'; } from '../../model/proto-message.model';
import { DefinitionEditorFieldComponent } from './definition-editor-field/definition-editor-field.component'; import { DefinitionEditorFieldComponent } from './definition-editor-field/definition-editor-field.component';
import { MatFormFieldModule } from '@angular/material/form-field';
import { FormsModule } from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
@Component({ @Component({
selector: 'app-definition-editor', selector: 'app-definition-editor',
imports: [ imports: [
CommonModule, FormsModule,
MatButtonModule, MatButtonModule,
MatDialogModule, MatDialogModule,
MatFormFieldModule,
MatInputModule,
DefinitionEditorFieldComponent, DefinitionEditorFieldComponent,
], ],
template: ` template: `
@@ -25,6 +28,14 @@ import { DefinitionEditorFieldComponent } from './definition-editor-field/defini
<mat-dialog-content> <mat-dialog-content>
@for (field of editableMessages; track $index) { @for (field of editableMessages; track $index) {
<h3>{{ field.name }}</h3> <h3>{{ field.name }}</h3>
<mat-form-field>
<mat-label>Friendly Name</mat-label>
<input
matInput
[(ngModel)]="field.friendlyName"
placeholder="Optional"
/>
</mat-form-field>
<app-definition-editor-field <app-definition-editor-field
[fieldConfiguration]="field.configuration" [fieldConfiguration]="field.configuration"
></app-definition-editor-field> ></app-definition-editor-field>
@@ -40,26 +51,5 @@ import { DefinitionEditorFieldComponent } from './definition-editor-field/defini
export class DefinitionEditorComponent { export class DefinitionEditorComponent {
protected protoMessage = inject<ProtoMessage>(MAT_DIALOG_DATA); protected protoMessage = inject<ProtoMessage>(MAT_DIALOG_DATA);
protected editableMessages = this.protoMessage.values.filter((message) => protected editableMessages = this.protoMessage.values;
this.filterMessageConfiguration(message.configuration)
);
private filterMessageConfiguration(
configuration: MessageConfiguration
): boolean {
if (configuration.type === MessageTypeEnum.List) {
return this.filterMessageConfiguration(
(configuration as ListMessage).subConfiguration
);
}
if (configuration.type === MessageTypeEnum.Object) {
// Ensure at least one nested message can be configured
return !!(configuration as ObjectMessage).messageDefinition.values.find(
(message) => this.filterMessageConfiguration(message.configuration)
);
}
// Note: Map can always be configured, as key needs to be a string or numeric type
return EDITABLE_MESSAGE_TYPES.includes(configuration.type);
}
} }

View File

@@ -0,0 +1,3 @@
mat-form-field {
display: block;
}

View File

@@ -0,0 +1,28 @@
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import { EnumMessage } from '../../../model/proto-message.model';
import { MatFormFieldModule, MatLabel } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-enum-editor-field',
standalone: true,
imports: [FormsModule, MatFormFieldModule, MatInputModule, MatLabel],
template: `
@for (option of configuration().options; track $index) {
<mat-form-field>
<mat-label>{{ option.protoName }}</mat-label>
<input
matInput
[(ngModel)]="option.friendlyName"
placeholder="Friendly Name"
/>
</mat-form-field>
}
`,
styleUrl: './enum-editor-field.component.css',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class EnumEditorFieldComponent {
configuration = input.required<EnumMessage>();
}

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@@ -10,7 +9,7 @@ import { ListMessage } from '../../../model/proto-message.model';
@Component({ @Component({
selector: 'app-list-editor-field', selector: 'app-list-editor-field',
imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)], imports: [forwardRef(() => DefinitionEditorFieldComponent)],
template: `<app-definition-editor-field template: `<app-definition-editor-field
[fieldConfiguration]="field().subConfiguration" [fieldConfiguration]="field().subConfiguration"
></app-definition-editor-field>`, ></app-definition-editor-field>`,

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@@ -14,7 +13,7 @@ import {
@Component({ @Component({
selector: 'app-map-editor-field', selector: 'app-map-editor-field',
imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)], imports: [forwardRef(() => DefinitionEditorFieldComponent)],
template: ` template: `
<h4>Key Configuration</h4> <h4>Key Configuration</h4>
<app-definition-editor-field <app-definition-editor-field

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
Component, Component,
@@ -6,31 +5,43 @@ import {
forwardRef, forwardRef,
input, input,
} from '@angular/core'; } from '@angular/core';
import { import { ObjectMessage } from '../../../model/proto-message.model';
EDITABLE_MESSAGE_TYPES,
ObjectMessage,
} from '../../../model/proto-message.model';
import { DefinitionEditorFieldComponent } from '../definition-editor-field/definition-editor-field.component'; import { DefinitionEditorFieldComponent } from '../definition-editor-field/definition-editor-field.component';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { FormsModule } from '@angular/forms';
@Component({ @Component({
selector: 'app-object-editor-field', selector: 'app-object-editor-field',
imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)], imports: [
FormsModule,
MatFormFieldModule,
MatInputModule,
forwardRef(() => DefinitionEditorFieldComponent),
],
template: ` template: `
@for (field of editableFields(); track $index) { @for (field of editableFields(); track $index) {
<h4>{{ field.name }}</h4> <h4>{{ field.name }}</h4>
<mat-form-field>
<mat-label>Friendly Name</mat-label>
<input matInput [(ngModel)]="field.friendlyName" placeholder="Optional" />
</mat-form-field>
<app-definition-editor-field <app-definition-editor-field
[fieldConfiguration]="field.configuration" [fieldConfiguration]="field.configuration"
></app-definition-editor-field> ></app-definition-editor-field>
} }
`, `,
styles: `
mat-form-field {
display: block;
}
`,
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ObjectEditorFieldComponent { export class ObjectEditorFieldComponent {
field = input.required<ObjectMessage>(); field = input.required<ObjectMessage>();
protected editableFields = computed(() => protected editableFields = computed(
this.field().messageDefinition.values.filter((field) => () => this.field().messageDefinition.values
EDITABLE_MESSAGE_TYPES.includes(field.configuration.type)
)
); );
} }

View File

@@ -1,4 +1,3 @@
import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, Component, input } from '@angular/core'; import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
@@ -8,14 +7,9 @@ import { MatInputModule } from '@angular/material/input';
@Component({ @Component({
selector: 'app-string-editor-field', selector: 'app-string-editor-field',
imports: [ imports: [FormsModule, MatFormFieldModule, MatInputModule, MatSelectModule],
CommonModule, template: `
FormsModule, <mat-form-field>
MatFormFieldModule,
MatInputModule,
MatSelectModule,
],
template: ` <mat-form-field>
<mat-label>Max Length</mat-label> <mat-label>Max Length</mat-label>
<input matInput type="number" [(ngModel)]="configuration().maxLength" /> <input matInput type="number" [(ngModel)]="configuration().maxLength" />
</mat-form-field> </mat-form-field>
@@ -25,7 +19,8 @@ import { MatInputModule } from '@angular/material/input';
<mat-option value="text">Text</mat-option> <mat-option value="text">Text</mat-option>
<mat-option value="sql">SQL</mat-option> <mat-option value="sql">SQL</mat-option>
</mat-select> </mat-select>
</mat-form-field>`, </mat-form-field>
`,
styleUrl: './string-editor-field.component.scss', styleUrl: './string-editor-field.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })

View File

@@ -1,16 +1,26 @@
import { CommonModule } from '@angular/common'; import {
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, HostListener, computed, output, signal, viewChild, inject } from '@angular/core'; ChangeDetectionStrategy,
Component,
ElementRef,
HostBinding,
HostListener,
computed,
inject,
output,
signal,
viewChild,
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatListModule, MatSelectionList } from '@angular/material/list';
import { ProtoMessage } from '../model/proto-message.model';
import { ProtoDefinitionService } from './proto-definition.service';
import { MatTreeModule } from '@angular/material/tree';
import { MatSnackBar } from '@angular/material/snack-bar';
import { writeTextFile } from '@tauri-apps/api/fs';
import { save } from '@tauri-apps/api/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule, MatSelectionList } from '@angular/material/list';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTreeModule } from '@angular/material/tree';
import { save } from '@tauri-apps/api/dialog';
import { writeTextFile } from '@tauri-apps/api/fs';
import { ProtoMessage } from '../model/proto-message.model';
import { DefinitionEditorComponent } from './definition-editor/definition-editor.component'; import { DefinitionEditorComponent } from './definition-editor/definition-editor.component';
import { ProtoDefinitionService } from './proto-definition.service';
declare const __TAURI__: any; declare const __TAURI__: any;
@@ -18,13 +28,7 @@ const collator = new Intl.Collator(undefined, { numeric: true });
@Component({ @Component({
selector: 'app-proto-definition-selector', selector: 'app-proto-definition-selector',
imports: [ imports: [MatButtonModule, MatIconModule, MatListModule, MatTreeModule],
CommonModule,
MatButtonModule,
MatIconModule,
MatListModule,
MatTreeModule,
],
template: ` template: `
<h2>Protobuf Definitions</h2> <h2>Protobuf Definitions</h2>
<button mat-button (click)="protoSelector.click()"> <button mat-button (click)="protoSelector.click()">
@@ -66,7 +70,7 @@ const collator = new Intl.Collator(undefined, { numeric: true });
> >
<mat-icon>edit</mat-icon> <mat-icon>edit</mat-icon>
</button> </button>
<div matListItemLine>{{ item.name }}</div> <div>{{ item.name }}</div>
</mat-list-option> </mat-list-option>
} }
</mat-selection-list> </mat-selection-list>