Compare commits

..

2 Commits

Author SHA1 Message Date
e1747ce20a Update angular material to v19, run inject migration 2025-02-11 11:10:35 +10:30
5a4541435f Update angular core and cli to v19 2025-02-11 11:02:53 +10:30
19 changed files with 103 additions and 126 deletions

BIN
bun.lockb

Binary file not shown.

View File

@@ -11,18 +11,18 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular-devkit/build-angular": "^18.1.1", "@angular-devkit/build-angular": "^19.1.6",
"@angular/animations": "^18.1.1", "@angular/animations": "^19.1.5",
"@angular/cdk": "^18.1.1", "@angular/cdk": "^19.1.3",
"@angular/common": "^18.1.1", "@angular/common": "^19.1.5",
"@angular/compiler": "^18.1.1", "@angular/compiler": "^19.1.5",
"@angular/core": "^18.1.1", "@angular/core": "^19.1.5",
"@angular/forms": "^18.1.1", "@angular/forms": "^19.1.5",
"@angular/material": "^18.1.1", "@angular/material": "^19.1.3",
"@angular/platform-browser": "^18.1.1", "@angular/platform-browser": "^19.1.5",
"@angular/platform-browser-dynamic": "^18.1.1", "@angular/platform-browser-dynamic": "^19.1.5",
"@angular/router": "^18.1.1", "@angular/router": "^19.1.5",
"@angular/service-worker": "^18.1.1", "@angular/service-worker": "^19.1.5",
"@tauri-apps/api": "^1.6.0", "@tauri-apps/api": "^1.6.0",
"highlight.js": "^11.10.0", "highlight.js": "^11.10.0",
"monaco-editor": "^0.50.0", "monaco-editor": "^0.50.0",
@@ -30,12 +30,12 @@
"protobufjs": "^7.3.2", "protobufjs": "^7.3.2",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"tslib": "^2.6.3", "tslib": "^2.6.3",
"zone.js": "^0.14.8" "zone.js": "^0.15.0"
}, },
"devDependencies": { "devDependencies": {
"@angular/build": "^18.1.1", "@angular/build": "^19.1.6",
"@angular/cli": "^18.1.1", "@angular/cli": "^19.1.6",
"@angular/compiler-cli": "^18.1.1", "@angular/compiler-cli": "^19.1.5",
"@tauri-apps/cli": "^1.6.0", "@tauri-apps/cli": "^1.6.0",
"@types/jasmine": "^5.1.4", "@types/jasmine": "^5.1.4",
"@types/protobufjs": "^6.0.0", "@types/protobufjs": "^6.0.0",

View File

@@ -1,13 +1,12 @@
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout'; import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { Component, computed, signal } 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';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatSidenavModule } from '@angular/material/sidenav'; import { MatSidenavModule } from '@angular/material/sidenav';
import { MatToolbarModule } from '@angular/material/toolbar'; import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTreeModule } from '@angular/material/tree'; import { MatTreeModule } from '@angular/material/tree';
import { RouterOutlet } from '@angular/router';
import { EditorComponent } from './editor/editor.component'; import { EditorComponent } from './editor/editor.component';
import { import {
FileOrFolder, FileOrFolder,
@@ -15,11 +14,11 @@ import {
} from './file-tree/file-tree.component'; } from './file-tree/file-tree.component';
import { ProtoMessage } from './model/proto-message.model'; import { ProtoMessage } from './model/proto-message.model';
import { ProtoDefinitionSelectorComponent } from './proto-definition-selector/proto-definition-selector.component'; import { ProtoDefinitionSelectorComponent } from './proto-definition-selector/proto-definition-selector.component';
const mobileBreakpoints = [Breakpoints.Handset, Breakpoints.TabletPortrait]; const mobileBreakpoints = [Breakpoints.Handset, Breakpoints.TabletPortrait];
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
standalone: true,
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrl: './app.component.scss', styleUrl: './app.component.scss',
imports: [ imports: [
@@ -32,10 +31,11 @@ const mobileBreakpoints = [Breakpoints.Handset, Breakpoints.TabletPortrait];
MatToolbarModule, MatToolbarModule,
MatTreeModule, MatTreeModule,
ProtoDefinitionSelectorComponent, ProtoDefinitionSelectorComponent,
RouterOutlet,
], ],
}) })
export class AppComponent { export class AppComponent {
private breakpointObserver = inject(BreakpointObserver);
protected selectedFile = signal<FileOrFolder | undefined>(undefined); protected selectedFile = signal<FileOrFolder | undefined>(undefined);
protected selectedMessage = signal<ProtoMessage | undefined>(undefined); protected selectedMessage = signal<ProtoMessage | undefined>(undefined);
protected rightSideOpen = signal(true); protected rightSideOpen = signal(true);
@@ -46,7 +46,9 @@ export class AppComponent {
this.breakpointObserver.isMatched(mobileBreakpoints) this.breakpointObserver.isMatched(mobileBreakpoints)
); );
constructor(private breakpointObserver: BreakpointObserver) { constructor() {
const breakpointObserver = this.breakpointObserver;
breakpointObserver breakpointObserver
.observe(mobileBreakpoints) .observe(mobileBreakpoints)
.pipe(takeUntilDestroyed()) .pipe(takeUntilDestroyed())

View File

@@ -1,8 +1,9 @@
import { import {
APP_INITIALIZER,
ApplicationConfig, ApplicationConfig,
isDevMode, isDevMode,
provideExperimentalZonelessChangeDetection, provideExperimentalZonelessChangeDetection,
provideAppInitializer,
inject,
} from '@angular/core'; } from '@angular/core';
import { provideRouter } from '@angular/router'; import { provideRouter } from '@angular/router';
@@ -22,24 +23,18 @@ export const appConfig: ApplicationConfig = {
provideExperimentalZonelessChangeDetection(), provideExperimentalZonelessChangeDetection(),
provideRouter(routes), provideRouter(routes),
provideAnimationsAsync(), provideAnimationsAsync(),
{ provideAppInitializer(() => {
provide: APP_INITIALIZER, hljs.registerLanguage('json', json);
useValue: () => { }),
hljs.registerLanguage('json', json); provideAppInitializer(() => {
}, const initializerFn = ((iconRegistry: MatIconRegistry) => () => {
multi: true,
},
{
provide: APP_INITIALIZER,
useFactory: (iconRegistry: MatIconRegistry) => () => {
iconRegistry.registerFontClassAlias( iconRegistry.registerFontClassAlias(
'material-symbols-rounded', 'material-symbols-rounded',
'material-symbols-rounded' 'material-symbols-rounded'
); );
}, })(inject(MatIconRegistry));
deps: [MatIconRegistry], return initializerFn();
multi: true, }),
},
{ {
provide: MAT_ICON_DEFAULT_OPTIONS, provide: MAT_ICON_DEFAULT_OPTIONS,
useValue: { fontSet: 'material-symbols-rounded' }, useValue: { fontSet: 'material-symbols-rounded' },

View File

@@ -8,6 +8,7 @@ import {
input, input,
signal, signal,
viewChild, viewChild,
inject,
} from '@angular/core'; } from '@angular/core';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
@@ -29,7 +30,6 @@ type PreviewType = 'raw' | 'edit' | 'diff';
@Component({ @Component({
selector: 'app-editor', selector: 'app-editor',
standalone: true,
imports: [ imports: [
CommonModule, CommonModule,
ProtoFieldComponent, ProtoFieldComponent,
@@ -43,6 +43,8 @@ type PreviewType = 'raw' | 'edit' | 'diff';
styleUrl: './editor.component.scss', styleUrl: './editor.component.scss',
}) })
export class EditorComponent { export class EditorComponent {
private snackBar = inject(MatSnackBar);
selectedFile = input<FileOrFolder>(); selectedFile = input<FileOrFolder>();
selectedMessage = input.required<ProtoMessage>(); selectedMessage = input.required<ProtoMessage>();
indentSize = input<number>(2); indentSize = input<number>(2);
@@ -80,7 +82,9 @@ export class EditorComponent {
private code = viewChild<ElementRef<HTMLElement>>('code'); private code = viewChild<ElementRef<HTMLElement>>('code');
constructor(sanitizer: DomSanitizer, private snackBar: MatSnackBar) { constructor() {
const sanitizer = inject(DomSanitizer);
effect(() => { effect(() => {
const element = this.code()?.nativeElement; const element = this.code()?.nativeElement;
if (element) { if (element) {

View File

@@ -14,15 +14,14 @@ import { ListMessage } from '../../model/proto-message.model';
import { ProtoFieldComponent } from '../proto-field/proto-field.component'; import { ProtoFieldComponent } from '../proto-field/proto-field.component';
@Component({ @Component({
selector: 'app-list-field', selector: 'app-list-field',
standalone: true, imports: [
imports: [ CommonModule,
CommonModule, MatButtonModule,
MatButtonModule, MatIconModule,
MatIconModule, forwardRef(() => ProtoFieldComponent),
forwardRef(() => ProtoFieldComponent), ],
], template: `<h3>{{ label() }}</h3>
template: `<h3>{{ label() }}</h3>
@if(values()) { @for(value of values(); track $index) { @if(values()) { @for(value of values(); track $index) {
<div class="row-wrapper"> <div class="row-wrapper">
<app-proto-field <app-proto-field
@@ -38,8 +37,8 @@ import { ProtoFieldComponent } from '../proto-field/proto-field.component';
<button mat-icon-button class="add-button" (click)="add()"> <button mat-icon-button class="add-button" (click)="add()">
<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

@@ -16,15 +16,14 @@ import { ProtoFieldComponent } from '../proto-field/proto-field.component';
const keyIsEmpty = (key: string | number) => key == null || key === ''; const keyIsEmpty = (key: string | number) => key == null || key === '';
@Component({ @Component({
selector: 'app-map-field', selector: 'app-map-field',
standalone: true, imports: [
imports: [ CommonModule,
CommonModule, forwardRef(() => ProtoFieldComponent),
forwardRef(() => ProtoFieldComponent), MatIconModule,
MatIconModule, MatButtonModule,
MatButtonModule, ],
], template: `<h3>{{ label() }}</h3>
template: `<h3>{{ label() }}</h3>
@if(valuePairs()) { @for(value of valuePairs(); track $index) { @if(valuePairs()) { @for(value of valuePairs(); track $index) {
<div class="row-wrapper"> <div class="row-wrapper">
<app-proto-field <app-proto-field
@@ -45,8 +44,8 @@ const keyIsEmpty = (key: string | number) => key == null || key === '';
<button mat-icon-button class="add-button" (click)="add()"> <button mat-icon-button class="add-button" (click)="add()">
<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>();

View File

@@ -11,10 +11,9 @@ import { ObjectMessage } from '../../model/proto-message.model';
import { ProtoFieldComponent } from '../proto-field/proto-field.component'; import { ProtoFieldComponent } from '../proto-field/proto-field.component';
@Component({ @Component({
selector: 'app-object-field', selector: 'app-object-field',
standalone: true, imports: [CommonModule, forwardRef(() => ProtoFieldComponent)],
imports: [CommonModule, forwardRef(() => ProtoFieldComponent)], template: `<h3>
template: `<h3>
{{ label() }} ({{ configuration().messageDefinition.name }}) {{ label() }} ({{ configuration().messageDefinition.name }})
</h3> </h3>
<div> <div>
@@ -27,8 +26,8 @@ import { ProtoFieldComponent } from '../proto-field/proto-field.component';
></app-proto-field> ></app-proto-field>
} }
</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

@@ -27,21 +27,20 @@ import { ObjectFieldComponent } from '../object-field/object-field.component';
import { StringFieldComponent } from '../string-field/string-field.component'; import { StringFieldComponent } from '../string-field/string-field.component';
@Component({ @Component({
selector: 'app-proto-field', selector: 'app-proto-field',
standalone: true, imports: [
imports: [ CommonModule,
CommonModule, FormsModule,
FormsModule, ListFieldComponent,
ListFieldComponent, MapFieldComponent,
MapFieldComponent, MatCheckboxModule,
MatCheckboxModule, MatFormFieldModule,
MatFormFieldModule, MatSelectModule,
MatSelectModule, MatInputModule,
MatInputModule, ObjectFieldComponent,
ObjectFieldComponent, StringFieldComponent,
StringFieldComponent, ],
], template: `@switch (configuration().type) { @case (MessageTypeEnum.String) {
template: `@switch (configuration().type) { @case (MessageTypeEnum.String) {
<app-string-field <app-string-field
[label]="label()" [label]="label()"
[configuration]="stringConfiguration()" [configuration]="stringConfiguration()"
@@ -101,8 +100,8 @@ import { StringFieldComponent } from '../string-field/string-field.component';
[configuration]="objectConfiguration()" [configuration]="objectConfiguration()"
></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

@@ -12,16 +12,15 @@ import { MatInputModule } from '@angular/material/input';
import { MonacoEditorModule } from 'ngx-monaco-editor-v2'; import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
@Component({ @Component({
selector: 'app-string-field', selector: 'app-string-field',
standalone: true, imports: [
imports: [ CommonModule,
CommonModule, FormsModule,
FormsModule, MatFormFieldModule,
MatFormFieldModule, MatInputModule,
MatInputModule, MonacoEditorModule,
MonacoEditorModule, ],
], template: ` @if(configuration().textType === 'text') {
template: ` @if(configuration().textType === 'text') {
<mat-form-field> <mat-form-field>
<mat-label>{{ label() }}</mat-label> <mat-label>{{ label() }}</mat-label>
<input <input
@@ -44,8 +43,8 @@ import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
[options]="editorOptions" [options]="editorOptions"
></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

@@ -40,7 +40,6 @@ const collator = new Intl.Collator(undefined, { numeric: true });
@Component({ @Component({
selector: 'app-file-tree', selector: 'app-file-tree',
standalone: true,
imports: [CommonModule, MatButtonModule, MatIconModule, MatTreeModule], imports: [CommonModule, 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

@@ -21,7 +21,6 @@ import { StringEditorFieldComponent } from '../string-editor-field/string-editor
@Component({ @Component({
selector: 'app-definition-editor-field', selector: 'app-definition-editor-field',
standalone: true,
imports: [ imports: [
CommonModule, CommonModule,
FormsModule, FormsModule,

View File

@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common'; 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 {
@@ -14,7 +14,6 @@ import { DefinitionEditorFieldComponent } from './definition-editor-field/defini
@Component({ @Component({
selector: 'app-definition-editor', selector: 'app-definition-editor',
standalone: true,
imports: [ imports: [
CommonModule, CommonModule,
MatButtonModule, MatButtonModule,
@@ -39,6 +38,8 @@ import { DefinitionEditorFieldComponent } from './definition-editor-field/defini
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class DefinitionEditorComponent { export class DefinitionEditorComponent {
protected protoMessage = inject<ProtoMessage>(MAT_DIALOG_DATA);
protected editableMessages = this.protoMessage.values.filter((message) => protected editableMessages = this.protoMessage.values.filter((message) =>
this.filterMessageConfiguration(message.configuration) this.filterMessageConfiguration(message.configuration)
); );
@@ -61,6 +62,4 @@ export class DefinitionEditorComponent {
// Note: Map can always be configured, as key needs to be a string or numeric type // Note: Map can always be configured, as key needs to be a string or numeric type
return EDITABLE_MESSAGE_TYPES.includes(configuration.type); return EDITABLE_MESSAGE_TYPES.includes(configuration.type);
} }
constructor(@Inject(MAT_DIALOG_DATA) protected protoMessage: ProtoMessage) {}
} }

View File

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

View File

@@ -14,7 +14,6 @@ import {
@Component({ @Component({
selector: 'app-map-editor-field', selector: 'app-map-editor-field',
standalone: true,
imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)], imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)],
template: ` template: `
<h4>Key Configuration</h4> <h4>Key Configuration</h4>

View File

@@ -14,7 +14,6 @@ import { DefinitionEditorFieldComponent } from '../definition-editor-field/defin
@Component({ @Component({
selector: 'app-object-editor-field', selector: 'app-object-editor-field',
standalone: true,
imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)], imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)],
template: ` template: `
@for (field of editableFields(); track $index) { @for (field of editableFields(); track $index) {

View File

@@ -8,7 +8,6 @@ import { MatInputModule } from '@angular/material/input';
@Component({ @Component({
selector: 'app-string-editor-field', selector: 'app-string-editor-field',
standalone: true,
imports: [ imports: [
CommonModule, CommonModule,
FormsModule, FormsModule,

View File

@@ -1,16 +1,5 @@
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, HostBinding, HostListener, computed, output, signal, viewChild, inject } from '@angular/core';
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
HostBinding,
HostListener,
computed,
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 { MatListModule, MatSelectionList } from '@angular/material/list';
import { ProtoMessage } from '../model/proto-message.model'; import { ProtoMessage } from '../model/proto-message.model';
@@ -29,7 +18,6 @@ const collator = new Intl.Collator(undefined, { numeric: true });
@Component({ @Component({
selector: 'app-proto-definition-selector', selector: 'app-proto-definition-selector',
standalone: true,
imports: [ imports: [
CommonModule, CommonModule,
MatButtonModule, MatButtonModule,
@@ -102,6 +90,10 @@ const collator = new Intl.Collator(undefined, { numeric: true });
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class ProtoDefinitionSelectorComponent { export class ProtoDefinitionSelectorComponent {
private protoDefinitionService = inject(ProtoDefinitionService);
private snackBar = inject(MatSnackBar);
private dialog = inject(MatDialog);
messageSelected = output<ProtoMessage>(); messageSelected = output<ProtoMessage>();
protected protoSelector = protected protoSelector =
@@ -135,12 +127,6 @@ export class ProtoDefinitionSelectorComponent {
return this.isDragging(); return this.isDragging();
} }
constructor(
private protoDefinitionService: ProtoDefinitionService,
private snackBar: MatSnackBar,
private dialog: MatDialog
) {}
protected async addDefinitionFiles() { protected async addDefinitionFiles() {
const files = this.protoSelector()?.nativeElement.files; const files = this.protoSelector()?.nativeElement.files;
if (files) { if (files) {

View File

@@ -1,7 +1,8 @@
@use "@angular/material" as mat; @use "@angular/material" as mat;
@use "./theme.scss"; @use "./theme.scss";
@include mat.core(); @include mat.elevation-classes();
@include mat.app-background();
@mixin custom-colours($theme) { @mixin custom-colours($theme) {
.mat-toolbar { .mat-toolbar {
@@ -20,7 +21,8 @@
} }
html { html {
@include mat.core-theme(theme.$rose-theme); @include mat.elevation-classes();
@include mat.app-background();
@include mat.toolbar-theme(theme.$rose-theme); @include mat.toolbar-theme(theme.$rose-theme);
@include mat.button-theme(theme.$rose-theme); @include mat.button-theme(theme.$rose-theme);
@include mat.tree-theme(theme.$rose-theme); @include mat.tree-theme(theme.$rose-theme);