mirror of
https://github.com/hashicorp/vault.git
synced 2026-06-11 01:42:06 -04:00
Merge remote-tracking branch 'remotes/from/ce/main'
Some checks are pending
build / setup (push) Waiting to run
build / Check ce/* Pull Requests (push) Blocked by required conditions
build / ui (push) Blocked by required conditions
build / artifacts-ce (push) Blocked by required conditions
build / artifacts-ent (push) Blocked by required conditions
build / hcp-setup (push) Waiting to run
build / hcp-image (push) Blocked by required conditions
build / test (push) Blocked by required conditions
build / test-hcp-image (push) Blocked by required conditions
build / completed-successfully (push) Blocked by required conditions
CI / setup (push) Waiting to run
CI / Run Autopilot upgrade tool (push) Blocked by required conditions
CI / Run Go tests (push) Blocked by required conditions
CI / Run Go tests tagged with testonly (push) Blocked by required conditions
CI / Run Go tests with data race detection (push) Blocked by required conditions
CI / Run Go tests with FIPS configuration (push) Blocked by required conditions
CI / Test UI (push) Blocked by required conditions
CI / tests-completed (push) Blocked by required conditions
Run linters / Setup (push) Waiting to run
Run linters / Deprecated functions (push) Blocked by required conditions
Run linters / Code checks (push) Blocked by required conditions
Run linters / Protobuf generate delta (push) Blocked by required conditions
Run linters / Format (push) Blocked by required conditions
Run linters / Semgrep (push) Waiting to run
Check Copywrite Headers / copywrite (push) Waiting to run
Security Scan / scan (push) Waiting to run
Some checks are pending
build / setup (push) Waiting to run
build / Check ce/* Pull Requests (push) Blocked by required conditions
build / ui (push) Blocked by required conditions
build / artifacts-ce (push) Blocked by required conditions
build / artifacts-ent (push) Blocked by required conditions
build / hcp-setup (push) Waiting to run
build / hcp-image (push) Blocked by required conditions
build / test (push) Blocked by required conditions
build / test-hcp-image (push) Blocked by required conditions
build / completed-successfully (push) Blocked by required conditions
CI / setup (push) Waiting to run
CI / Run Autopilot upgrade tool (push) Blocked by required conditions
CI / Run Go tests (push) Blocked by required conditions
CI / Run Go tests tagged with testonly (push) Blocked by required conditions
CI / Run Go tests with data race detection (push) Blocked by required conditions
CI / Run Go tests with FIPS configuration (push) Blocked by required conditions
CI / Test UI (push) Blocked by required conditions
CI / tests-completed (push) Blocked by required conditions
Run linters / Setup (push) Waiting to run
Run linters / Deprecated functions (push) Blocked by required conditions
Run linters / Code checks (push) Blocked by required conditions
Run linters / Protobuf generate delta (push) Blocked by required conditions
Run linters / Format (push) Blocked by required conditions
Run linters / Semgrep (push) Waiting to run
Check Copywrite Headers / copywrite (push) Waiting to run
Security Scan / scan (push) Waiting to run
This commit is contained in:
commit
faa255ff4a
7 changed files with 257 additions and 37 deletions
|
|
@ -40,7 +40,7 @@
|
|||
</Hds::Text::Body>
|
||||
<Hds::Card::Container @hasBorder={{true}} class="has-top-padding-m has-bottom-padding-m side-padding-24">
|
||||
{{#if (eq this.creationMethodChoice this.methods.APICLI)}}
|
||||
<CodeGenerator::AutomationSnippets @customTabs={{this.customTabs}} @onTabChange={{fn (mut this.selectedTabIdx)}} />
|
||||
<CodeGenerator::AutomationSnippets @customTabs={{this.customTabs}} @onTabChange={{this.onTabChange}} />
|
||||
{{else}}
|
||||
<Hds::CodeBlock
|
||||
@language="hcl"
|
||||
|
|
|
|||
|
|
@ -6,13 +6,14 @@
|
|||
import { action } from '@ember/object';
|
||||
import { service } from '@ember/service';
|
||||
import Component from '@glimmer/component';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { generateCurlCommand } from 'core/utils/code-generators/api';
|
||||
import { generateCliWriteCommand } from 'core/utils/code-generators/cli';
|
||||
import { terraformGenericResourceTemplate } from 'core/utils/code-generators/terraform';
|
||||
import { CreationMethod } from 'vault/utils/constants/snippet';
|
||||
|
||||
import type V2Form from 'vault/forms/v2/v2-form';
|
||||
import type NamespaceService from 'vault/services/namespace';
|
||||
import type SnippetService from 'vault/services/snippet';
|
||||
|
||||
interface Args {
|
||||
form: V2Form;
|
||||
|
|
@ -21,12 +22,6 @@ interface Args {
|
|||
onApply: () => void;
|
||||
}
|
||||
|
||||
export enum CreationMethod {
|
||||
TERRAFORM = 'Terraform automation',
|
||||
APICLI = 'API/CLI',
|
||||
UI = 'Vault UI workflow',
|
||||
}
|
||||
|
||||
interface CreationMethodChoice {
|
||||
icon: string;
|
||||
label: CreationMethod;
|
||||
|
|
@ -36,9 +31,7 @@ interface CreationMethodChoice {
|
|||
|
||||
export default class FormV2Apply extends Component<Args> {
|
||||
@service declare readonly namespace: NamespaceService;
|
||||
|
||||
@tracked creationMethodChoice = CreationMethod.TERRAFORM;
|
||||
@tracked selectedTabIdx = 0;
|
||||
@service declare readonly snippet: SnippetService;
|
||||
|
||||
methods = CreationMethod;
|
||||
|
||||
|
|
@ -64,6 +57,14 @@ export default class FormV2Apply extends Component<Args> {
|
|||
},
|
||||
];
|
||||
|
||||
get creationMethodChoice() {
|
||||
return this.snippet.creationMethodChoice;
|
||||
}
|
||||
|
||||
get selectedTabIdx() {
|
||||
return this.snippet.selectedTabIdx;
|
||||
}
|
||||
|
||||
get requestData() {
|
||||
const { payload } = this.args.form;
|
||||
// payload has a top level key -- we need the actual data object for creating the snippets
|
||||
|
|
@ -93,6 +94,11 @@ export default class FormV2Apply extends Component<Args> {
|
|||
|
||||
@action
|
||||
onChange(choice: CreationMethodChoice) {
|
||||
this.creationMethodChoice = choice.label;
|
||||
this.snippet.setCreationMethod(choice.label, this.tfSnippet, this.customTabs);
|
||||
}
|
||||
|
||||
@action
|
||||
onTabChange(idx: number) {
|
||||
this.snippet.setSelectedTab(idx, this.tfSnippet, this.customTabs);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { action } from '@ember/object';
|
|||
import { tracked } from '@glimmer/tracking';
|
||||
import Component from '@glimmer/component';
|
||||
import { SecurityPolicy } from 'vault/components/wizard/namespaces/step-1';
|
||||
import { CreationMethod } from 'vault/components/wizard/namespaces/step-3';
|
||||
import { CreationMethod } from 'vault/utils/constants/snippet';
|
||||
import { WIZARD_ID_MAP } from 'vault/utils/constants/wizard';
|
||||
|
||||
import type ApiService from 'vault/services/api';
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
import Component from '@glimmer/component';
|
||||
import { service } from '@ember/service';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { SecurityPolicy } from './step-1';
|
||||
import type NamespaceService from 'vault/services/namespace';
|
||||
import type SnippetService from 'vault/services/snippet';
|
||||
import { CreationMethod } from 'vault/utils/constants/snippet';
|
||||
import {
|
||||
generateApiSnippet,
|
||||
generateCliSnippet,
|
||||
|
|
@ -25,12 +26,6 @@ interface Args {
|
|||
updateWizardState: (key: string, value: unknown) => void;
|
||||
}
|
||||
|
||||
export enum CreationMethod {
|
||||
TERRAFORM = 'Terraform automation',
|
||||
APICLI = 'API/CLI',
|
||||
UI = 'Vault UI workflow',
|
||||
}
|
||||
|
||||
interface CreationMethodChoice {
|
||||
icon: string;
|
||||
label: CreationMethod;
|
||||
|
|
@ -40,15 +35,14 @@ interface CreationMethodChoice {
|
|||
|
||||
export default class WizardNamespacesStep3 extends Component<Args> {
|
||||
@service declare readonly namespace: NamespaceService;
|
||||
@tracked creationMethodChoice: CreationMethod;
|
||||
@tracked selectedTabIdx = 0;
|
||||
@service declare readonly snippet: SnippetService;
|
||||
|
||||
methods = CreationMethod;
|
||||
policy = SecurityPolicy;
|
||||
|
||||
constructor(owner: unknown, args: Args) {
|
||||
super(owner, args);
|
||||
this.creationMethodChoice = this.args.wizardState.creationMethod || CreationMethod.TERRAFORM;
|
||||
this.snippet.reset(this.args.wizardState.creationMethod || CreationMethod.TERRAFORM);
|
||||
}
|
||||
|
||||
creationMethodOptions: CreationMethodChoice[] = [
|
||||
|
|
@ -73,6 +67,14 @@ export default class WizardNamespacesStep3 extends Component<Args> {
|
|||
},
|
||||
];
|
||||
|
||||
get creationMethodChoice() {
|
||||
return this.snippet.creationMethodChoice;
|
||||
}
|
||||
|
||||
get selectedTabIdx() {
|
||||
return this.snippet.selectedTabIdx;
|
||||
}
|
||||
|
||||
get tfSnippet() {
|
||||
const { namespacePaths } = this.args.wizardState;
|
||||
return generateTerraformSnippet(namespacePaths, this.namespace.path);
|
||||
|
|
@ -96,28 +98,20 @@ export default class WizardNamespacesStep3 extends Component<Args> {
|
|||
|
||||
@action
|
||||
onChange(choice: CreationMethodChoice) {
|
||||
this.creationMethodChoice = choice.label;
|
||||
this.snippet.setCreationMethod(choice.label, this.tfSnippet, this.customTabs);
|
||||
this.args.updateWizardState('creationMethod', choice.label);
|
||||
// Update the code snippet whenever the creation method changes
|
||||
this.updateCodeSnippet();
|
||||
this.args.updateWizardState('codeSnippet', this.snippet.codeSnippet);
|
||||
}
|
||||
|
||||
@action
|
||||
onTabChange(idx: number) {
|
||||
this.selectedTabIdx = idx;
|
||||
|
||||
// Update the code snippet whenever the tab changes
|
||||
this.updateCodeSnippet();
|
||||
this.snippet.setSelectedTab(idx, this.tfSnippet, this.customTabs);
|
||||
this.args.updateWizardState('codeSnippet', this.snippet.codeSnippet);
|
||||
}
|
||||
|
||||
// Update the wizard state with the current code snippet
|
||||
@action
|
||||
updateCodeSnippet() {
|
||||
if (this.creationMethodChoice === CreationMethod.TERRAFORM) {
|
||||
this.args.updateWizardState('codeSnippet', this.tfSnippet);
|
||||
} else if (this.creationMethodChoice === CreationMethod.APICLI) {
|
||||
const snippet = this.customTabs[this.selectedTabIdx]?.snippet;
|
||||
this.args.updateWizardState('codeSnippet', snippet);
|
||||
}
|
||||
this.snippet.persistSnippet(this.tfSnippet, this.customTabs);
|
||||
this.args.updateWizardState('codeSnippet', this.snippet.codeSnippet);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
50
ui/app/services/snippet.ts
Normal file
50
ui/app/services/snippet.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Copyright IBM Corp. 2016, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import Service from '@ember/service';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { CreationMethod } from 'vault/utils/constants/snippet';
|
||||
|
||||
export interface SnippetTab {
|
||||
key: string;
|
||||
label: string;
|
||||
snippet: string;
|
||||
}
|
||||
|
||||
export default class SnippetService extends Service {
|
||||
@tracked selectedTabIdx = 0;
|
||||
@tracked creationMethodChoice: CreationMethod = CreationMethod.TERRAFORM;
|
||||
@tracked codeSnippet: string | null = null;
|
||||
|
||||
@action
|
||||
setCreationMethod(choice: CreationMethod, tfSnippet: string, customTabs: SnippetTab[]) {
|
||||
this.creationMethodChoice = choice;
|
||||
this.persistSnippet(tfSnippet, customTabs);
|
||||
}
|
||||
|
||||
@action
|
||||
setSelectedTab(idx: number, tfSnippet: string, customTabs: SnippetTab[]) {
|
||||
this.selectedTabIdx = idx;
|
||||
this.persistSnippet(tfSnippet, customTabs);
|
||||
}
|
||||
|
||||
@action
|
||||
persistSnippet(tfSnippet: string, customTabs: SnippetTab[]) {
|
||||
if (this.creationMethodChoice === CreationMethod.TERRAFORM) {
|
||||
this.codeSnippet = tfSnippet;
|
||||
} else if (this.creationMethodChoice === CreationMethod.APICLI) {
|
||||
this.codeSnippet = customTabs[this.selectedTabIdx]?.snippet ?? null;
|
||||
} else {
|
||||
this.codeSnippet = null;
|
||||
}
|
||||
}
|
||||
|
||||
reset(initialChoice: CreationMethod = CreationMethod.TERRAFORM) {
|
||||
this.selectedTabIdx = 0;
|
||||
this.creationMethodChoice = initialChoice;
|
||||
this.codeSnippet = null;
|
||||
}
|
||||
}
|
||||
10
ui/app/utils/constants/snippet.ts
Normal file
10
ui/app/utils/constants/snippet.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Copyright IBM Corp. 2016, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
export enum CreationMethod {
|
||||
TERRAFORM = 'Terraform automation',
|
||||
APICLI = 'API/CLI',
|
||||
UI = 'Vault UI workflow',
|
||||
}
|
||||
160
ui/tests/unit/services/snippet-test.js
Normal file
160
ui/tests/unit/services/snippet-test.js
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
* Copyright IBM Corp. 2016, 2026
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupTest } from 'ember-qunit';
|
||||
import { CreationMethod } from 'vault/utils/constants/snippet';
|
||||
|
||||
const TF_SNIPPET = 'resource "vault_mount" "example" {}';
|
||||
const API_SNIPPET = 'curl --header "X-Vault-Token: $VAULT_TOKEN" $VAULT_ADDR/v1/test';
|
||||
const CLI_SNIPPET = 'vault write test/path key=value';
|
||||
|
||||
const CUSTOM_TABS = [
|
||||
{ key: 'api', label: 'API', snippet: API_SNIPPET },
|
||||
{ key: 'cli', label: 'CLI', snippet: CLI_SNIPPET },
|
||||
];
|
||||
|
||||
module('Unit | Service | snippet', function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.service = this.owner.lookup('service:snippet');
|
||||
});
|
||||
|
||||
module('default state', function () {
|
||||
test('selectedTabIdx defaults to 0', function (assert) {
|
||||
assert.strictEqual(this.service.selectedTabIdx, 0);
|
||||
});
|
||||
|
||||
test('creationMethodChoice defaults to TERRAFORM', function (assert) {
|
||||
assert.strictEqual(this.service.creationMethodChoice, CreationMethod.TERRAFORM);
|
||||
});
|
||||
|
||||
test('codeSnippet defaults to null', function (assert) {
|
||||
assert.strictEqual(this.service.codeSnippet, null);
|
||||
});
|
||||
});
|
||||
|
||||
module('#reset', function () {
|
||||
test('resets service state to defaults', function (assert) {
|
||||
this.service.selectedTabIdx = 1;
|
||||
this.service.creationMethodChoice = CreationMethod.APICLI;
|
||||
this.service.codeSnippet = TF_SNIPPET;
|
||||
|
||||
this.service.reset();
|
||||
|
||||
assert.strictEqual(this.service.selectedTabIdx, 0);
|
||||
assert.strictEqual(this.service.creationMethodChoice, CreationMethod.TERRAFORM);
|
||||
assert.strictEqual(this.service.codeSnippet, null);
|
||||
});
|
||||
|
||||
test('accepts an initial creation method', function (assert) {
|
||||
this.service.reset(CreationMethod.APICLI);
|
||||
|
||||
assert.strictEqual(this.service.creationMethodChoice, CreationMethod.APICLI);
|
||||
assert.strictEqual(this.service.selectedTabIdx, 0);
|
||||
assert.strictEqual(this.service.codeSnippet, null);
|
||||
});
|
||||
});
|
||||
|
||||
module('#persistSnippet', function () {
|
||||
test('sets codeSnippet to tfSnippet when method is TERRAFORM', function (assert) {
|
||||
this.service.creationMethodChoice = CreationMethod.TERRAFORM;
|
||||
|
||||
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, TF_SNIPPET);
|
||||
});
|
||||
|
||||
test('sets codeSnippet to the selected tab snippet when method is APICLI', function (assert) {
|
||||
this.service.creationMethodChoice = CreationMethod.APICLI;
|
||||
this.service.selectedTabIdx = 0;
|
||||
|
||||
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, API_SNIPPET);
|
||||
});
|
||||
|
||||
test('sets codeSnippet to the CLI tab when selectedTabIdx is 1', function (assert) {
|
||||
this.service.creationMethodChoice = CreationMethod.APICLI;
|
||||
this.service.selectedTabIdx = 1;
|
||||
|
||||
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, CLI_SNIPPET);
|
||||
});
|
||||
|
||||
test('sets codeSnippet to null when method is UI', function (assert) {
|
||||
this.service.creationMethodChoice = CreationMethod.UI;
|
||||
|
||||
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, null);
|
||||
});
|
||||
|
||||
test('sets codeSnippet to null when APICLI tab index is out of range', function (assert) {
|
||||
this.service.creationMethodChoice = CreationMethod.APICLI;
|
||||
this.service.selectedTabIdx = 99;
|
||||
|
||||
this.service.persistSnippet(TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, null);
|
||||
});
|
||||
});
|
||||
|
||||
module('#setCreationMethod', function () {
|
||||
test('updates creationMethodChoice', function (assert) {
|
||||
this.service.setCreationMethod(CreationMethod.APICLI, TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.creationMethodChoice, CreationMethod.APICLI);
|
||||
});
|
||||
|
||||
test('persists the correct snippet after changing to TERRAFORM', function (assert) {
|
||||
this.service.setCreationMethod(CreationMethod.TERRAFORM, TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, TF_SNIPPET);
|
||||
});
|
||||
|
||||
test('persists the correct snippet after changing to APICLI', function (assert) {
|
||||
this.service.selectedTabIdx = 0;
|
||||
this.service.setCreationMethod(CreationMethod.APICLI, TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, API_SNIPPET);
|
||||
});
|
||||
|
||||
test('clears codeSnippet when changing to UI', function (assert) {
|
||||
this.service.codeSnippet = TF_SNIPPET;
|
||||
this.service.setCreationMethod(CreationMethod.UI, TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, null);
|
||||
});
|
||||
});
|
||||
|
||||
module('#setSelectedTab', function () {
|
||||
test('updates selectedTabIdx', function (assert) {
|
||||
this.service.creationMethodChoice = CreationMethod.APICLI;
|
||||
|
||||
this.service.setSelectedTab(1, TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.selectedTabIdx, 1);
|
||||
});
|
||||
|
||||
test('persists the snippet for the newly selected tab', function (assert) {
|
||||
this.service.creationMethodChoice = CreationMethod.APICLI;
|
||||
|
||||
this.service.setSelectedTab(1, TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, CLI_SNIPPET);
|
||||
});
|
||||
|
||||
test('persists tfSnippet if method is still TERRAFORM when tab changes', function (assert) {
|
||||
this.service.creationMethodChoice = CreationMethod.TERRAFORM;
|
||||
|
||||
this.service.setSelectedTab(1, TF_SNIPPET, CUSTOM_TABS);
|
||||
|
||||
assert.strictEqual(this.service.codeSnippet, TF_SNIPPET);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in a new issue