mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Feature/save code (#1222)
* Persist dev projects and auto save on edit Co-authored-by: Drew Ansbacher <drew.ansbacher@spiredigital.com> Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
@@ -185,8 +185,6 @@
|
||||
<ion-card-header></ion-card-header>
|
||||
<ion-checkbox></ion-checkbox>
|
||||
<ion-content></ion-content>
|
||||
<ion-fab></ion-fab>
|
||||
<ion-fab-button></ion-fab-button>
|
||||
<ion-footer></ion-footer>
|
||||
<ion-grid></ion-grid>
|
||||
<ion-header></ion-header>
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button defaultHref="/developer"></ion-back-button>
|
||||
<ion-back-button
|
||||
[defaultHref]="'/developer/projects/' + projectId"
|
||||
></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Config</ion-title>
|
||||
<ion-title
|
||||
>Config
|
||||
<ion-spinner
|
||||
*ngIf="saving"
|
||||
name="crescent"
|
||||
style="transform: scale(0.55); position: absolute"
|
||||
></ion-spinner
|
||||
></ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="submit()">Preview</ion-button>
|
||||
<ion-button (click)="preview()">Preview</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ngx-monaco-editor
|
||||
(keyup)="save()"
|
||||
[options]="editorOptions"
|
||||
[(ngModel)]="code"
|
||||
></ngx-monaco-editor>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
.centered{
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
transform: scale(2);
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { ModalController } from '@ionic/angular'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { take } from 'rxjs/operators'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { debounce } from '../../../../../../shared/src/util/misc.util'
|
||||
import { GenericFormPage } from '../../../modals/generic-form/generic-form.page'
|
||||
import { ConfigSpec } from '../../../pkg-config/config-types'
|
||||
import { ErrorToastService } from '../../../services/error-toast.service'
|
||||
|
||||
@Component({
|
||||
@@ -11,21 +15,31 @@ import { ErrorToastService } from '../../../services/error-toast.service'
|
||||
styleUrls: ['dev-config.page.scss'],
|
||||
})
|
||||
export class DevConfigPage {
|
||||
projectId: string
|
||||
editorOptions = { theme: 'vs-dark', language: 'yaml' }
|
||||
code: string
|
||||
code: string = ''
|
||||
saving: boolean = false
|
||||
|
||||
constructor(
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly patchDb: PatchDbService,
|
||||
private readonly api: ApiService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.code = yaml
|
||||
.dump(SAMPLE_CODE)
|
||||
.replace(/warning:/g, '# Optional\n warning:')
|
||||
this.projectId = this.route.snapshot.paramMap.get('projectId')
|
||||
|
||||
this.patchDb
|
||||
.watch$('ui', 'dev', this.projectId, 'config')
|
||||
.pipe(take(1))
|
||||
.subscribe(config => {
|
||||
this.code = config
|
||||
})
|
||||
}
|
||||
|
||||
async submit() {
|
||||
async preview() {
|
||||
let doc: any
|
||||
try {
|
||||
doc = yaml.load(this.code)
|
||||
@@ -51,56 +65,21 @@ export class DevConfigPage {
|
||||
})
|
||||
await modal.present()
|
||||
}
|
||||
}
|
||||
|
||||
const SAMPLE_CODE: ConfigSpec = {
|
||||
'sample-string': {
|
||||
type: 'string',
|
||||
name: 'Example String Input',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
// optional
|
||||
warning: null,
|
||||
description: 'Example description for required string input.',
|
||||
default: null,
|
||||
placeholder: 'Enter string value',
|
||||
pattern: '^[a-zA-Z0-9! _]+$',
|
||||
'pattern-description': 'Must be alphanumeric (may contain underscore).',
|
||||
},
|
||||
'sample-number': {
|
||||
type: 'number',
|
||||
name: 'Example Number Input',
|
||||
nullable: false,
|
||||
range: '[5,1000000]',
|
||||
integral: true,
|
||||
// optional
|
||||
warning: 'Example warning to display when changing this number value.',
|
||||
units: 'ms',
|
||||
description: 'Example description for optional number input.',
|
||||
default: null,
|
||||
placeholder: 'Enter number value',
|
||||
},
|
||||
'sample-boolean': {
|
||||
type: 'boolean',
|
||||
name: 'Example Boolean Toggle',
|
||||
// optional
|
||||
warning: null,
|
||||
description: 'Example description for boolean toggle',
|
||||
default: true,
|
||||
},
|
||||
'sample-enum': {
|
||||
type: 'enum',
|
||||
name: 'Example Enum Select',
|
||||
values: ['red', 'blue', 'green'],
|
||||
'value-names': {
|
||||
red: 'Red',
|
||||
blue: 'Blue',
|
||||
green: 'Green',
|
||||
},
|
||||
// optional
|
||||
warning: 'Example warning to display when changing this enum value.',
|
||||
description: 'Example description for enum select',
|
||||
default: 'red',
|
||||
},
|
||||
@debounce(1000)
|
||||
async save() {
|
||||
this.saving = true
|
||||
try {
|
||||
await this.api.setDbValue({
|
||||
pointer: `/dev/${this.projectId}/config`,
|
||||
value: this.code,
|
||||
})
|
||||
} catch (e) {
|
||||
this.errToast.present({
|
||||
message: 'Auto save error: Your changes are not saved.',
|
||||
} as any)
|
||||
} finally {
|
||||
this.saving = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button defaultHref="/developer"></ion-back-button>
|
||||
<ion-back-button
|
||||
[defaultHref]="'/developer/projects/' + projectId"
|
||||
></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Instructions</ion-title>
|
||||
<ion-title
|
||||
>Instructions
|
||||
<ion-spinner
|
||||
*ngIf="saving"
|
||||
name="crescent"
|
||||
style="transform: scale(0.55); position: absolute"
|
||||
></ion-spinner
|
||||
></ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="submit()">Preview</ion-button>
|
||||
<ion-button (click)="preview()">Preview</ion-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ngx-monaco-editor
|
||||
(keyup)="save()"
|
||||
[options]="editorOptions"
|
||||
[(ngModel)]="code"
|
||||
></ngx-monaco-editor>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { ModalController } from '@ionic/angular'
|
||||
import { take } from 'rxjs/operators'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { debounce } from '../../../../../../shared/src/util/misc.util'
|
||||
import { MarkdownPage } from '../../../modals/markdown/markdown.page'
|
||||
|
||||
@Component({
|
||||
@@ -8,12 +14,31 @@ import { MarkdownPage } from '../../../modals/markdown/markdown.page'
|
||||
styleUrls: ['dev-instructions.page.scss'],
|
||||
})
|
||||
export class DevInstructionsPage {
|
||||
projectId: string
|
||||
editorOptions = { theme: 'vs-dark', language: 'markdown' }
|
||||
code: string = `# Create Instructions using Markdown! :)`
|
||||
code: string = ''
|
||||
saving: boolean = false
|
||||
|
||||
constructor(private readonly modalCtrl: ModalController) {}
|
||||
constructor(
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly patchDb: PatchDbService,
|
||||
private readonly api: ApiService,
|
||||
) {}
|
||||
|
||||
async submit() {
|
||||
ngOnInit() {
|
||||
this.projectId = this.route.snapshot.paramMap.get('projectId')
|
||||
|
||||
this.patchDb
|
||||
.watch$('ui', 'dev', this.projectId, 'instructions')
|
||||
.pipe(take(1))
|
||||
.subscribe(config => {
|
||||
this.code = config
|
||||
})
|
||||
}
|
||||
|
||||
async preview() {
|
||||
const modal = await this.modalCtrl.create({
|
||||
componentProps: {
|
||||
title: 'Instructions Sample',
|
||||
@@ -24,4 +49,21 @@ export class DevInstructionsPage {
|
||||
|
||||
await modal.present()
|
||||
}
|
||||
|
||||
@debounce(1000)
|
||||
async save() {
|
||||
this.saving = true
|
||||
try {
|
||||
await this.api.setDbValue({
|
||||
pointer: `/dev/${this.projectId}/instructions`,
|
||||
value: this.code,
|
||||
})
|
||||
} catch (e) {
|
||||
this.errToast.present({
|
||||
message: 'Auto save error: Your changes are not saved.',
|
||||
} as any)
|
||||
} finally {
|
||||
this.saving = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@ import { NgModule } from '@angular/core'
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { RouterModule, Routes } from '@angular/router'
|
||||
import { DeveloperPage } from './developer-list.page'
|
||||
import { DeveloperListPage } from './developer-list.page'
|
||||
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||
import { BackupReportPageModule } from 'src/app/modals/backup-report/backup-report.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DeveloperPage,
|
||||
component: DeveloperListPage,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -21,6 +21,6 @@ const routes: Routes = [
|
||||
BadgeMenuComponentModule,
|
||||
BackupReportPageModule,
|
||||
],
|
||||
declarations: [DeveloperPage],
|
||||
declarations: [DeveloperListPage],
|
||||
})
|
||||
export class DeveloperPageModule {}
|
||||
export class DeveloperListPageModule {}
|
||||
|
||||
@@ -4,23 +4,36 @@
|
||||
<ion-back-button></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>Developer Tools</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<badge-menu-button></badge-menu-button>
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-item-divider>Components</ion-item-divider>
|
||||
<ion-item button detail (click)="navToInstructions()">
|
||||
<ion-icon slot="start" name="list-outline"></ion-icon>
|
||||
<ion-item-divider>Projects</ion-item-divider>
|
||||
|
||||
<ion-item button detail="false" (click)="openCreateProjectModal()">
|
||||
<ion-icon slot="start" name="add" color="dark"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>Instructions Generator</h2>
|
||||
<p>Create instructions and see how they will appear to the end user</p>
|
||||
<ion-text color="dark">Create project</ion-text>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button detail (click)="navToConfig()">
|
||||
<ion-icon slot="start" name="construct-outline"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>Config Generator</h2>
|
||||
<p>Edit the config with YAML and see it in real time</p>
|
||||
</ion-label>
|
||||
|
||||
<ion-item
|
||||
button
|
||||
*ngFor="let entry of devData | keyvalue"
|
||||
(click)="goToProject(entry.key)"
|
||||
>
|
||||
<p>{{ entry.value.name }}</p>
|
||||
<ion-button
|
||||
slot="end"
|
||||
fill="clear"
|
||||
color="danger"
|
||||
(click)="presentAlertDelete(entry.key, $event)"
|
||||
>
|
||||
<ion-icon slot="start" name="close"></ion-icon>
|
||||
Delete
|
||||
</ion-button>
|
||||
</ion-item>
|
||||
</ion-content>
|
||||
|
||||
@@ -1,23 +1,211 @@
|
||||
import { Component } from '@angular/core'
|
||||
import {
|
||||
AlertController,
|
||||
LoadingController,
|
||||
ModalController,
|
||||
NavController,
|
||||
} from '@ionic/angular'
|
||||
import {
|
||||
GenericInputComponent,
|
||||
GenericInputOptions,
|
||||
} from 'src/app/modals/generic-input/generic-input.component'
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import * as yaml from 'js-yaml'
|
||||
import { v4 } from 'uuid'
|
||||
import { DevData } from 'src/app/services/patch-db/data-model'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { ErrorToastService } from 'src/app/services/error-toast.service'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { NavController } from '@ionic/angular'
|
||||
import { DestroyService } from '@start9labs/shared'
|
||||
import { takeUntil } from 'rxjs/operators'
|
||||
|
||||
@Component({
|
||||
selector: 'developer-list',
|
||||
templateUrl: 'developer-list.page.html',
|
||||
styleUrls: ['developer-list.page.scss'],
|
||||
providers: [DestroyService],
|
||||
})
|
||||
export class DeveloperPage {
|
||||
export class DeveloperListPage {
|
||||
devData: DevData
|
||||
|
||||
constructor(
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly api: ApiService,
|
||||
private readonly loadingCtrl: LoadingController,
|
||||
private readonly errToast: ErrorToastService,
|
||||
private readonly alertCtrl: AlertController,
|
||||
private readonly navCtrl: NavController,
|
||||
private readonly route: ActivatedRoute,
|
||||
private readonly destroy$: DestroyService,
|
||||
private readonly patch: PatchDbService,
|
||||
) {}
|
||||
|
||||
navToConfig() {
|
||||
this.navCtrl.navigateForward(['config'], { relativeTo: this.route })
|
||||
ngOnInit() {
|
||||
this.patch
|
||||
.watch$('ui', 'dev')
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(dd => {
|
||||
this.devData = dd
|
||||
})
|
||||
}
|
||||
|
||||
navToInstructions() {
|
||||
this.navCtrl.navigateForward(['instructions'], { relativeTo: this.route })
|
||||
async openCreateProjectModal() {
|
||||
const projNumber = Object.keys(this.devData || {}).length + 1
|
||||
const options: GenericInputOptions = {
|
||||
title: 'Add new project',
|
||||
message: 'Create a new dev project.',
|
||||
label: 'New project',
|
||||
useMask: false,
|
||||
placeholder: `Project ${projNumber}`,
|
||||
nullable: true,
|
||||
initialValue: `Project ${projNumber}`,
|
||||
buttonText: 'Save',
|
||||
submitFn: (value: string) => this.createProject(value),
|
||||
}
|
||||
|
||||
const modal = await this.modalCtrl.create({
|
||||
componentProps: { options },
|
||||
cssClass: 'alertlike-modal',
|
||||
presentingElement: await this.modalCtrl.getTop(),
|
||||
component: GenericInputComponent,
|
||||
})
|
||||
|
||||
await modal.present()
|
||||
}
|
||||
|
||||
async createProject(name: string) {
|
||||
// fail silently if duplicate project name
|
||||
if (
|
||||
Object.values(this.devData || {})
|
||||
.map(v => v.name)
|
||||
.includes(name)
|
||||
)
|
||||
return
|
||||
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Creating Project...',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
const id = v4()
|
||||
const config = yaml
|
||||
.dump(SAMPLE_CONFIG)
|
||||
.replace(/warning:/g, '# Optional\n warning:')
|
||||
|
||||
const def = { name, config, instructions: SAMPLE_INSTUCTIONS }
|
||||
if (this.devData) {
|
||||
await this.api.setDbValue({ pointer: `/dev/${id}`, value: def })
|
||||
} else {
|
||||
await this.api.setDbValue({ pointer: `/dev`, value: { [id]: def } })
|
||||
}
|
||||
} catch (e) {
|
||||
this.errToast.present({ message: `Error saving project data` } as any)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
async presentAlertDelete(id: string, event: Event) {
|
||||
event.stopPropagation()
|
||||
const alert = await this.alertCtrl.create({
|
||||
header: 'Caution',
|
||||
message: `Are you sure you want to delete this project?`,
|
||||
buttons: [
|
||||
{
|
||||
text: 'Cancel',
|
||||
role: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Delete',
|
||||
handler: () => {
|
||||
this.delete(id)
|
||||
},
|
||||
cssClass: 'enter-click',
|
||||
},
|
||||
],
|
||||
})
|
||||
await alert.present()
|
||||
}
|
||||
|
||||
async delete(id: string) {
|
||||
const loader = await this.loadingCtrl.create({
|
||||
spinner: 'lines',
|
||||
message: 'Removing Project...',
|
||||
cssClass: 'loader',
|
||||
})
|
||||
await loader.present()
|
||||
|
||||
try {
|
||||
const devDataToSave: DevData = JSON.parse(JSON.stringify(this.devData))
|
||||
delete devDataToSave[id]
|
||||
await this.api.setDbValue({ pointer: `/dev`, value: devDataToSave })
|
||||
} catch (e) {
|
||||
this.errToast.present({ message: `Error deleting project data` } as any)
|
||||
} finally {
|
||||
loader.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
async goToProject(id: string) {
|
||||
await this.navCtrl.navigateForward([id], { relativeTo: this.route })
|
||||
}
|
||||
}
|
||||
|
||||
const SAMPLE_INSTUCTIONS = `# Create Instructions using Markdown! :)`
|
||||
|
||||
const SAMPLE_CONFIG: ConfigSpec = {
|
||||
'sample-string': {
|
||||
type: 'string',
|
||||
name: 'Example String Input',
|
||||
nullable: false,
|
||||
masked: false,
|
||||
copyable: false,
|
||||
// optional
|
||||
warning: null,
|
||||
description: 'Example description for required string input.',
|
||||
default: null,
|
||||
placeholder: 'Enter string value',
|
||||
pattern: '^[a-zA-Z0-9! _]+$',
|
||||
'pattern-description': 'Must be alphanumeric (may contain underscore).',
|
||||
},
|
||||
'sample-number': {
|
||||
type: 'number',
|
||||
name: 'Example Number Input',
|
||||
nullable: false,
|
||||
range: '[5,1000000]',
|
||||
integral: true,
|
||||
// optional
|
||||
warning: 'Example warning to display when changing this number value.',
|
||||
units: 'ms',
|
||||
description: 'Example description for optional number input.',
|
||||
default: null,
|
||||
placeholder: 'Enter number value',
|
||||
},
|
||||
'sample-boolean': {
|
||||
type: 'boolean',
|
||||
name: 'Example Boolean Toggle',
|
||||
// optional
|
||||
warning: null,
|
||||
description: 'Example description for boolean toggle',
|
||||
default: true,
|
||||
},
|
||||
'sample-enum': {
|
||||
type: 'enum',
|
||||
name: 'Example Enum Select',
|
||||
values: ['red', 'blue', 'green'],
|
||||
'value-names': {
|
||||
red: 'Red',
|
||||
blue: 'Blue',
|
||||
green: 'Green',
|
||||
},
|
||||
// optional
|
||||
warning: 'Example warning to display when changing this enum value.',
|
||||
description: 'Example description for enum select',
|
||||
default: 'red',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { IonicModule } from '@ionic/angular'
|
||||
import { RouterModule, Routes } from '@angular/router'
|
||||
import { DeveloperMenuPage } from './developer-menu.page'
|
||||
import { BadgeMenuComponentModule } from 'src/app/components/badge-menu-button/badge-menu.component.module'
|
||||
import { BackupReportPageModule } from 'src/app/modals/backup-report/backup-report.module'
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: DeveloperMenuPage,
|
||||
},
|
||||
]
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
IonicModule,
|
||||
RouterModule.forChild(routes),
|
||||
BadgeMenuComponentModule,
|
||||
BackupReportPageModule,
|
||||
],
|
||||
declarations: [DeveloperMenuPage],
|
||||
})
|
||||
export class DeveloperMenuPageModule {}
|
||||
@@ -0,0 +1,26 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button defaultHref="/developer"></ion-back-button>
|
||||
</ion-buttons>
|
||||
<ion-title>{{ patchDb.data.ui.dev[projectId].name}}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-item-divider>Components</ion-item-divider>
|
||||
<ion-item button detail routerLink="instructions" routerDirection="forward">
|
||||
<ion-icon slot="start" name="list-outline"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>Instructions Generator</h2>
|
||||
<p>Create instructions and see how they will appear to the end user</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
<ion-item button detail routerLink="config">
|
||||
<ion-icon slot="start" name="construct-outline"></ion-icon>
|
||||
<ion-label>
|
||||
<h2>Config Generator</h2>
|
||||
<p>Edit the config with YAML and see it in real time</p>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-content>
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||
|
||||
@Component({
|
||||
selector: 'developer-menu',
|
||||
templateUrl: 'developer-menu.page.html',
|
||||
styleUrls: ['developer-menu.page.scss'],
|
||||
})
|
||||
export class DeveloperMenuPage {
|
||||
projectId: string
|
||||
constructor(
|
||||
private readonly route: ActivatedRoute,
|
||||
public readonly patchDb: PatchDbService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.projectId = this.route.snapshot.paramMap.get('projectId')
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,30 @@ import { Routes, RouterModule } from '@angular/router'
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'projects',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: 'projects',
|
||||
loadChildren: () =>
|
||||
import('./developer-list/developer-list.module').then(
|
||||
m => m.DeveloperPageModule,
|
||||
m => m.DeveloperListPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'config',
|
||||
path: 'projects/:projectId',
|
||||
loadChildren: () =>
|
||||
import('./developer-menu/developer-menu.module').then(
|
||||
m => m.DeveloperMenuPageModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'projects/:projectId/config',
|
||||
loadChildren: () =>
|
||||
import('./dev-config/dev-config.module').then(m => m.DevConfigPageModule),
|
||||
},
|
||||
{
|
||||
path: 'instructions',
|
||||
path: 'projects/:projectId/instructions',
|
||||
loadChildren: () =>
|
||||
import('./dev-instructions/dev-instructions.module').then(
|
||||
m => m.DevInstructionsPageModule,
|
||||
|
||||
@@ -15,6 +15,7 @@ export const mockPatchData: DataModel = {
|
||||
'pkg-order': [],
|
||||
'ack-welcome': '1.0.0',
|
||||
marketplace: undefined,
|
||||
dev: undefined,
|
||||
},
|
||||
'server-info': {
|
||||
id: 'embassy-abcdefgh',
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface UIData {
|
||||
'pkg-order': string[]
|
||||
'ack-welcome': string // EOS version
|
||||
marketplace: UIMarketplaceData
|
||||
dev: DevData
|
||||
}
|
||||
|
||||
export interface UIMarketplaceData {
|
||||
@@ -26,6 +27,14 @@ export interface UIMarketplaceData {
|
||||
}
|
||||
}
|
||||
|
||||
export interface DevData {
|
||||
[id: string]: {
|
||||
name: string
|
||||
instructions?: string
|
||||
config?: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface ServerInfo {
|
||||
id: string
|
||||
version: string
|
||||
|
||||
Reference in New Issue
Block a user