diff --git a/src/app/editor/proto-field/proto-field.component.ts b/src/app/editor/proto-field/proto-field.component.ts
index 2ec8ca4..5f1bab2 100644
--- a/src/app/editor/proto-field/proto-field.component.ts
+++ b/src/app/editor/proto-field/proto-field.component.ts
@@ -17,11 +17,14 @@ import {
MapMessage,
MessageConfiguration,
MessageTypeEnum,
+ NumericMessage,
ObjectMessage,
+ StringMessage,
} from '../../model/proto-message.model';
import { ListFieldComponent } from '../list-field/list-field.component';
import { MapFieldComponent } from '../map-field/map-field.component';
import { ObjectFieldComponent } from '../object-field/object-field.component';
+import { StringFieldComponent } from '../string-field/string-field.component';
@Component({
selector: 'app-proto-field',
@@ -36,16 +39,33 @@ import { ObjectFieldComponent } from '../object-field/object-field.component';
MatSelectModule,
MatInputModule,
ObjectFieldComponent,
+ StringFieldComponent,
],
template: `@switch (configuration().type) { @case (MessageTypeEnum.String) {
-
- {{ label() }}
-
-
+
} @case (MessageTypeEnum.Numeric) {
{{ label() }}
-
+
+ Number should not be less than
+ {{ numericConfiguration().min }}
+ Number should not greater than
+ {{ numericConfiguration().max }}
} @case (MessageTypeEnum.Boolean) {
@@ -89,6 +109,14 @@ export class ProtoFieldComponent {
configuration = input.required();
value = model();
+ protected stringConfiguration = computed(
+ () => this.configuration() as StringMessage
+ );
+
+ protected numericConfiguration = computed(
+ () => this.configuration() as NumericMessage
+ );
+
protected enumConfiguration = computed(
() => this.configuration() as EnumMessage
);
diff --git a/src/app/editor/string-field/string-field.component.css b/src/app/editor/string-field/string-field.component.css
new file mode 100644
index 0000000..c7acb4b
--- /dev/null
+++ b/src/app/editor/string-field/string-field.component.css
@@ -0,0 +1,3 @@
+mat-form-field {
+ width: 100%;
+}
diff --git a/src/app/editor/string-field/string-field.component.ts b/src/app/editor/string-field/string-field.component.ts
new file mode 100644
index 0000000..eba7b12
--- /dev/null
+++ b/src/app/editor/string-field/string-field.component.ts
@@ -0,0 +1,57 @@
+import { CommonModule } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ input,
+ model,
+} from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { StringMessage } from '../../model/proto-message.model';
+import { MatInputModule } from '@angular/material/input';
+import { MonacoEditorModule } from 'ngx-monaco-editor-v2';
+
+@Component({
+ selector: 'app-string-field',
+ standalone: true,
+ imports: [
+ CommonModule,
+ FormsModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MonacoEditorModule,
+ ],
+ template: ` @if(configuration().textType === 'text') {
+
+ {{ label() }}
+
+ Text should be less than
+ {{ configuration().maxLength }} characters
+
+ } @else {
+
+ }`,
+ styleUrl: './string-field.component.css',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class StringFieldComponent {
+ label = input();
+ configuration = input.required();
+ value = model();
+
+ protected editorOptions = {
+ theme: 'vs-dark',
+ language: 'sql',
+ automaticLayout: true,
+ };
+}
diff --git a/src/app/model/proto-message.model.ts b/src/app/model/proto-message.model.ts
index ea71afd..6e2a26f 100644
--- a/src/app/model/proto-message.model.ts
+++ b/src/app/model/proto-message.model.ts
@@ -9,8 +9,11 @@ export enum MessageTypeEnum {
Enum = 'enum',
}
+export type StringMessageTextType = 'text' | 'sql';
+
export interface StringMessage extends MessageConfiguration {
maxLength?: number;
+ textType: StringMessageTextType;
}
export interface BooleanMessage extends MessageConfiguration {}
@@ -43,9 +46,13 @@ export interface MessageConfiguration {
type: MessageTypeEnum;
}
-export const StringMessage = (maxLength?: number): StringMessage => ({
+export const StringMessage = (
+ maxLength?: number,
+ textType: StringMessageTextType = 'text'
+): StringMessage => ({
type: MessageTypeEnum.String,
maxLength,
+ textType,
});
export const BooleanMessage = (): BooleanMessage => ({
@@ -114,3 +121,11 @@ export const UnknownProto = (
fullName,
values: [{ name: 'Raw JSON', configuration: RawMessage() }],
});
+
+export const EDITABLE_MESSAGE_TYPES = [
+ MessageTypeEnum.String,
+ MessageTypeEnum.Numeric,
+ MessageTypeEnum.List,
+ MessageTypeEnum.Map,
+ MessageTypeEnum.Object,
+];
diff --git a/src/app/proto-definition-selector/definition-editor/definition-editor-field/definition-editor-field.component.css b/src/app/proto-definition-selector/definition-editor/definition-editor-field/definition-editor-field.component.css
new file mode 100644
index 0000000..9ee20ad
--- /dev/null
+++ b/src/app/proto-definition-selector/definition-editor/definition-editor-field/definition-editor-field.component.css
@@ -0,0 +1,3 @@
+mat-form-field {
+ display: block;
+}
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
new file mode 100644
index 0000000..9ea50dc
--- /dev/null
+++ b/src/app/proto-definition-selector/definition-editor/definition-editor-field/definition-editor-field.component.ts
@@ -0,0 +1,109 @@
+import { CommonModule } from '@angular/common';
+import { ChangeDetectionStrategy, Component, input } from '@angular/core';
+import {
+ ListMessage,
+ MapMessage,
+ MessageConfiguration,
+ MessageTypeEnum,
+ NumericMessage,
+ ObjectMessage,
+ ProtoMessageField,
+ StringMessage,
+} from '../../../model/proto-message.model';
+import { FormsModule } from '@angular/forms';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSelectModule } from '@angular/material/select';
+import { MatInputModule } from '@angular/material/input';
+import { ListEditorFieldComponent } from '../list-editor-field/list-editor-field.component';
+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';
+
+@Component({
+ selector: 'app-definition-editor-field',
+ standalone: true,
+ imports: [
+ CommonModule,
+ FormsModule,
+ ListEditorFieldComponent,
+ MapEditorFieldComponent,
+ MatFormFieldModule,
+ MatInputModule,
+ MatSelectModule,
+ ObjectEditorFieldComponent,
+ StringEditorFieldComponent,
+ ],
+ template: ` @switch (fieldConfiguration().type) {
+ @case(MessageTypeEnum.String) {
+
+ } @case (MessageTypeEnum.Numeric) { @let configuration =
+ numericConfiguration(fieldConfiguration());
+
+ Min
+
+ Min should not be greater than {{ configuration.max }}
+
+
+ Max
+
+ Max should not be less than {{ configuration.min }}
+
+ } @case (MessageTypeEnum.List) {
+
+ } @case (MessageTypeEnum.Map) {
+
+ } @case(MessageTypeEnum.Object) {
+
+ } }`,
+ styleUrl: './definition-editor-field.component.css',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DefinitionEditorFieldComponent {
+ fieldConfiguration = input.required();
+
+ protected stringConfiguration(configuration: MessageConfiguration) {
+ return configuration as StringMessage;
+ }
+
+ protected numericConfiguration(configuration: MessageConfiguration) {
+ return configuration as NumericMessage;
+ }
+
+ protected listConfiguration(configuration: MessageConfiguration) {
+ return configuration as ListMessage;
+ }
+
+ protected mapConfiguration(configuration: MessageConfiguration) {
+ return configuration as MapMessage;
+ }
+
+ protected objectConfiguration(configuration: MessageConfiguration) {
+ return configuration as ObjectMessage;
+ }
+
+ 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
new file mode 100644
index 0000000..e69de29
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
new file mode 100644
index 0000000..c1e0987
--- /dev/null
+++ b/src/app/proto-definition-selector/definition-editor/definition-editor.component.ts
@@ -0,0 +1,66 @@
+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,
+ ObjectMessage,
+ ProtoMessage,
+} from '../../model/proto-message.model';
+import { DefinitionEditorFieldComponent } from './definition-editor-field/definition-editor-field.component';
+
+@Component({
+ selector: 'app-definition-editor',
+ standalone: true,
+ imports: [
+ CommonModule,
+ MatButtonModule,
+ MatDialogModule,
+ DefinitionEditorFieldComponent,
+ ],
+ template: `
+ {{ protoMessage.name }}
+
+ @for (field of editableMessages; track $index) {
+ {{ field.name }}
+
+ }
+
+
+
+
+ `,
+ styleUrl: './definition-editor.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DefinitionEditorComponent {
+ 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);
+ }
+
+ constructor(@Inject(MAT_DIALOG_DATA) protected protoMessage: ProtoMessage) {}
+}
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
new file mode 100644
index 0000000..78efc83
--- /dev/null
+++ b/src/app/proto-definition-selector/definition-editor/list-editor-field/list-editor-field.component.ts
@@ -0,0 +1,22 @@
+import { CommonModule } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ forwardRef,
+ input,
+} from '@angular/core';
+import { DefinitionEditorFieldComponent } from '../definition-editor-field/definition-editor-field.component';
+import { ListMessage } from '../../../model/proto-message.model';
+
+@Component({
+ selector: 'app-list-editor-field',
+ standalone: true,
+ imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)],
+ template: ``,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ListEditorFieldComponent {
+ field = input.required();
+}
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
new file mode 100644
index 0000000..ff189a1
--- /dev/null
+++ b/src/app/proto-definition-selector/definition-editor/map-editor-field/map-editor-field.component.ts
@@ -0,0 +1,39 @@
+import { CommonModule } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ forwardRef,
+ input,
+} from '@angular/core';
+import { DefinitionEditorFieldComponent } from '../definition-editor-field/definition-editor-field.component';
+import {
+ EDITABLE_MESSAGE_TYPES,
+ MapMessage,
+ MessageConfiguration,
+} from '../../../model/proto-message.model';
+
+@Component({
+ selector: 'app-map-editor-field',
+ standalone: true,
+ imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)],
+ template: `
+ Key Configuration
+
+ @if(isEditable(field().valueConfiguration)) {
+ Value Configuration
+
+ }
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class MapEditorFieldComponent {
+ field = input.required();
+
+ protected isEditable(configuration: MessageConfiguration) {
+ return EDITABLE_MESSAGE_TYPES.includes(configuration.type);
+ }
+}
diff --git a/src/app/proto-definition-selector/definition-editor/object-editor-field/object-editor-field.component.ts b/src/app/proto-definition-selector/definition-editor/object-editor-field/object-editor-field.component.ts
new file mode 100644
index 0000000..7c2129a
--- /dev/null
+++ b/src/app/proto-definition-selector/definition-editor/object-editor-field/object-editor-field.component.ts
@@ -0,0 +1,37 @@
+import { CommonModule } from '@angular/common';
+import {
+ ChangeDetectionStrategy,
+ Component,
+ computed,
+ forwardRef,
+ input,
+} from '@angular/core';
+import {
+ EDITABLE_MESSAGE_TYPES,
+ ObjectMessage,
+} from '../../../model/proto-message.model';
+import { DefinitionEditorFieldComponent } from '../definition-editor-field/definition-editor-field.component';
+
+@Component({
+ selector: 'app-object-editor-field',
+ standalone: true,
+ imports: [CommonModule, forwardRef(() => DefinitionEditorFieldComponent)],
+ template: `
+ @for (field of editableFields(); track $index) {
+ {{ field.name }}
+
+ }
+ `,
+ 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)
+ )
+ );
+}
diff --git a/src/app/proto-definition-selector/definition-editor/string-editor-field/string-editor-field.component.scss b/src/app/proto-definition-selector/definition-editor/string-editor-field/string-editor-field.component.scss
new file mode 100644
index 0000000..9ee20ad
--- /dev/null
+++ b/src/app/proto-definition-selector/definition-editor/string-editor-field/string-editor-field.component.scss
@@ -0,0 +1,3 @@
+mat-form-field {
+ display: block;
+}
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
new file mode 100644
index 0000000..79449ff
--- /dev/null
+++ b/src/app/proto-definition-selector/definition-editor/string-editor-field/string-editor-field.component.ts
@@ -0,0 +1,35 @@
+import { CommonModule } from '@angular/common';
+import { ChangeDetectionStrategy, Component, input } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatSelectModule } from '@angular/material/select';
+import { StringMessage } from '../../../model/proto-message.model';
+import { MatInputModule } from '@angular/material/input';
+
+@Component({
+ selector: 'app-string-editor-field',
+ standalone: true,
+ imports: [
+ CommonModule,
+ FormsModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MatSelectModule,
+ ],
+ template: `
+ Max Length
+
+
+
+ Field Type
+
+ Text
+ SQL
+
+ `,
+ styleUrl: './string-editor-field.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class StringEditorFieldComponent {
+ configuration = input.required();
+}
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 16b968e..4d43a16 100644
--- a/src/app/proto-definition-selector/proto-definition-selector.component.ts
+++ b/src/app/proto-definition-selector/proto-definition-selector.component.ts
@@ -1,6 +1,7 @@
import { CommonModule } from '@angular/common';
import {
ChangeDetectionStrategy,
+ ChangeDetectorRef,
Component,
ElementRef,
HostBinding,
@@ -11,20 +12,29 @@ import {
viewChild,
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
-import { MatListModule } from '@angular/material/list';
+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 { DefinitionEditorComponent } from './definition-editor/definition-editor.component';
declare const __TAURI__: any;
@Component({
selector: 'app-proto-definition-selector',
standalone: true,
- imports: [CommonModule, MatButtonModule, MatListModule, MatTreeModule],
+ imports: [
+ CommonModule,
+ MatButtonModule,
+ MatIconModule,
+ MatListModule,
+ MatTreeModule,
+ ],
template: `
Protobuf Definitions