diff --git a/.drone.yml b/.drone.yml
index 7beab32..b833ea8 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -55,7 +55,7 @@ steps:
- cd www
- sed -i 's///' index.html
- sed -i 's/Ionic App/Noded/' index.html
- - echo -n '${DRONE_TAG}-staging' | sudo tee version.html
+ - echo -n "$(uuidgen)" | sudo tee version.html
when:
event: promote
target: staging
@@ -93,7 +93,7 @@ steps:
- cd www
- sed -i 's///' index.html
- sed -i 's/Ionic App/Noded/' index.html
- - echo -n '${DRONE_TAG}-prod' | sudo tee version.html
+ - echo -n "$(uuidgen)" | sudo tee version.html
when:
event: promote
target: production
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 6f90e65..2756d2a 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -36,12 +36,7 @@ export class AppComponent implements OnInit {
actionMapping: {
mouse: {
dblClick: (tree, node, $event) => {
- const id = node.data.id;
- const nodeId = node.data.node_id;
- if ( !node.data.virtual ) {
- this.currentPageId = id;
- this.router.navigate(['/editor', { id, ...(nodeId ? { node_id: nodeId } : {}) }]);
- }
+ this.navigateEditorToNode(node);
},
click: (tree, node, $event) => {
TREE_ACTIONS.FOCUS(tree, node, $event);
@@ -165,6 +160,19 @@ export class AppComponent implements OnInit {
this.hasSearchOpen = false;
}
+ public navigateEditorToNode(node: any) {
+ if ( !node.data ) {
+ node = { data: node };
+ }
+
+ const id = node.data.id;
+ const nodeId = node.data.node_id;
+ if ( !node.data.virtual ) {
+ this.currentPageId = id;
+ this.router.navigate(['/editor', { id, ...(nodeId ? { node_id: nodeId } : {}) }]);
+ }
+ }
+
async onNodeMenuClick($event) {
let canManage = this.menuTarget.data.level === 'manage';
if ( !canManage ) {
@@ -368,6 +376,7 @@ export class AppComponent implements OnInit {
}
async initializeApp() {
+ console.log('session', this);
this.loader = await this.loading.create({
message: 'Starting up...',
cssClass: 'noded-loading-mask',
@@ -388,17 +397,46 @@ export class AppComponent implements OnInit {
this.session.systemBase = stat.system_base;
await this.session.initialize();
+
+ if ( this.session.get('user.preferences.dark_mode') ) {
+ this.toggleDark();
+ }
+
await this.statusBar.styleDefault();
await this.splashScreen.hide();
this.initialized$.next(true);
+
+ if ( this.session.get('user.preferences.default_page') ) {
+ const id = this.session.get('user.preferences.default_page');
+ const node = this.findNode(id);
+ if ( node ) {
+ this.navigateEditorToNode(node);
+ }
+ }
}
toggleDark() {
// const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
this.darkMode = !this.darkMode;
+ this.session.set('user.preferences.dark_mode', this.darkMode);
document.body.classList.toggle('dark', this.darkMode);
}
+ findNode(id: string, nodes = this.nodes) {
+ for ( const node of nodes ) {
+ if ( node.id === id ) {
+ return node;
+ }
+
+ if ( node.children ) {
+ const foundNode = this.findNode(id, node.children);
+ if ( foundNode ) {
+ return foundNode;
+ }
+ }
+ }
+ }
+
isDark() {
return !!this.darkMode;
}
diff --git a/src/app/service/session.service.ts b/src/app/service/session.service.ts
index a2a9062..c8c76d9 100644
--- a/src/app/service/session.service.ts
+++ b/src/app/service/session.service.ts
@@ -1,5 +1,6 @@
import { Injectable } from '@angular/core';
import {ApiService} from './api.service';
+import {debounce} from './editor.service';
@Injectable({
providedIn: 'root'
@@ -8,6 +9,22 @@ export class SessionService {
public appName!: string;
public systemBase!: string;
protected data: any = {};
+ protected saveTriggered = false;
+ protected saving = false;
+ protected privTriggerSave = debounce(() => {
+ if ( this.saving ) {
+ this.triggerSave();
+ } else {
+ this.save();
+ }
+
+ this.saveTriggered = false;
+ }, 3000);
+
+ public triggerSave() {
+ this.saveTriggered = true;
+ this.privTriggerSave();
+ }
constructor(
protected readonly api: ApiService,
@@ -30,6 +47,22 @@ export class SessionService {
});
}
+ async save() {
+ this.saving = true;
+ return new Promise((res, rej) => {
+ this.api.post('/session', this.data || {}).subscribe({
+ next: result => {
+ res();
+ this.saving = false;
+ },
+ error: (e) => {
+ this.saving = false;
+ rej(e);
+ },
+ });
+ });
+ }
+
buildAppUrl(...parts: string[]): string {
parts = parts.map(x => {
if ( x.startsWith('/') ) {
@@ -45,4 +78,45 @@ export class SessionService {
return `${this.systemBase}${this.systemBase.endsWith('/') ? '' : '/'}${parts.join('/')}`;
}
+
+ get(path?: string): any {
+ let current: any = this.data;
+ if ( !path ) {
+ return current;
+ }
+
+ const parts = path.split('.');
+ for ( const part of parts ) {
+ current = current?.[part];
+ }
+
+ return current;
+ }
+
+ set(pathOrValue: string | any, value?: any): any {
+ if ( typeof pathOrValue !== 'string' ) {
+ this.data = pathOrValue;
+ return;
+ }
+
+ if ( typeof value === 'undefined' ) {
+ return;
+ }
+
+ const parts = pathOrValue.split('.');
+ let last;
+ let current = this.data;
+
+ for ( const part of parts ) {
+ last = current;
+ current = current?.[part];
+ }
+
+ parts.reverse();
+ if ( last ) {
+ last[parts[0]] = value;
+ }
+
+ this.triggerSave();
+ }
}