feat(appstore): add remote app store templates with service upgrades and Redis/MariaDB platform support

This commit is contained in:
2026-03-21 19:36:25 +00:00
parent c0f9f979c7
commit 22f34e7de5
35 changed files with 2496 additions and 254 deletions

View File

@@ -1,6 +1,7 @@
import * as plugins from '../plugins.js';
import * as appstate from '../appstate.js';
import * as interfaces from '../../ts_interfaces/index.js';
import { appRouter } from '../router.js';
import {
DeesElement,
customElement,
@@ -93,6 +94,9 @@ export class ObAppShell extends DeesElement {
<dees-simple-appdash
name="Onebox"
.viewTabs=${this.resolvedViewTabs}
.selectedView=${this.resolvedViewTabs.find(
(t) => t.name.toLowerCase().replace(/\s+/g, '-') === this.uiState.activeView
) || this.resolvedViewTabs[0]}
>
</dees-simple-appdash>
</dees-simple-login>
@@ -122,8 +126,8 @@ export class ObAppShell extends DeesElement {
const appDash = this.shadowRoot!.querySelector('dees-simple-appdash') as any;
if (appDash) {
appDash.addEventListener('view-select', (e: CustomEvent) => {
const viewName = e.detail.view.name.toLowerCase();
appstate.uiStatePart.dispatchAction(appstate.setActiveViewAction, { view: viewName });
const viewName = e.detail.view.name.toLowerCase().replace(/\s+/g, '-');
appRouter.navigateToView(viewName);
});
appDash.addEventListener('logout', async () => {
await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
@@ -131,10 +135,11 @@ export class ObAppShell extends DeesElement {
}
// Load the initial view on the appdash now that tabs are resolved
// (appdash's own firstUpdated already fired when viewTabs was still empty)
// Read activeView directly from state (not this.uiState which may be stale)
if (appDash && this.resolvedViewTabs.length > 0) {
const currentActiveView = appstate.uiStatePart.getState().activeView;
const initialView = this.resolvedViewTabs.find(
(t) => t.name.toLowerCase() === this.uiState.activeView,
(t) => t.name.toLowerCase().replace(/\s+/g, '-') === currentActiveView,
) || this.resolvedViewTabs[0];
await appDash.loadView(initialView);
}
@@ -143,23 +148,26 @@ export class ObAppShell extends DeesElement {
const loginState = appstate.loginStatePart.getState();
if (loginState.identity?.jwt) {
if (loginState.identity.expiresAt > Date.now()) {
// Validate token with server before switching to dashboard
// (server may have restarted with a new JWT secret)
// Switch to dashboard immediately (no flash of login form)
this.loginState = loginState;
if (simpleLogin) {
await simpleLogin.switchToSlottedContent();
}
// Validate token with server in the background
try {
const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_GetSystemStatus
>('/typedrequest', 'getSystemStatus');
const response = await typedRequest.fire({ identity: loginState.identity });
// Token is valid - switch to dashboard
appstate.systemStatePart.setState({ status: response.status });
this.loginState = loginState;
if (simpleLogin) {
await simpleLogin.switchToSlottedContent();
}
} catch (err) {
// Token rejected by server - clear session
// Token rejected by server - switch back to login
console.warn('Stored session invalid, returning to login:', err);
await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
if (simpleLogin) {
// Force page reload to show login properly
window.location.reload();
}
}
} else {
await appstate.loginStatePart.dispatchAction(appstate.logoutAction, null);
@@ -201,9 +209,11 @@ export class ObAppShell extends DeesElement {
private syncAppdashView(viewName: string): void {
const appDash = this.shadowRoot?.querySelector('dees-simple-appdash') as any;
if (!appDash || this.resolvedViewTabs.length === 0) return;
const targetTab = this.resolvedViewTabs.find((t) => t.name.toLowerCase() === viewName);
// Match kebab-case view name (e.g., 'app-store') to tab name (e.g., 'App Store')
const targetTab = this.resolvedViewTabs.find(
(t) => t.name.toLowerCase().replace(/\s+/g, '-') === viewName
);
if (!targetTab) return;
// Use appdash's own loadView method for proper view management
appDash.loadView(targetTab);
}
}