f40ef6b7c0
Align Cloudly with the current typedserver, smartconfig, smartstate, and Docker tooling releases so builds and Docker output stay compatible with the upgraded stack.
264 lines
7.6 KiB
TypeScript
264 lines
7.6 KiB
TypeScript
import { commitinfo } from '../00_commitinfo_data.js';
|
|
import * as plugins from '../plugins.js';
|
|
|
|
import * as appstate from '../appstate.js';
|
|
|
|
import {
|
|
DeesElement,
|
|
css,
|
|
cssManager,
|
|
customElement,
|
|
html,
|
|
state
|
|
} from '@design.estate/dees-element';
|
|
import { CloudlyViewBackups } from './views/backups/index.js';
|
|
import { CloudlyViewBaseOs } from './views/baseos/index.js';
|
|
import { CloudlyViewClusters } from './views/clusters/index.js';
|
|
import { CloudlyViewDbs } from './views/dbs/index.js';
|
|
import { CloudlyViewDeployments } from './views/deployments/index.js';
|
|
import { CloudlyViewDns } from './views/dns/index.js';
|
|
import { CloudlyViewDomains } from './views/domains/index.js';
|
|
import { CloudlyViewImages } from './views/images/index.js';
|
|
import { CloudlyViewLogs } from './views/logs/index.js';
|
|
import { CloudlyViewMails } from './views/mails/index.js';
|
|
import { CloudlyViewOverview } from './views/overview/index.js';
|
|
import { CloudlyViewS3 } from './views/s3/index.js';
|
|
import { CloudlyViewSecretBundles } from './views/secretbundles/index.js';
|
|
import { CloudlyViewSecretGroups } from './views/secretgroups/index.js';
|
|
import { CloudlyViewServices } from './views/services/index.js';
|
|
import { CloudlyViewExternalRegistries } from './views/externalregistries/index.js';
|
|
import { CloudlyViewSettings } from './views/settings/index.js';
|
|
import { CloudlyViewTasks } from './views/tasks/index.js';
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
'cvault-dashboard': CloudlyDashboard;
|
|
}
|
|
}
|
|
|
|
@customElement('cloudly-dashboard')
|
|
export class CloudlyDashboard extends DeesElement {
|
|
@state() private accessor identity: plugins.interfaces.data.IIdentity | null = null;
|
|
@state() private accessor data: appstate.IDataState = {
|
|
secretGroups: [],
|
|
secretBundles: [],
|
|
clusters: [],
|
|
};
|
|
|
|
// Keep view tabs stable across renders to preserve active selection
|
|
private readonly viewTabs: plugins.deesCatalog.IView[] = [
|
|
{
|
|
name: 'Overview',
|
|
iconName: 'lucide:LayoutDashboard',
|
|
element: CloudlyViewOverview,
|
|
},
|
|
{
|
|
name: 'Settings',
|
|
iconName: 'lucide:Settings',
|
|
element: CloudlyViewSettings,
|
|
},
|
|
{
|
|
name: 'SecretGroups',
|
|
iconName: 'lucide:ShieldCheck',
|
|
element: CloudlyViewSecretGroups,
|
|
},
|
|
{
|
|
name: 'SecretBundles',
|
|
iconName: 'lucide:LockKeyhole',
|
|
element: CloudlyViewSecretBundles,
|
|
},
|
|
{
|
|
name: 'Clusters',
|
|
iconName: 'lucide:Network',
|
|
element: CloudlyViewClusters,
|
|
},
|
|
{
|
|
name: 'ExternalRegistries',
|
|
iconName: 'lucide:Package',
|
|
element: CloudlyViewExternalRegistries,
|
|
},
|
|
{
|
|
name: 'Images',
|
|
iconName: 'lucide:Image',
|
|
element: CloudlyViewImages,
|
|
},
|
|
{
|
|
name: 'Services',
|
|
iconName: 'lucide:Layers',
|
|
element: CloudlyViewServices,
|
|
},
|
|
{
|
|
name: 'Testing & Building',
|
|
iconName: 'lucide:HardHat',
|
|
element: CloudlyViewServices,
|
|
},
|
|
{
|
|
name: 'Deployments',
|
|
iconName: 'lucide:Rocket',
|
|
element: CloudlyViewDeployments,
|
|
},
|
|
{
|
|
name: 'Tasks',
|
|
iconName: 'lucide:ListChecks',
|
|
element: CloudlyViewTasks,
|
|
},
|
|
{
|
|
name: 'Domains',
|
|
iconName: 'lucide:Globe2',
|
|
element: CloudlyViewDomains,
|
|
},
|
|
{
|
|
name: 'DNS',
|
|
iconName: 'lucide:Globe',
|
|
element: CloudlyViewDns,
|
|
},
|
|
{
|
|
name: 'Mails',
|
|
iconName: 'lucide:Mail',
|
|
element: CloudlyViewMails,
|
|
},
|
|
{
|
|
name: 'Logs',
|
|
iconName: 'lucide:FileText',
|
|
element: CloudlyViewLogs,
|
|
},
|
|
{
|
|
name: 's3',
|
|
iconName: 'lucide:Cloud',
|
|
element: CloudlyViewS3,
|
|
},
|
|
{
|
|
name: 'DBs',
|
|
iconName: 'lucide:Database',
|
|
element: CloudlyViewDbs,
|
|
},
|
|
{
|
|
name: 'Backups',
|
|
iconName: 'lucide:Save',
|
|
element: CloudlyViewBackups,
|
|
},
|
|
{
|
|
name: 'BaseOS',
|
|
iconName: 'lucide:HardDriveDownload',
|
|
element: CloudlyViewBaseOs,
|
|
},
|
|
{
|
|
name: 'Fleet',
|
|
iconName: 'lucide:Truck',
|
|
element: CloudlyViewBackups,
|
|
},
|
|
];
|
|
|
|
constructor() {
|
|
super();
|
|
document.title = `cloudly v${commitinfo.version}`;
|
|
const subcription = appstate.dataState
|
|
.select((stateArg) => stateArg)
|
|
.subscribe((dataArg) => {
|
|
this.data = dataArg;
|
|
});
|
|
this.rxSubscriptions.push(subcription);
|
|
}
|
|
|
|
public static styles = [
|
|
cssManager.defaultStyles,
|
|
css`
|
|
.maincontainer {
|
|
position: relative;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
}
|
|
|
|
h1 {
|
|
font-weight: 400;
|
|
font-size: 24px;
|
|
font-family: 'Cal Sans';
|
|
}
|
|
`,
|
|
];
|
|
public render() {
|
|
return html`
|
|
<div class="maincontainer">
|
|
<dees-simple-login name="cloudly v${commitinfo.version}">
|
|
<dees-simple-appdash name="cloudly v${commitinfo.version}"
|
|
.viewTabs=${this.viewTabs}
|
|
></dees-simple-appdash>
|
|
</dees-simple-login>
|
|
</div>
|
|
`;
|
|
}
|
|
public async firstUpdated() {
|
|
const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
|
|
simpleLogin.addEventListener('login', (eventArg: Event) => {
|
|
const loginEvent = eventArg as CustomEvent;
|
|
console.log(loginEvent.detail);
|
|
this.login(loginEvent.detail.data.username, loginEvent.detail.data.password);
|
|
});
|
|
this.addEventListener('contextmenu', (eventArg) => {
|
|
plugins.deesCatalog.DeesContextmenu.openContextMenuWithOptions(eventArg, [
|
|
{
|
|
name: 'About',
|
|
iconName: 'mugHot',
|
|
action: async () => {
|
|
await plugins.deesCatalog.DeesModal.createAndShow({
|
|
heading: 'About',
|
|
content: html`cloudly ${commitinfo.version}`,
|
|
menuOptions: [
|
|
{
|
|
name: 'close',
|
|
iconName: undefined,
|
|
action: async (modalArg: any) => {
|
|
await modalArg.destroy();
|
|
},
|
|
},
|
|
],
|
|
});
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
// lets deal with initial state
|
|
const domtools = await this.domtoolsPromise;
|
|
const loginState = appstate.loginStatePart.getState();
|
|
console.log(loginState);
|
|
if (loginState?.identity) {
|
|
this.identity = loginState.identity;
|
|
try {
|
|
appstate.apiClient.identity = loginState.identity;
|
|
if (!appstate.apiClient['typedsocketClient']) {
|
|
await appstate.apiClient.start();
|
|
}
|
|
try { await appstate.apiClient.typedsocketClient.setTag('identity', appstate.apiClient.identity); } catch {}
|
|
} catch (e) { console.warn('Failed to initialize API client WS', e); }
|
|
await simpleLogin.switchToSlottedContent();
|
|
await appstate.dataState.dispatchAction(appstate.getAllDataAction, null);
|
|
}
|
|
}
|
|
|
|
private async login(username: string, password: string) {
|
|
const domtools = await this.domtoolsPromise;
|
|
console.log(`attempting to login...`);
|
|
const simpleLogin = this.shadowRoot!.querySelector('dees-simple-login') as any;
|
|
const form = simpleLogin.shadowRoot.querySelector('dees-form') as any;
|
|
form.setStatus('pending', 'Logging in...');
|
|
const state = await appstate.loginStatePart.dispatchAction(appstate.loginAction, {
|
|
username,
|
|
password,
|
|
});
|
|
if (state?.identity) {
|
|
console.log('got jwt');
|
|
this.identity = state.identity;
|
|
form.setStatus('success', 'Logged in!');
|
|
await simpleLogin.switchToSlottedContent();
|
|
await appstate.dataState.dispatchAction(appstate.getAllDataAction, null);
|
|
} else {
|
|
form.setStatus('error', 'Login failed!');
|
|
await domtools.convenience.smartdelay.delayFor(2000);
|
|
form.reset();
|
|
}
|
|
}
|
|
|
|
private async logout() {}
|
|
}
|