- Added typedRequestInterfaces import to plugins.ts for better type handling. - Updated CLI client to utilize environment variables for Cloudly API credentials and improved authentication flow. - Refactored appstate.ts to use a shared API client instance, reducing redundancy in API calls for various actions. - Simplified external registry actions in appstate.ts by leveraging the shared API client. - Updated CloudlyDashboard and CloudlyViewSettings components to utilize the shared API client for fetching settings and managing connections. - Removed redundant TypedRequest instances in favor of direct API client calls for improved performance and maintainability. - Exposed the API client in plugins.ts for easier access in UI components.
257 lines
7.3 KiB
TypeScript
257 lines
7.3 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 './cloudly-view-backups.js';
|
|
import { CloudlyViewClusters } from './cloudly-view-clusters.js';
|
|
import { CloudlyViewDbs } from './cloudly-view-dbs.js';
|
|
import { CloudlyViewDeployments } from './cloudly-view-deployments.js';
|
|
import { CloudlyViewDns } from './cloudly-view-dns.js';
|
|
import { CloudlyViewDomains } from './cloudly-view-domains.js';
|
|
import { CloudlyViewImages } from './cloudly-view-images.js';
|
|
import { CloudlyViewLogs } from './cloudly-view-logs.js';
|
|
import { CloudlyViewMails } from './cloudly-view-mails.js';
|
|
import { CloudlyViewOverview } from './cloudly-view-overview.js';
|
|
import { CloudlyViewS3 } from './cloudly-view-s3.js';
|
|
import { CloudlyViewSecretBundles } from './cloudly-view-secretbundles.js';
|
|
import { CloudlyViewSecretGroups } from './cloudly-view-secretgroups.js';
|
|
import { CloudlyViewServices } from './cloudly-view-services.js';
|
|
import { CloudlyViewExternalRegistries } from './cloudly-view-externalregistries.js';
|
|
import { CloudlyViewSettings } from './cloudly-view-settings.js';
|
|
import { CloudlyViewTasks } from './cloudly-view-tasks.js';
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
'cvault-dashboard': CloudlyDashboard;
|
|
}
|
|
}
|
|
|
|
@customElement('cloudly-dashboard')
|
|
export class CloudlyDashboard extends DeesElement {
|
|
@state() private identity: plugins.interfaces.data.IIdentity;
|
|
@state() private 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: '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');
|
|
simpleLogin.addEventListener('login', (e: CustomEvent) => {
|
|
console.log(e.detail);
|
|
this.login(e.detail.data.username, e.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: null,
|
|
action: async (modalArg) => {
|
|
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 { appstate.apiClient.typedsocketClient.addTag('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');
|
|
const form = simpleLogin.shadowRoot.querySelector('dees-form');
|
|
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() {}
|
|
}
|