diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 2a44b6f..01788bc 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,5 +1,4 @@ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; -import { CommonModule } from '@angular/common'; import { Component, signal, inject } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; @@ -22,7 +21,6 @@ const mobileBreakpoints = [Breakpoints.Handset, Breakpoints.TabletPortrait]; templateUrl: './app.component.html', styleUrl: './app.component.scss', imports: [ - CommonModule, EditorComponent, FileTreeComponent, MatButtonModule, diff --git a/src/app/editor/editor.component.html b/src/app/editor/editor.component.html index b13c18e..90c4200 100644 --- a/src/app/editor/editor.component.html +++ b/src/app/editor/editor.component.html @@ -7,7 +7,7 @@
@if(values()) { @for (item of selectedMessage().values; track $index) { { - const message = this.selectedMessage(); - this.values.set( - Object.fromEntries( - message.values.map((value) => [[value.name, undefined]]) - ) - ); - }, - { allowSignalWrites: true } - ); + effect(() => { + const message = this.selectedMessage(); + this.values.set( + Object.fromEntries( + message.values.map((value) => [[value.name, undefined]]) + ) + ); + }); effect(async () => { const selectedFile = this.selectedFile(); diff --git a/src/app/editor/list-field/list-field.component.ts b/src/app/editor/list-field/list-field.component.ts index 4ee3b73..e20b948 100644 --- a/src/app/editor/list-field/list-field.component.ts +++ b/src/app/editor/list-field/list-field.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { AfterViewInit, ChangeDetectionStrategy, @@ -14,14 +13,13 @@ import { ListMessage } from '../../model/proto-message.model'; import { ProtoFieldComponent } from '../proto-field/proto-field.component'; @Component({ - selector: 'app-list-field', - imports: [ - CommonModule, - MatButtonModule, - MatIconModule, - forwardRef(() => ProtoFieldComponent), - ], - template: `

{{ label() }}

+ selector: 'app-list-field', + imports: [ + MatButtonModule, + MatIconModule, + forwardRef(() => ProtoFieldComponent), + ], + template: `

{{ label() }}

@if(values()) { @for(value of values(); track $index) {
add `, - styleUrl: './list-field.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush + styleUrl: './list-field.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ListFieldComponent { label = input(); diff --git a/src/app/editor/map-field/map-field.component.ts b/src/app/editor/map-field/map-field.component.ts index 5a840ab..31d761e 100644 --- a/src/app/editor/map-field/map-field.component.ts +++ b/src/app/editor/map-field/map-field.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -16,14 +15,13 @@ import { ProtoFieldComponent } from '../proto-field/proto-field.component'; const keyIsEmpty = (key: string | number) => key == null || key === ''; @Component({ - selector: 'app-map-field', - imports: [ - CommonModule, - forwardRef(() => ProtoFieldComponent), - MatIconModule, - MatButtonModule, - ], - template: `

{{ label() }}

+ selector: 'app-map-field', + imports: [ + forwardRef(() => ProtoFieldComponent), + MatIconModule, + MatButtonModule, + ], + template: `

{{ label() }}

@if(valuePairs()) { @for(value of valuePairs(); track $index) {
key == null || key === ''; `, - styleUrl: './map-field.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush + styleUrl: './map-field.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class MapFieldComponent { label = input(); @@ -57,22 +55,19 @@ export class MapFieldComponent { private changedInternal = false; constructor() { - effect( - () => { - // 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 - // design that updated on blur only perhaps - if (this.changedInternal) { - this.changedInternal = false; - return; - } - const values = this.values(); - if (values) { - this.valuePairs.set(Object.entries(values)); - } - }, - { allowSignalWrites: true } - ); + effect(() => { + // 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 + // design that updated on blur only perhaps + if (this.changedInternal) { + this.changedInternal = false; + return; + } + const values = this.values(); + if (values) { + this.valuePairs.set(Object.entries(values)); + } + }); } add() { diff --git a/src/app/editor/object-field/object-field.component.ts b/src/app/editor/object-field/object-field.component.ts index 725af8d..4c8a670 100644 --- a/src/app/editor/object-field/object-field.component.ts +++ b/src/app/editor/object-field/object-field.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -11,23 +10,23 @@ import { ObjectMessage } from '../../model/proto-message.model'; import { ProtoFieldComponent } from '../proto-field/proto-field.component'; @Component({ - selector: 'app-object-field', - imports: [CommonModule, forwardRef(() => ProtoFieldComponent)], - template: `

+ selector: 'app-object-field', + imports: [forwardRef(() => ProtoFieldComponent)], + template: `

{{ label() }} ({{ configuration().messageDefinition.name }})

@for (item of configuration().messageDefinition.values; track $index) { }
`, - styleUrl: './object-field.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush + styleUrl: './object-field.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ObjectFieldComponent { label = input(); diff --git a/src/app/editor/proto-field/proto-field.component.ts b/src/app/editor/proto-field/proto-field.component.ts index a40ecbf..4a1fca2 100644 --- a/src/app/editor/proto-field/proto-field.component.ts +++ b/src/app/editor/proto-field/proto-field.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -27,20 +26,19 @@ import { ObjectFieldComponent } from '../object-field/object-field.component'; import { StringFieldComponent } from '../string-field/string-field.component'; @Component({ - selector: 'app-proto-field', - imports: [ - CommonModule, - FormsModule, - ListFieldComponent, - MapFieldComponent, - MatCheckboxModule, - MatFormFieldModule, - MatSelectModule, - MatInputModule, - ObjectFieldComponent, - StringFieldComponent, - ], - template: `@switch (configuration().type) { @case (MessageTypeEnum.String) { + selector: 'app-proto-field', + imports: [ + FormsModule, + ListFieldComponent, + MapFieldComponent, + MatCheckboxModule, + MatFormFieldModule, + MatSelectModule, + MatInputModule, + ObjectFieldComponent, + StringFieldComponent, + ], + template: `@switch (configuration().type) { @case (MessageTypeEnum.String) { - Number should not be less than {{ numericConfiguration().min }} - Number should not greater than {{ numericConfiguration().max }} + } } @case (MessageTypeEnum.Boolean) {

@@ -74,10 +75,11 @@ import { StringFieldComponent } from '../string-field/string-field.component'; {{ label() }} - @for(option of enumConfiguration().options; track - enumConfiguration()!.options) { None - {{ option }} + @for(option of enumConfiguration().options; track option) { + {{ + option.friendlyName || option.protoName + }} } @@ -100,8 +102,8 @@ import { StringFieldComponent } from '../string-field/string-field.component'; [configuration]="objectConfiguration()" > } @case (MessageTypeEnum.Raw) {}}`, - styleUrl: './proto-field.component.scss', - changeDetection: ChangeDetectionStrategy.OnPush + styleUrl: './proto-field.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ProtoFieldComponent { label = input(); diff --git a/src/app/editor/string-field/string-field.component.ts b/src/app/editor/string-field/string-field.component.ts index 6e04ecd..f75d3ad 100644 --- a/src/app/editor/string-field/string-field.component.ts +++ b/src/app/editor/string-field/string-field.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -12,15 +11,14 @@ import { MatInputModule } from '@angular/material/input'; import { MonacoEditorModule } from 'ngx-monaco-editor-v2'; @Component({ - selector: 'app-string-field', - imports: [ - CommonModule, - FormsModule, - MatFormFieldModule, - MatInputModule, - MonacoEditorModule, - ], - template: ` @if(configuration().textType === 'text') { + selector: 'app-string-field', + imports: [ + FormsModule, + MatFormFieldModule, + MatInputModule, + MonacoEditorModule, + ], + template: ` @if(configuration().textType === 'text') { {{ label() }} }`, - styleUrl: './string-field.component.css', - changeDetection: ChangeDetectionStrategy.OnPush + styleUrl: './string-field.component.css', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class StringFieldComponent { label = input(); diff --git a/src/app/file-tree/file-tree.component.ts b/src/app/file-tree/file-tree.component.ts index 8b424bb..c4a274d 100644 --- a/src/app/file-tree/file-tree.component.ts +++ b/src/app/file-tree/file-tree.component.ts @@ -1,5 +1,4 @@ import { FlatTreeControl } from '@angular/cdk/tree'; -import { CommonModule } from '@angular/common'; import { Component, ElementRef, @@ -40,7 +39,7 @@ const collator = new Intl.Collator(undefined, { numeric: true }); @Component({ selector: 'app-file-tree', - imports: [CommonModule, MatButtonModule, MatIconModule, MatTreeModule], + imports: [MatButtonModule, MatIconModule, MatTreeModule], templateUrl: './file-tree.component.html', styleUrl: './file-tree.component.scss', }) diff --git a/src/app/model/proto-message.model.ts b/src/app/model/proto-message.model.ts index 6e2a26f..58972f9 100644 --- a/src/app/model/proto-message.model.ts +++ b/src/app/model/proto-message.model.ts @@ -38,8 +38,13 @@ export interface ObjectMessage extends MessageConfiguration { export interface RawMessage extends MessageConfiguration {} +export interface EnumMessageOption { + protoName: string; + friendlyName?: string; +} + export interface EnumMessage extends MessageConfiguration { - options: string[]; + options: EnumMessageOption[]; } export interface MessageConfiguration { @@ -90,11 +95,12 @@ export const RawMessage = (): RawMessage => ({ type: MessageTypeEnum.Raw }); export const EnumMessage = (options: string[]) => ({ type: MessageTypeEnum.Enum, - options, + options: options.map((option) => ({ protoName: option })), }); export interface ProtoMessageField { name: string; + friendlyName?: string; configuration: T; } @@ -119,7 +125,9 @@ export const UnknownProto = ( ): ProtoMessage => ({ name, fullName, - values: [{ name: 'Raw JSON', configuration: RawMessage() }], + values: [ + { name: 'Raw JSON', friendlyName: 'Raw JSON', configuration: RawMessage() }, + ], }); export const EDITABLE_MESSAGE_TYPES = [ diff --git a/src/app/proto-definition-selector/definition-editor/definition-editor-field/definition-editor-field.component.ts b/src/app/proto-definition-selector/definition-editor/definition-editor-field/definition-editor-field.component.ts index f1b7fba..f823f9d 100644 --- a/src/app/proto-definition-selector/definition-editor/definition-editor-field/definition-editor-field.component.ts +++ b/src/app/proto-definition-selector/definition-editor/definition-editor-field/definition-editor-field.component.ts @@ -1,13 +1,12 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, input } from '@angular/core'; import { + EnumMessage, ListMessage, MapMessage, MessageConfiguration, MessageTypeEnum, NumericMessage, ObjectMessage, - ProtoMessageField, StringMessage, } from '../../../model/proto-message.model'; 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 { ObjectEditorFieldComponent } from '../object-editor-field/object-editor-field.component'; import { StringEditorFieldComponent } from '../string-editor-field/string-editor-field.component'; +import { EnumEditorFieldComponent } from '../enum-editor-field/enum-editor-field.component'; @Component({ selector: 'app-definition-editor-field', imports: [ - CommonModule, FormsModule, ListEditorFieldComponent, MapEditorFieldComponent, @@ -31,6 +30,7 @@ import { StringEditorFieldComponent } from '../string-editor-field/string-editor MatSelectModule, ObjectEditorFieldComponent, StringEditorFieldComponent, + EnumEditorFieldComponent, ], template: ` @switch (fieldConfiguration().type) { @case(MessageTypeEnum.String) { @@ -48,9 +48,11 @@ import { StringEditorFieldComponent } from '../string-editor-field/string-editor [(ngModel)]="configuration.min" [max]="configuration.max ?? null" /> - Min should not be greater than {{ configuration.max }} + } Max @@ -61,9 +63,9 @@ import { StringEditorFieldComponent } from '../string-editor-field/string-editor [(ngModel)]="configuration.max" [min]="configuration.min ?? null" /> - Max should not be less than {{ configuration.min }} + @if(max.hasError('min')) { + Max should not be less than {{ configuration.min }} + } } @case (MessageTypeEnum.List) { + } @case(MessageTypeEnum.Enum) { + } }`, styleUrl: './definition-editor-field.component.css', changeDetection: ChangeDetectionStrategy.OnPush, @@ -104,5 +110,9 @@ export class DefinitionEditorFieldComponent { return configuration as ObjectMessage; } + protected enumConfiguration(configuration: MessageConfiguration) { + return configuration as EnumMessage; + } + protected readonly MessageTypeEnum = MessageTypeEnum; } diff --git a/src/app/proto-definition-selector/definition-editor/definition-editor.component.scss b/src/app/proto-definition-selector/definition-editor/definition-editor.component.scss index e69de29..9ee20ad 100644 --- a/src/app/proto-definition-selector/definition-editor/definition-editor.component.scss +++ b/src/app/proto-definition-selector/definition-editor/definition-editor.component.scss @@ -0,0 +1,3 @@ +mat-form-field { + display: block; +} diff --git a/src/app/proto-definition-selector/definition-editor/definition-editor.component.ts b/src/app/proto-definition-selector/definition-editor/definition-editor.component.ts index ac60ea5..485b74a 100644 --- a/src/app/proto-definition-selector/definition-editor/definition-editor.component.ts +++ b/src/app/proto-definition-selector/definition-editor/definition-editor.component.ts @@ -1,9 +1,7 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; import { - EDITABLE_MESSAGE_TYPES, ListMessage, MessageConfiguration, MessageTypeEnum, @@ -11,13 +9,18 @@ import { ProtoMessage, } from '../../model/proto-message.model'; 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({ selector: 'app-definition-editor', imports: [ - CommonModule, + FormsModule, MatButtonModule, MatDialogModule, + MatFormFieldModule, + MatInputModule, DefinitionEditorFieldComponent, ], template: ` @@ -25,6 +28,14 @@ import { DefinitionEditorFieldComponent } from './definition-editor-field/defini @for (field of editableMessages; track $index) {

{{ field.name }}

+ + Friendly Name + + @@ -40,26 +51,5 @@ import { DefinitionEditorFieldComponent } from './definition-editor-field/defini export class DefinitionEditorComponent { protected protoMessage = inject(MAT_DIALOG_DATA); - protected editableMessages = this.protoMessage.values.filter((message) => - 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); - } + protected editableMessages = this.protoMessage.values; } diff --git a/src/app/proto-definition-selector/definition-editor/enum-editor-field/enum-editor-field.component.css b/src/app/proto-definition-selector/definition-editor/enum-editor-field/enum-editor-field.component.css new file mode 100644 index 0000000..9ee20ad --- /dev/null +++ b/src/app/proto-definition-selector/definition-editor/enum-editor-field/enum-editor-field.component.css @@ -0,0 +1,3 @@ +mat-form-field { + display: block; +} diff --git a/src/app/proto-definition-selector/definition-editor/enum-editor-field/enum-editor-field.component.ts b/src/app/proto-definition-selector/definition-editor/enum-editor-field/enum-editor-field.component.ts new file mode 100644 index 0000000..1ba2218 --- /dev/null +++ b/src/app/proto-definition-selector/definition-editor/enum-editor-field/enum-editor-field.component.ts @@ -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) { + + {{ option.protoName }} + + + } + `, + styleUrl: './enum-editor-field.component.css', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class EnumEditorFieldComponent { + configuration = input.required(); +} diff --git a/src/app/proto-definition-selector/definition-editor/list-editor-field/list-editor-field.component.ts b/src/app/proto-definition-selector/definition-editor/list-editor-field/list-editor-field.component.ts index 3298b49..9d91a67 100644 --- a/src/app/proto-definition-selector/definition-editor/list-editor-field/list-editor-field.component.ts +++ b/src/app/proto-definition-selector/definition-editor/list-editor-field/list-editor-field.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -10,7 +9,7 @@ import { ListMessage } from '../../../model/proto-message.model'; @Component({ selector: 'app-list-editor-field', - imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)], + imports: [forwardRef(() => DefinitionEditorFieldComponent)], template: ``, diff --git a/src/app/proto-definition-selector/definition-editor/map-editor-field/map-editor-field.component.ts b/src/app/proto-definition-selector/definition-editor/map-editor-field/map-editor-field.component.ts index dab526f..1634454 100644 --- a/src/app/proto-definition-selector/definition-editor/map-editor-field/map-editor-field.component.ts +++ b/src/app/proto-definition-selector/definition-editor/map-editor-field/map-editor-field.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, @@ -14,7 +13,7 @@ import { @Component({ selector: 'app-map-editor-field', - imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)], + imports: [forwardRef(() => DefinitionEditorFieldComponent)], template: `

Key Configuration

DefinitionEditorFieldComponent)], + imports: [ + FormsModule, + MatFormFieldModule, + MatInputModule, + forwardRef(() => DefinitionEditorFieldComponent), + ], template: ` @for (field of editableFields(); track $index) {

{{ field.name }}

+ + Friendly Name + + } `, + styles: ` + mat-form-field { + display: block; + } + `, changeDetection: ChangeDetectionStrategy.OnPush, }) export class ObjectEditorFieldComponent { field = input.required(); - protected editableFields = computed(() => - this.field().messageDefinition.values.filter((field) => - EDITABLE_MESSAGE_TYPES.includes(field.configuration.type) - ) + protected editableFields = computed( + () => this.field().messageDefinition.values ); } diff --git a/src/app/proto-definition-selector/definition-editor/string-editor-field/string-editor-field.component.ts b/src/app/proto-definition-selector/definition-editor/string-editor-field/string-editor-field.component.ts index b3b18eb..f5f8b8f 100644 --- a/src/app/proto-definition-selector/definition-editor/string-editor-field/string-editor-field.component.ts +++ b/src/app/proto-definition-selector/definition-editor/string-editor-field/string-editor-field.component.ts @@ -1,4 +1,3 @@ -import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, input } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -8,14 +7,9 @@ import { MatInputModule } from '@angular/material/input'; @Component({ selector: 'app-string-editor-field', - imports: [ - CommonModule, - FormsModule, - MatFormFieldModule, - MatInputModule, - MatSelectModule, - ], - template: ` + imports: [FormsModule, MatFormFieldModule, MatInputModule, MatSelectModule], + template: ` + Max Length @@ -25,7 +19,8 @@ import { MatInputModule } from '@angular/material/input'; Text SQL - `, + + `, styleUrl: './string-editor-field.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) diff --git a/src/app/proto-definition-selector/proto-definition-selector.component.ts b/src/app/proto-definition-selector/proto-definition-selector.component.ts index b4666bd..37a7efd 100644 --- a/src/app/proto-definition-selector/proto-definition-selector.component.ts +++ b/src/app/proto-definition-selector/proto-definition-selector.component.ts @@ -1,16 +1,26 @@ -import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, HostListener, computed, output, signal, viewChild, inject } from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + HostBinding, + HostListener, + computed, + inject, + output, + signal, + viewChild, +} from '@angular/core'; 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 { 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 { ProtoDefinitionService } from './proto-definition.service'; declare const __TAURI__: any; @@ -18,13 +28,7 @@ const collator = new Intl.Collator(undefined, { numeric: true }); @Component({ selector: 'app-proto-definition-selector', - imports: [ - CommonModule, - MatButtonModule, - MatIconModule, - MatListModule, - MatTreeModule, - ], + imports: [MatButtonModule, MatIconModule, MatListModule, MatTreeModule], template: `

Protobuf Definitions

-
{{ item.name }}
+
{{ item.name }}
}