fix(core): update

This commit is contained in:
2024-04-20 12:21:41 +02:00
commit c24262f765
84 changed files with 14340 additions and 0 deletions

View File

@ -0,0 +1,202 @@
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 { 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';
declare global {
interface HTMLElementTagNameMap {
'cvault-dashboard': CloudlyDashboard;
}
}
@customElement('cloudly-dashboard')
export class CloudlyDashboard extends DeesElement {
@state() private jwt: string;
@state() private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
clusters: [],
};
constructor() {
super();
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=${[
{
name: 'Overview',
element: CloudlyViewOverview,
},
{
name: 'SecretGroups',
element: CloudlyViewSecretGroups,
},
{
name: 'SecretBundles',
element: CloudlyViewSecretBundles,
},
{
name: 'Clusters',
element: CloudlyViewClusters,
},
{
name: 'Images',
element: CloudlyViewImages,
},
{
name: 'Services',
element: CloudlyViewServices,
},
{
name: 'Deployments',
element: CloudlyViewDeployments,
},
{
name: 'DNS',
element: CloudlyViewDns,
},
{
name: 'Mails',
element: CloudlyViewMails,
},
{
name: 'Logs',
element: CloudlyViewLogs,
},
{
name: 's3',
element: CloudlyViewS3,
},
{
name: 'DBs',
element: CloudlyViewDbs,
},
{
name: 'Backups',
element: CloudlyViewBackups,
},
{
name: 'Fleet',
element: CloudlyViewBackups,
}
] as plugins.deesCatalog.IView[]}
></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`configvault ${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.jwt) {
this.jwt = loginState.jwt;
await simpleLogin.switchToSlottedContent();
await appstate.dataState.dispatchAction(appstate.getDataAction, 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.jwt) {
console.log('got jwt');
this.jwt = state.jwt;
form.setStatus('success', 'Logged in!');
await simpleLogin.switchToSlottedContent();
await appstate.dataState.dispatchAction(appstate.getDataAction, null);
} else {
form.setStatus('error', 'Login failed!');
await domtools.convenience.smartdelay.delayFor(2000);
form.reset();
}
}
private async logout() {}
}

View File

@ -0,0 +1,133 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-backups')
export class CloudlyViewBackups extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>Backups</cloudly-sectionheading>
<dees-table
.heading1=${'Backups'}
.heading2=${'decoded in client'}
.data=${this.data.backups}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,140 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-clusters')
export class CloudlyViewClusters extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>Clusters</cloudly-sectionheading>
<dees-table
.heading1=${'Clusters'}
.heading2=${'decoded in client'}
.data=${this.data.clusters}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
console.log(itemArg);
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add cluster',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add Cluster',
content: html`
<dees-form>
<dees-input-text
.key=${'clusterName'}
.label=${'cluster name'}
.description=${'a descriptive name for the cluster'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{
name: 'create',
action: async (modalArg) => {
const data: {
clusterName: string;
} = (await modalArg.shadowRoot
.querySelector('dees-form')
.collectFormData()) as any;
await appstate.dataState.dispatchAction(appstate.addClusterAction, data);
await modalArg.destroy();
},
},
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,133 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-dbs')
export class CloudlyViewDbs extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>DBs</cloudly-sectionheading>
<dees-table
.heading1=${'DBs'}
.heading2=${'decoded in client'}
.data=${this.data.dbs}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,133 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-deployments')
export class CloudlyViewDeployments extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>Deployments</cloudly-sectionheading>
<dees-table
.heading1=${'Deployments'}
.heading2=${'decoded in client'}
.data=${this.data.deployments}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,133 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-dns')
export class CloudlyViewDns extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>DNS</cloudly-sectionheading>
<dees-table
.heading1=${'DNS'}
.heading2=${'decoded in client'}
.data=${this.data.deployments}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,367 @@
import * as plugins from '../plugins.js';
import { DeesElement, customElement, html, state, css, cssManager } from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-images')
export class CloudlyViewImages extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>Images</cloudly-sectionheading>
<dees-table
heading1="SecretGroups"
heading2="decoded in client"
.data=${this.data.images}
.displayFunction=${(secretGroup: plugins.interfaces.data.ISecretGroup) => {
return {
name: secretGroup.data.name,
priority: secretGroup.data.priority,
tags: html`<dees-chips
.selectionMode=${'none'}
.selectableChips=${secretGroup.data.tags}
></dees-chips>`,
key: secretGroup.data.key,
history: (() => {
const allHistory = [];
for (const environment in secretGroup.data.environments) {
allHistory.push(...secretGroup.data.environments[environment].history);
}
return allHistory.length;
})(),
};
}}
.dataActions=${[
{
name: 'add SecretGroup',
type: ['header', 'footer'],
iconName: 'plus',
actionFunc: async () => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: 'create new SecretGroup',
content: html`
<dees-form>
<dees-input-text
.label=${'name'}
.key=${'data.name'}
.value=${''}
></dees-input-text>
<dees-input-text
.label=${'description'}
.key=${'data.description'}
.value=${''}
></dees-input-text>
<dees-input-text
.label=${'Secret Key (data.key)'}
.key=${'data.key'}
.value=${''}
></dees-input-text>
<dees-table
.heading1=${'Environments'}
.heading2=${'keys need to be unique'}
key="environments"
.data=${[
{
environment: 'production',
value: '',
},
{
environment: 'staging',
value: '',
},
]}
.dataActions=${[
{
name: 'add environment',
iconName: 'plus',
type: ['footer'],
actionFunc: async (dataArg) => {
dataArg.table.data.push({
environment: 'new environment',
value: '',
});
dataArg.table.requestUpdate('data');
},
},
{
name: 'delete environment',
iconName: 'trash',
type: ['inRow'],
actionFunc: async (dataArg) => {
dataArg.table.data.splice(dataArg.table.data.indexOf(dataArg.item), 1);
dataArg.table.requestUpdate('data');
},
},
] as plugins.deesCatalog.ITableAction[]}
.editableFields=${['environment', 'value']}
></dees-table>
</dees-form>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'save',
action: async (modalArg) => {
const deesForm = modalArg.shadowRoot.querySelector('dees-form');
const formData = await deesForm.collectFormData();
console.log(`Prepare saving of data:`);
console.log(formData);
const environments: plugins.interfaces.data.ISecretGroup['data']['environments'] =
{};
for (const itemArg of formData['environments'] as any[]) {
environments[itemArg.environment] = {
value: itemArg.value,
history: [],
lastUpdated: Date.now(),
};
}
await appstate.dataState.dispatchAction(appstate.createSecretGroupAction, {
id: null,
data: {
name: formData['data.name'] as string,
description: formData['data.description'] as string,
key: formData['data.key'] as string,
environments,
tags: [],
},
});
await modalArg.destroy();
},
},
],
});
},
},
{
name: 'edit',
type: ['contextmenu', 'inRow', 'doubleClick'],
iconName: 'penToSquare',
actionFunc: async (
dataArg: plugins.deesCatalog.ITableActionDataArg<plugins.interfaces.data.ISecretGroup>
) => {
const environmentsArray: Array<
plugins.interfaces.data.ISecretGroup['data']['environments'][any] & {
environment: string;
}
> = [];
for (const environmentName of Object.keys(dataArg.item.data.environments)) {
environmentsArray.push({
environment: environmentName,
...dataArg.item.data.environments[environmentName],
});
}
await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Edit Secret',
content: html`
<dees-form>
<dees-input-text
.key=${'id'}
.disabled=${true}
.label=${'ID'}
.value=${dataArg.item.id}
></dees-input-text>
<dees-input-text
.key=${'data.name'}
.disabled=${false}
.label=${'name'}
.value=${dataArg.item.data.name}
></dees-input-text>
<dees-input-text
.key=${'data.description'}
.disabled=${false}
.label=${'description'}
.value=${dataArg.item.data.description}
></dees-input-text>
<dees-input-text
.key=${'data.key'}
.disabled=${false}
.label=${'key'}
.value=${dataArg.item.data.key}
></dees-input-text>
<dees-table
.key=${'environments'}
.heading1=${'Environments'}
.heading2=${'double-click to edit values'}
.data=${environmentsArray.map((itemArg) => {
return {
environment: itemArg.environment,
value: itemArg.value,
};
})}
.editableFields=${['environment', 'value']}
.dataActions=${[
{
name: 'delete',
iconName: 'trash',
type: ['inRow'],
actionFunc: async (actionDataArg) => {
actionDataArg.table.data.splice(
actionDataArg.table.data.indexOf(actionDataArg.item),
1
);
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
</dees-form>
`,
menuOptions: [
{
name: 'Cancel',
iconName: null,
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'Save',
iconName: null,
action: async (modalArg) => {
const data = await modalArg.shadowRoot
.querySelector('dees-form')
.collectFormData();
console.log(data);
const updatedSecretGroup: plugins.interfaces.data.ISecretGroup = {
id: dataArg.item.id,
data: {
name: data['data.name'] as string,
description: data['data.description'] as string,
key: data['data.key'] as string,
environments: {},
tags: dataArg.item.data.tags,
},
};
const environments: plugins.interfaces.data.ISecretGroup['data']['environments'] =
{};
for (const itemArg of data['environments'] as any[]) {
}
},
},
],
});
},
},
{
name: 'history',
iconName: 'clockRotateLeft',
type: ['contextmenu', 'inRow'],
actionFunc: async (
dataArg: plugins.deesCatalog.ITableActionDataArg<plugins.interfaces.data.ISecretGroup>
) => {
const historyArray: Array<{
environment: string;
value: string;
}> = [];
for (const environment of Object.keys(dataArg.item.data.environments)) {
for (const historyItem of dataArg.item.data.environments[environment].history) {
historyArray.push({
environment,
value: historyItem.value,
});
}
}
await plugins.deesCatalog.DeesModal.createAndShow({
heading: `history for ${dataArg.item.data.key}`,
content: html`
<dees-table
.data=${historyArray}
.dataActions=${[
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (
itemArg: plugins.deesCatalog.ITableActionDataArg<(typeof historyArray)[0]>
) => {
console.log('delete', itemArg);
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`,
menuOptions: [
{
name: 'close',
action: async (modalArg) => {
await modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (
itemArg: plugins.deesCatalog.ITableActionDataArg<plugins.interfaces.data.ISecretGroup>
) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ${itemArg.item.data.key}`,
content: html`
<div style="text-align:center">Do you really want to delete the secret?</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${itemArg.item.data.key}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
console.log(`Delete ${itemArg.item.id}`);
await appstate.dataState.dispatchAction(appstate.deleteSecretGroupAction, {
secretGroupId: itemArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,133 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-logs')
export class CloudlyViewLogs extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>Logs</cloudly-sectionheading>
<dees-table
.heading1=${'Logs'}
.heading2=${'decoded in client'}
.data=${this.data.deployments}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,133 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-mails')
export class CloudlyViewMails extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>Mails</cloudly-sectionheading>
<dees-table
.heading1=${'Mails'}
.heading2=${'decoded in client'}
.data=${this.data.deployments}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,71 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-overview')
export class CloudlyViewOverview extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 8px 16px;
}
.clusterGrid {
display: grid;
grid-template-columns: ${cssManager.cssGridColumns(3, 8)};
grid-gap: 16px;
margin-bottom: 40px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>Overview</cloudly-sectionheading>
${this.data.clusters.length === 0 ? html`
You need to create at least one cluster to see an overview.
`: html``}
${this.data.clusters.map(
(clusterArg) => html`
<dees-label .label=${'cluster: ' + clusterArg.data.name}></dees-label>
<div class="clusterGrid">
<dees-chart-area .label=${'System Usage'}></dees-chart-area>
<dees-chart-area .label=${'Internet Traffic'}></dees-chart-area>
<dees-chart-area .label=${'Requests'}></dees-chart-area>
<dees-chart-area .label=${'WebSocket Connections'}></dees-chart-area>
<dees-chart-log class="services" .label=${'Deployed Services'}></dees-chart-log>
<dees-chart-log class="eventLog" .label=${'Event Log'}></dees-chart-log>
</div>
`
)}
`;
}
}

View File

@ -0,0 +1,133 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-s3')
export class CloudlyViewS3 extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>S3</cloudly-sectionheading>
<dees-table
.heading1=${'S3'}
.heading2=${'decoded in client'}
.data=${this.data.s3}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,173 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-secretbundles')
export class CloudlyViewSecretBundles extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>SecretBundles</cloudly-sectionheading>
<dees-table
.heading1=${'SecretBundles'}
.heading2=${'decoded in client'}
.data=${this.data.secretBundles}
.displayFunction=${(itemArg: plugins.interfaces.data.ISecretBundle) => {
return {
name: itemArg.data.name,
secretGroups: (() => {
const secretGroupIds = itemArg.data.includedSecretGroupIds;
let secretGroupNames: string[] = [];
for (const secretGroupId of secretGroupIds) {
const secretGroup = this.data.secretGroups.find(
(secretGroupArg) => secretGroupArg.id === secretGroupId
);
if (secretGroup) {
secretGroupNames.push(secretGroup.data.name);
}
}
return secretGroupNames.join(', ');
})(),
tags: html`<dees-chips
.selectionMode=${'none'}
.selectableChips=${itemArg.data.includedTags}
></dees-chips>`,
};
}}
.dataActions=${[
{
name: 'add SecretBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add SecretBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
{
name: 'edit',
iconName: 'edit',
type: ['doubleClick', 'contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Edit SecretBundle',
content: html`
<dees-form>
<dees-input-text .label=${'purpose'}></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'save', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,367 @@
import * as plugins from '../plugins.js';
import { DeesElement, customElement, html, state, css, cssManager } from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-secretsgroups')
export class CloudlyViewSecretGroups extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>SecretGroups</cloudly-sectionheading>
<dees-table
heading1="SecretGroups"
heading2="decoded in client"
.data=${this.data.secretGroups}
.displayFunction=${(secretGroup: plugins.interfaces.data.ISecretGroup) => {
return {
name: secretGroup.data.name,
priority: secretGroup.data.priority,
tags: html`<dees-chips
.selectionMode=${'none'}
.selectableChips=${secretGroup.data.tags}
></dees-chips>`,
key: secretGroup.data.key,
history: (() => {
const allHistory = [];
for (const environment in secretGroup.data.environments) {
allHistory.push(...secretGroup.data.environments[environment].history);
}
return allHistory.length;
})(),
};
}}
.dataActions=${[
{
name: 'add SecretGroup',
type: ['header', 'footer'],
iconName: 'plus',
actionFunc: async () => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: 'create new SecretGroup',
content: html`
<dees-form>
<dees-input-text
.label=${'name'}
.key=${'data.name'}
.value=${''}
></dees-input-text>
<dees-input-text
.label=${'description'}
.key=${'data.description'}
.value=${''}
></dees-input-text>
<dees-input-text
.label=${'Secret Key (data.key)'}
.key=${'data.key'}
.value=${''}
></dees-input-text>
<dees-table
.heading1=${'Environments'}
.heading2=${'keys need to be unique'}
key="environments"
.data=${[
{
environment: 'production',
value: '',
},
{
environment: 'staging',
value: '',
},
]}
.dataActions=${[
{
name: 'add environment',
iconName: 'plus',
type: ['footer'],
actionFunc: async (dataArg) => {
dataArg.table.data.push({
environment: 'new environment',
value: '',
});
dataArg.table.requestUpdate('data');
},
},
{
name: 'delete environment',
iconName: 'trash',
type: ['inRow'],
actionFunc: async (dataArg) => {
dataArg.table.data.splice(dataArg.table.data.indexOf(dataArg.item), 1);
dataArg.table.requestUpdate('data');
},
},
] as plugins.deesCatalog.ITableAction[]}
.editableFields=${['environment', 'value']}
></dees-table>
</dees-form>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'save',
action: async (modalArg) => {
const deesForm = modalArg.shadowRoot.querySelector('dees-form');
const formData = await deesForm.collectFormData();
console.log(`Prepare saving of data:`);
console.log(formData);
const environments: plugins.interfaces.data.ISecretGroup['data']['environments'] =
{};
for (const itemArg of formData['environments'] as any[]) {
environments[itemArg.environment] = {
value: itemArg.value,
history: [],
lastUpdated: Date.now(),
};
}
await appstate.dataState.dispatchAction(appstate.createSecretGroupAction, {
id: null,
data: {
name: formData['data.name'] as string,
description: formData['data.description'] as string,
key: formData['data.key'] as string,
environments,
tags: [],
},
});
await modalArg.destroy();
},
},
],
});
},
},
{
name: 'edit',
type: ['contextmenu', 'inRow', 'doubleClick'],
iconName: 'penToSquare',
actionFunc: async (
dataArg: plugins.deesCatalog.ITableActionDataArg<plugins.interfaces.data.ISecretGroup>
) => {
const environmentsArray: Array<
plugins.interfaces.data.ISecretGroup['data']['environments'][any] & {
environment: string;
}
> = [];
for (const environmentName of Object.keys(dataArg.item.data.environments)) {
environmentsArray.push({
environment: environmentName,
...dataArg.item.data.environments[environmentName],
});
}
await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Edit Secret',
content: html`
<dees-form>
<dees-input-text
.key=${'id'}
.disabled=${true}
.label=${'ID'}
.value=${dataArg.item.id}
></dees-input-text>
<dees-input-text
.key=${'data.name'}
.disabled=${false}
.label=${'name'}
.value=${dataArg.item.data.name}
></dees-input-text>
<dees-input-text
.key=${'data.description'}
.disabled=${false}
.label=${'description'}
.value=${dataArg.item.data.description}
></dees-input-text>
<dees-input-text
.key=${'data.key'}
.disabled=${false}
.label=${'key'}
.value=${dataArg.item.data.key}
></dees-input-text>
<dees-table
.key=${'environments'}
.heading1=${'Environments'}
.heading2=${'double-click to edit values'}
.data=${environmentsArray.map((itemArg) => {
return {
environment: itemArg.environment,
value: itemArg.value,
};
})}
.editableFields=${['environment', 'value']}
.dataActions=${[
{
name: 'delete',
iconName: 'trash',
type: ['inRow'],
actionFunc: async (actionDataArg) => {
actionDataArg.table.data.splice(
actionDataArg.table.data.indexOf(actionDataArg.item),
1
);
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
</dees-form>
`,
menuOptions: [
{
name: 'Cancel',
iconName: null,
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'Save',
iconName: null,
action: async (modalArg) => {
const data = await modalArg.shadowRoot
.querySelector('dees-form')
.collectFormData();
console.log(data);
const updatedSecretGroup: plugins.interfaces.data.ISecretGroup = {
id: dataArg.item.id,
data: {
name: data['data.name'] as string,
description: data['data.description'] as string,
key: data['data.key'] as string,
environments: {},
tags: dataArg.item.data.tags,
},
};
const environments: plugins.interfaces.data.ISecretGroup['data']['environments'] =
{};
for (const itemArg of data['environments'] as any[]) {
}
},
},
],
});
},
},
{
name: 'history',
iconName: 'clockRotateLeft',
type: ['contextmenu', 'inRow'],
actionFunc: async (
dataArg: plugins.deesCatalog.ITableActionDataArg<plugins.interfaces.data.ISecretGroup>
) => {
const historyArray: Array<{
environment: string;
value: string;
}> = [];
for (const environment of Object.keys(dataArg.item.data.environments)) {
for (const historyItem of dataArg.item.data.environments[environment].history) {
historyArray.push({
environment,
value: historyItem.value,
});
}
}
await plugins.deesCatalog.DeesModal.createAndShow({
heading: `history for ${dataArg.item.data.key}`,
content: html`
<dees-table
.data=${historyArray}
.dataActions=${[
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (
itemArg: plugins.deesCatalog.ITableActionDataArg<(typeof historyArray)[0]>
) => {
console.log('delete', itemArg);
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`,
menuOptions: [
{
name: 'close',
action: async (modalArg) => {
await modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (
itemArg: plugins.deesCatalog.ITableActionDataArg<plugins.interfaces.data.ISecretGroup>
) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ${itemArg.item.data.key}`,
content: html`
<div style="text-align:center">Do you really want to delete the secret?</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${itemArg.item.data.key}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
console.log(`Delete ${itemArg.item.id}`);
await appstate.dataState.dispatchAction(appstate.deleteSecretGroupAction, {
secretGroupId: itemArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

View File

@ -0,0 +1,133 @@
import * as plugins from '../plugins.js';
import {
DeesElement,
customElement,
html,
state,
css,
cssManager,
} from '@design.estate/dees-element';
import * as appstate from '../appstate.js';
@customElement('cloudly-view-services')
export class CloudlyViewServices extends DeesElement {
@state()
private data: appstate.IDataState = {
secretGroups: [],
secretBundles: [],
};
constructor() {
super();
const subecription = appstate.dataState
.select((stateArg) => stateArg)
.subscribe((dataArg) => {
this.data = dataArg;
});
this.rxSubscriptions.push(subecription);
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
margin: auto;
max-width: 1280px;
padding: 16px 16px;
}
`,
];
public render() {
return html`
<cloudly-sectionheading>Services</cloudly-sectionheading>
<dees-table
.heading1=${'Services'}
.heading2=${'decoded in client'}
.data=${this.data.services}
.displayFunction=${(itemArg: plugins.interfaces.data.ICluster) => {
return {
id: itemArg.id,
serverAmount: itemArg.data.servers.length,
};
}}
.dataActions=${[
{
name: 'add configBundle',
iconName: 'plus',
type: ['header', 'footer'],
actionFunc: async (dataActionArg) => {
const modal = await plugins.deesCatalog.DeesModal.createAndShow({
heading: 'Add ConfigBundle',
content: html`
<dees-form>
<dees-input-text .key=${'id'} .label=${'ID'} .value=${''}></dees-input-text>
<dees-input-text
.key=${'data.secretGroupIds'}
.label=${'secretGroupIds'}
.value=${''}
></dees-input-text>
<dees-input-text
.key=${'data.includedTags'}
.label=${'includedTags'}
.value=${''}
></dees-input-text>
</dees-form>
`,
menuOptions: [
{ name: 'create', action: async (modalArg) => {} },
{
name: 'cancel',
action: async (modalArg) => {
modalArg.destroy();
},
},
],
});
},
},
{
name: 'delete',
iconName: 'trash',
type: ['contextmenu', 'inRow'],
actionFunc: async (actionDataArg) => {
plugins.deesCatalog.DeesModal.createAndShow({
heading: `Delete ConfigBundle ${actionDataArg.item.id}`,
content: html`
<div style="text-align:center">
Do you really want to delete the ConfigBundle?
</div>
<div
style="font-size: 0.8em; color: red; text-align:center; padding: 16px; margin-top: 24px; border: 1px solid #444; font-family: Intel One Mono; font-size: 16px;"
>
${actionDataArg.item.id}
</div>
`,
menuOptions: [
{
name: 'cancel',
action: async (modalArg) => {
await modalArg.destroy();
},
},
{
name: 'delete',
action: async (modalArg) => {
appstate.dataState.dispatchAction(appstate.deleteSecretBundleAction, {
configBundleId: actionDataArg.item.id,
});
await modalArg.destroy();
},
},
],
});
},
},
] as plugins.deesCatalog.ITableAction[]}
></dees-table>
`;
}
}

4
ts_web/elements/index.ts Normal file
View File

@ -0,0 +1,4 @@
export * from './shared/index.js';
export * from './cloudly-dashboard.js';
export * from './cloudly-view-secretgroups.js';
export * from './cloudly-view-secretbundles.js';

View File

@ -0,0 +1,33 @@
import * as plugins from '../../plugins.js';
import {
customElement,
html,
DeesElement,
property,
type TemplateResult,
cssManager,
css,
unsafeCSS,
type CSSResult,
state,
} from '@design.estate/dees-element';
@customElement('cloudly-sectionheading')
export class CloudlySectionheading extends DeesElement {
public static styles = [
cssManager.defaultStyles,
css`
h1 {
font-family: 'Cal Sans';
letter-spacing: 0.025em;
}
`,
]
public render() {
return html`
<h1><slot></slot></h1>
`;
}
}

View File

@ -0,0 +1 @@
export * from './cloudly-sectionheading.js';