- Implemented CloudlyViewSettings component for managing cloud provider settings including Hetzner, Cloudflare, AWS, DigitalOcean, Azure, and Google Cloud. - Added functionality to load, save, and test connections for each provider. - Enhanced UI with loading states and success/error notifications. feat: Create tasks view with execution history - Developed CloudlyViewTasks component to display and manage tasks and their executions. - Integrated auto-refresh functionality for task executions. - Added filtering and searching capabilities for tasks. feat: Implement execution details and task panel components - Created CloudlyExecutionDetails component to show detailed information about task executions including logs and metrics. - Developed CloudlyTaskPanel component to display individual tasks with execution status and actions to run or cancel tasks. feat: Utility functions for formatting and categorization - Added utility functions for formatting dates, durations, and cron expressions. - Implemented functions to retrieve category icons and hues for task categorization.
78 lines
7.9 KiB
TypeScript
78 lines
7.9 KiB
TypeScript
import * as plugins from '../../../plugins.js';
|
|
import * as shared from '../../shared/index.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 = {} as any;
|
|
|
|
constructor() {
|
|
super();
|
|
const subscription = appstate.dataState.select((stateArg) => stateArg).subscribe((dataArg) => { this.data = dataArg; });
|
|
this.rxSubscriptions.push(subscription);
|
|
}
|
|
|
|
public static styles = [ cssManager.defaultStyles, shared.viewHostCss, css`` ];
|
|
|
|
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: any) => { dataArg.table.data.push({ environment: 'new environment', value: '' }); dataArg.table.requestUpdate('data'); } }, { name: 'delete environment', iconName: 'trash', type: ['inRow'], actionFunc: async (dataArg: any) => { 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: any) => { await modalArg.destroy(); } }, { name: 'save', action: async (modalArg: any) => { const deesForm = modalArg.shadowRoot.querySelector('dees-form'); const formData = await deesForm.collectFormData(); 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) => ({ environment: itemArg.environment, value: itemArg.value, }))} .editableFields=${['environment', 'value']} .dataActions=${[{ name: 'delete', iconName: 'trash', type: ['inRow'], actionFunc: async (actionDataArg: any) => { 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: any) => { await modalArg.destroy(); } }, { name: 'Save', iconName: null, action: async (modalArg: any) => { const data = await modalArg.shadowRoot.querySelector('dees-form').collectFormData(); console.log(data); } } ] });
|
|
} },
|
|
{ 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: any) => { 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: any) => { await modalArg.destroy(); } }, { name: 'delete', action: async (modalArg: any) => { await appstate.dataState.dispatchAction(appstate.deleteSecretGroupAction, { secretGroupId: itemArg.item.id, }); await modalArg.destroy(); } } ] });
|
|
} },
|
|
] as plugins.deesCatalog.ITableAction[]}
|
|
></dees-table>
|
|
`;
|
|
}
|
|
}
|
|
|
|
declare global { interface HTMLElementTagNameMap { 'cloudly-view-secretsgroups': CloudlyViewSecretGroups; } }
|
|
|