@for (item of selectedMessage().values; track $index) {
diff --git a/src/app/editor/editor.component.scss b/src/app/editor/editor.component.scss
index e69de29..83fd8be 100644
--- a/src/app/editor/editor.component.scss
+++ b/src/app/editor/editor.component.scss
@@ -0,0 +1,3 @@
+:host {
+ padding: var(--mat-sidenav-container-shape);
+}
diff --git a/src/app/editor/editor.component.ts b/src/app/editor/editor.component.ts
index 1dcc59e..f3a9b6b 100644
--- a/src/app/editor/editor.component.ts
+++ b/src/app/editor/editor.component.ts
@@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
import {
Component,
ElementRef,
+ computed,
effect,
input,
signal,
@@ -22,8 +23,12 @@ export class EditorComponent {
// TODO: This needs to be reworked so we have a local property and implement some kind of auto-save
fileContents = input
();
selectedMessage = input.required();
- // TODO: This needs to start with the parsed file contents, and get updated when the code value changes
- protected values = signal([]);
+
+ protected values = computed(() => {
+ const message = this.selectedMessage();
+ return message.values.map((value) => null);
+ });
+
private code = viewChild>('code');
constructor() {
diff --git a/src/app/file-tree/file-tree.component.html b/src/app/file-tree/file-tree.component.html
index 99097b9..07c8ec5 100644
--- a/src/app/file-tree/file-tree.component.html
+++ b/src/app/file-tree/file-tree.component.html
@@ -1,4 +1,11 @@
-{{ workspaceName() }}
+@if(workspaceName()) {workspaceName()} @else { No Worspace Selected}
+@if(!selectedDirectory()) {
+
+
+
+}@else {
+}
diff --git a/src/app/file-tree/file-tree.component.ts b/src/app/file-tree/file-tree.component.ts
index a3d7014..a821863 100644
--- a/src/app/file-tree/file-tree.component.ts
+++ b/src/app/file-tree/file-tree.component.ts
@@ -1,6 +1,13 @@
import { FlatTreeControl } from '@angular/cdk/tree';
import { CommonModule } from '@angular/common';
-import { Component, computed, input, output } from '@angular/core';
+import {
+ Component,
+ OnDestroy,
+ OnInit,
+ computed,
+ output,
+ signal,
+} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import {
@@ -8,6 +15,10 @@ import {
MatTreeFlattener,
MatTreeModule,
} from '@angular/material/tree';
+import { message, open } from '@tauri-apps/api/dialog';
+import { UnlistenFn, listen } from '@tauri-apps/api/event';
+import { FileEntry, readDir } from '@tauri-apps/api/fs';
+import { OpenFolderMessage } from '../messages/openfolder.message';
export interface FileOrFolder {
isDirectory: boolean;
@@ -29,12 +40,10 @@ interface FileNode {
templateUrl: './file-tree.component.html',
styleUrl: './file-tree.component.scss',
})
-export class FileTreeComponent {
- workspaceName = input();
- files = input([]);
-
+export class FileTreeComponent implements OnInit, OnDestroy {
fileSelected = output();
+ // File tree
protected hasChild = (_: number, node: FileNode) => node.expandable;
private _transformer = (node: FileOrFolder, level: number) => ({
@@ -64,4 +73,71 @@ export class FileTreeComponent {
dataSource.data = this.files();
return dataSource;
});
+
+ // Folder selection
+ protected selectedDirectory = signal(null);
+ protected files = signal([]);
+ protected workspaceName = computed(() => {
+ const directory = this.selectedDirectory();
+ if (directory) {
+ const directorySplit = directory.split('/');
+ return directorySplit[directorySplit.length - 1];
+ }
+ return null;
+ });
+
+ private unlisten?: UnlistenFn;
+
+ async ngOnInit() {
+ this.unlisten = await listen(
+ 'openfolder',
+ async (event: OpenFolderMessage) => {
+ await this.selectDirectory();
+ }
+ );
+ }
+
+ async ngOnDestroy() {
+ if (this.unlisten) {
+ this.unlisten();
+ }
+ }
+
+ async selectDirectory() {
+ const selectedDirectory = await open({
+ directory: true,
+ multiple: false,
+ });
+ if (Array.isArray(selectedDirectory)) {
+ message('Only a single folder can be selected at a time');
+ return;
+ } else {
+ this.selectedDirectory.set(selectedDirectory);
+ }
+ if (selectedDirectory) {
+ const entries = await readDir(selectedDirectory, {
+ recursive: true,
+ });
+ const splitNumbers = /(\d)+|(\D)+/;
+ this.files.set(
+ entries
+ .sort(this.sortFiles(splitNumbers))
+ .map((entry) => this.mapEntry(entry, splitNumbers))
+ );
+ }
+ }
+
+ private mapEntry(entry: FileEntry, splitNumbers: RegExp): FileOrFolder {
+ return {
+ isDirectory: entry.children != null,
+ name: entry.name || '',
+ children: entry.children
+ ?.sort(this.sortFiles(splitNumbers))
+ .map((entry) => this.mapEntry(entry, splitNumbers)),
+ path: entry.path,
+ };
+ }
+
+ private sortFiles = (splitNumbers: RegExp) => (a: FileEntry, b: FileEntry) =>
+ a.name?.localeCompare(b.name ?? '') ?? 0;
}
diff --git a/src/app/list-field/list-field.component.ts b/src/app/list-field/list-field.component.ts
index a9bb0bb..17f68e6 100644
--- a/src/app/list-field/list-field.component.ts
+++ b/src/app/list-field/list-field.component.ts
@@ -1,24 +1,29 @@
import { CommonModule } from '@angular/common';
import {
+ AfterViewInit,
ChangeDetectionStrategy,
Component,
+ OnInit,
+ forwardRef,
input,
model,
} from '@angular/core';
-import { MatButton } from '@angular/material/button';
+import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
+import { ListMessage } from '../model/proto-message.model';
import { ProtoFieldComponent } from '../proto-field/proto-field.component';
-import {
- EnumMessage,
- ListMessage,
- ProtoMessageField,
-} from '../model/proto-message.model';
@Component({
selector: 'app-list-field',
standalone: true,
- imports: [CommonModule, MatButton, MatIconModule, ProtoFieldComponent],
- template: ` @for(value of values(); track $index) {
+ imports: [
+ CommonModule,
+ MatButtonModule,
+ MatIconModule,
+ forwardRef(() => ProtoFieldComponent),
+ ],
+ template: ` {{ label() }}
+ @if(values()) { @for(value of values(); track $index) {
- }
+ } }
`,
styleUrl: './list-field.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ListFieldComponent {
+ label = input();
configuration = input.required();
values = model();
add() {
const newValues = this.values();
- newValues?.push(null);
- this.values.set(newValues);
+ if (newValues) {
+ newValues.push(null);
+ this.values.set(newValues);
+ } else {
+ this.values.set([null]);
+ }
}
remove(index: number) {
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 cc0e5da..6d9c439 100644
--- a/src/app/proto-definition-selector/proto-definition-selector.component.ts
+++ b/src/app/proto-definition-selector/proto-definition-selector.component.ts
@@ -20,6 +20,9 @@ import { ProtoDefinitionService } from '../proto-definition.service';
imports: [CommonModule, MatButtonModule, MatListModule],
template: `
Protobuf Definitions
+
@for (item of definitionFiles(); track $index) {
}
-
@if(selectedProtoFile()) {
Messages in {{ selectedProtoFile()?.name }}
@@ -67,10 +67,7 @@ export class ProtoDefinitionSelectorComponent {
return this.isDragging();
}
- constructor(
- private protoDefinitionService: ProtoDefinitionService,
- private elementRef: ElementRef
- ) {}
+ constructor(private protoDefinitionService: ProtoDefinitionService) {}
protected async addDefinitionFiles() {
const files = this.protoSelector()?.nativeElement.files;
diff --git a/src/app/proto-field/proto-field.component.ts b/src/app/proto-field/proto-field.component.ts
index e3815c8..92a5121 100644
--- a/src/app/proto-field/proto-field.component.ts
+++ b/src/app/proto-field/proto-field.component.ts
@@ -17,6 +17,7 @@ import {
MessageConfiguration,
MessageTypeEnum,
} from '../model/proto-message.model';
+import { MatInputModule } from '@angular/material/input';
@Component({
selector: 'app-proto-field',
@@ -28,22 +29,36 @@ import {
MatCheckboxModule,
MatFormFieldModule,
MatSelectModule,
+ MatInputModule,
],
template: `@switch (configuration().type) { @case (MessageTypeEnum.String) {
-
+
+ {{ label() }}
+
+
} @case (MessageTypeEnum.Numeric) {
-
+
+ {{ label() }}
+
+
} @case (MessageTypeEnum.Boolean) {
-
+
+ {{ label() }}
+
} @case(MessageTypeEnum.Enum) {
-
- @for(option of enumConfiguration()!.options; track
- enumConfiguration()!.options) {
-
- }
-
+
+ {{ label() }}
+
+ @for(option of enumConfiguration()!.options; track
+ enumConfiguration()!.options) {
+ None
+ {{ option }}
+ }
+
+
} @case (MessageTypeEnum.List) {
@@ -53,6 +68,7 @@ import {
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProtoFieldComponent {
+ label = input();
configuration = input.required();
value = model();
diff --git a/src/styles.scss b/src/styles.scss
index 82ae672..7da354a 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -41,4 +41,6 @@ body {
--mat-tree-node-min-height: 24px;
--mat-tree-node-text-size: 14px;
--mdc-icon-button-state-layer-size: 24px;
+ --mat-icon-button-touch-target-display: none;
+ --mdc-list-list-item-one-line-container-height: 24px;
}