import * as plugins from '../../../plugins.js'; import * as appstate from '../../../appstate.js'; import { viewHostCss } from '../../shared/index.js'; import { DeesElement, customElement, html, state, css, cssManager, type TemplateResult, } from '@design.estate/dees-element'; @customElement('gitops-view-secrets') export class GitopsViewSecrets extends DeesElement { @state() accessor connectionsState: appstate.IConnectionsState = { connections: [], activeConnectionId: null, }; @state() accessor dataState: appstate.IDataState = { projects: [], groups: [], secrets: [], pipelines: [], pipelineJobs: [], currentJobLog: '', }; @state() accessor selectedConnectionId: string = ''; @state() accessor selectedScope: 'project' | 'group' = 'project'; @state() accessor selectedScopeId: string = ''; private _autoRefreshHandler: () => void; constructor() { super(); const connSub = appstate.connectionsStatePart .select((s) => s) .subscribe((s) => { this.connectionsState = s; }); this.rxSubscriptions.push(connSub); const dataSub = appstate.dataStatePart .select((s) => s) .subscribe((s) => { this.dataState = s; }); this.rxSubscriptions.push(dataSub); this._autoRefreshHandler = () => this.handleAutoRefresh(); document.addEventListener('gitops-auto-refresh', this._autoRefreshHandler); } public override disconnectedCallback() { super.disconnectedCallback(); document.removeEventListener('gitops-auto-refresh', this._autoRefreshHandler); } private handleAutoRefresh(): void { this.loadSecrets(); } public static styles = [ cssManager.defaultStyles, viewHostCss, ]; public render(): TemplateResult { const connectionOptions = this.connectionsState.connections.map((c) => ({ option: `${c.name} (${c.providerType})`, key: c.id, })); const scopeOptions = [ { option: 'Project', key: 'project' }, { option: 'Group', key: 'group' }, ]; const entityOptions = this.selectedScope === 'project' ? this.dataState.projects.map((p) => ({ option: p.fullPath || p.name, key: p.id })) : this.dataState.groups.map((g) => ({ option: g.fullPath || g.name, key: g.id })); return html`
Secrets
Manage CI/CD secrets and variables
o.key === this.selectedConnectionId) || connectionOptions[0]} @selectedOption=${(e: CustomEvent) => { this.selectedConnectionId = e.detail.key; this.loadEntities(); }} > o.key === this.selectedScope)} @selectedOption=${(e: CustomEvent) => { this.selectedScope = e.detail.key as 'project' | 'group'; this.loadEntities(); }} > o.key === this.selectedScopeId) || entityOptions[0]} @selectedOption=${(e: CustomEvent) => { this.selectedScopeId = e.detail.key; this.loadSecrets(); }} > this.addSecret()}>Add Secret this.loadSecrets()}>Refresh
({ Key: item.key, Value: item.masked ? '******' : item.value, Protected: item.protected ? 'Yes' : 'No', Environment: item.environment || '*', })} .dataActions=${[ { name: 'Edit', iconName: 'lucide:edit', action: async (item: any) => { await this.editSecret(item); }, }, { name: 'Delete', iconName: 'lucide:trash2', action: async (item: any) => { await appstate.dataStatePart.dispatchAction(appstate.deleteSecretAction, { connectionId: this.selectedConnectionId, scope: this.selectedScope, scopeId: this.selectedScopeId, key: item.key, }); }, }, ]} > `; } async firstUpdated() { await appstate.connectionsStatePart.dispatchAction(appstate.fetchConnectionsAction, null); const conns = appstate.connectionsStatePart.getState().connections; if (conns.length > 0 && !this.selectedConnectionId) { this.selectedConnectionId = conns[0].id; await this.loadEntities(); } } private async loadEntities() { if (!this.selectedConnectionId) return; if (this.selectedScope === 'project') { await appstate.dataStatePart.dispatchAction(appstate.fetchProjectsAction, { connectionId: this.selectedConnectionId, }); } else { await appstate.dataStatePart.dispatchAction(appstate.fetchGroupsAction, { connectionId: this.selectedConnectionId, }); } } private async loadSecrets() { if (!this.selectedConnectionId || !this.selectedScopeId) return; await appstate.dataStatePart.dispatchAction(appstate.fetchSecretsAction, { connectionId: this.selectedConnectionId, scope: this.selectedScope, scopeId: this.selectedScopeId, }); } private async addSecret() { await plugins.deesCatalog.DeesModal.createAndShow({ heading: 'Add Secret', content: html`
`, menuOptions: [ { name: 'Cancel', action: async (modal: any) => { modal.destroy(); } }, { name: 'Create', action: async (modal: any) => { const inputs = modal.shadowRoot.querySelectorAll('dees-input-text'); const data: any = {}; for (const input of inputs) { data[input.key] = input.value || ''; } await appstate.dataStatePart.dispatchAction(appstate.createSecretAction, { connectionId: this.selectedConnectionId, scope: this.selectedScope, scopeId: this.selectedScopeId, key: data.key, value: data.value, }); modal.destroy(); }, }, ], }); } private async editSecret(item: any) { await plugins.deesCatalog.DeesModal.createAndShow({ heading: `Edit Secret: ${item.key}`, content: html`
`, menuOptions: [ { name: 'Cancel', action: async (modal: any) => { modal.destroy(); } }, { name: 'Update', action: async (modal: any) => { const input = modal.shadowRoot.querySelector('dees-input-text'); await appstate.dataStatePart.dispatchAction(appstate.updateSecretAction, { connectionId: this.selectedConnectionId, scope: this.selectedScope, scopeId: this.selectedScopeId, key: item.key, value: input?.value || '', }); modal.destroy(); }, }, ], }); } }