feat: 🎸 Create string formats component (#3191)

* feat: 🎸 Create string formats component

* Add missing copyright headers

* fix: 🐛 change to readonly

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-18458
This commit is contained in:
Lisbet Alvarez authored and Zhihe Li committed 2026-05-14 15:21:28 -04:00
1 parent d469f305de
commit 37de7e3480
6 files changed
+201 -6

No files matched your search

@@ -4,15 +4,25 @@
}}
<Rose::Form class='full-width' as |form|>
{{! TODO: Add responsive options to @colspan once we upgrade to HDS v6.0.0}}
<Hds::Layout::Grid @gap='32' as |LG|>
<LG.Item @colspan={{2}}>
<Hds::Layout::Grid
@columnWidth={{hash sm='100%' md='33.33%'}}
@gap='12'
as |LG|
>
<LG.Item @colspan={{hash sm=1 md=2}}>
{{! TODO: Add grants code editor. }}
</LG.Item>
<LG.Item @colspan={{1}}>
{{! TODO: Add string options and actions. }}
</LG.Item>
<Hds::Accordion @size='large' as |A|>
<A.Item>
<:toggle>{{t
'resources.role.edit-grants.string-formats.title_plural'
}}</:toggle>
<:content>
<GrantStringFormats />
</:content>
</A.Item>
</Hds::Accordion>
</Hds::Layout::Grid>
<form.actions class='margin-top-l'>
@@ -0,0 +1,63 @@
{{!
Copyright IBM Corp. 2021, 2026
SPDX-License-Identifier: BUSL-1.1
}}
<Hds::Form::Radio::Group
@name='string-formats'
{{on 'change' (set-from-event this 'selectedFormatType')}}
as |G|
>
<G.RadioField
@value={{this.stringFormatTypes.resourceType}}
checked={{eq this.selectedFormatType this.stringFormatTypes.resourceType}}
as |F|
>
<F.Label>{{t
'resources.role.edit-grants.string-formats.resource-type.label'
}}</F.Label>
<F.HelperText>{{t
'resources.role.edit-grants.string-formats.resource-type.help'
}}</F.HelperText>
</G.RadioField>
<G.RadioField
@value={{this.stringFormatTypes.resource}}
checked={{eq this.selectedFormatType this.stringFormatTypes.resource}}
as |F|
>
<F.Label>{{t
'resources.role.edit-grants.string-formats.resource.label'
}}</F.Label>
<F.HelperText>{{t
'resources.role.edit-grants.string-formats.resource.help'
}}</F.HelperText>
</G.RadioField>
<G.RadioField
@value={{this.stringFormatTypes.pinnedId}}
checked={{eq this.selectedFormatType this.stringFormatTypes.pinnedId}}
as |F|
>
<F.Label>{{t
'resources.role.edit-grants.string-formats.pinned-id.label'
}}</F.Label>
<F.HelperText>
{{t 'resources.role.edit-grants.string-formats.pinned-id.help'}}
<Hds::Link::Inline
@color='secondary'
@href={{doc-url 'role.grant-string-format.pinned-id'}}
>
{{t 'resources.role.edit-grants.string-formats.pinned-id.link'}}
</Hds::Link::Inline>
</F.HelperText>
</G.RadioField>
</Hds::Form::Radio::Group>
<Hds::Form::Textarea::Field
name='string-format'
readonly
@value={{this.stringFormat}}
@height='3.5rem'
as |F|
>
<F.Label>{{t 'resources.role.edit-grants.string-formats.title'}}</F.Label>
</Hds::Form::Textarea::Field>
@@ -0,0 +1,41 @@
/**
* Copyright IBM Corp. 2021, 2026
* SPDX-License-Identifier: BUSL-1.1
*/
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { service } from '@ember/service';
export default class GrantStringFormatsIndex extends Component {
// =services
@service intl;
// =attributes
stringFormatTypes = {
resourceType: 'resource-type',
resource: 'resource',
pinnedId: 'pinned-id',
};
stringFormats = {
[this.stringFormatTypes.resourceType]:
`type=<${this.intl.t('resources.role.edit-grants.string-formats.insert-resource-types')}>;actions=<${this.intl.t('resources.role.edit-grants.string-formats.insert-actions')}>`,
[this.stringFormatTypes.resource]:
`id=<${this.intl.t('resources.role.edit-grants.string-formats.insert-resource-ids')}>;actions=<${this.intl.t('resources.role.edit-grants.string-formats.insert-actions')}>`,
[this.stringFormatTypes.pinnedId]:
`id=<${this.intl.t('resources.role.edit-grants.string-formats.insert-id')}>;type=<${this.intl.t('resources.role.edit-grants.string-formats.insert-resource-types')}>;actions=<${this.intl.t('resources.role.edit-grants.string-formats.insert-actions')}>`,
};
@tracked selectedFormatType = this.stringFormatTypes.resourceType;
/**
* Returns the string format based on the selected format type.
* @type {string}
*/
get stringFormat() {
return this.stringFormats[this.selectedFormatType];
}
}
+2
View File
@@ -97,6 +97,8 @@ module.exports = function (environment) {
'role.add-principals':
'/tutorials/oss-administration/oss-manage-roles#create-a-role',
'role.add-grant-scopes': '/docs/commands/roles/add-grant-scopes',
'role.grant-string-format.pinned-id':
'/docs/rbac/permission-grant-formats#pinned-id',
session: '/docs/concepts/domain-model/sessions',
target: '/docs/concepts/domain-model/targets',
'target.new': '/docs/common-workflows/manage-targets',
@@ -0,0 +1,62 @@
/**
* Copyright IBM Corp. 2021, 2026
* SPDX-License-Identifier: BUSL-1.1
*/
import { module, test } from 'qunit';
import { setupRenderingTest } from 'admin/tests/helpers';
import { setupIntl } from 'ember-intl/test-support';
import { render, click } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module(
'Integration | Component | grant-string-formats/index',
function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks, 'en-us');
const RESOURCE_TYPE_OPTION = '[value="resource-type"]';
const RESOURCE_OPTION = '[value="resource"]';
const PINNED_ID_OPTION = '[value="pinned-id"]';
const STRING_FORMAT_FIELD = '[name="string-format"]';
test('it renders string format with resource type by default', async function (assert) {
await render(hbs`<GrantStringFormats />`);
assert.dom(RESOURCE_TYPE_OPTION).isChecked();
assert.dom(RESOURCE_OPTION).isNotChecked();
assert.dom(PINNED_ID_OPTION).isNotChecked();
assert
.dom(STRING_FORMAT_FIELD)
.hasValue('type=<insert resource types>;actions=<insert actions>');
});
test('it renders string format when type is changed to specific resource', async function (assert) {
await render(hbs`<GrantStringFormats />`);
await click(RESOURCE_OPTION);
assert.dom(RESOURCE_OPTION).isChecked();
assert.dom(RESOURCE_TYPE_OPTION).isNotChecked();
assert.dom(PINNED_ID_OPTION).isNotChecked();
assert
.dom(STRING_FORMAT_FIELD)
.hasValue('id=<insert resource ids>;actions=<insert actions>');
});
test('it renders string format when type is changed to pinned id', async function (assert) {
await render(hbs`<GrantStringFormats />`);
await click(PINNED_ID_OPTION);
assert.dom(PINNED_ID_OPTION).isChecked();
assert.dom(RESOURCE_TYPE_OPTION).isNotChecked();
assert.dom(RESOURCE_OPTION).isNotChecked();
assert
.dom(STRING_FORMAT_FIELD)
.hasValue(
'id=<insert id>;type=<insert resource types>;actions=<insert actions>',
);
});
},
);