Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions pages/collection-preferences/content-display-groups.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useState } from 'react';

import Box from '~components/box';
import CollectionPreferences, { CollectionPreferencesProps } from '~components/collection-preferences';
import SpaceBetween from '~components/space-between';

import { contentDisplayPreferenceI18nStrings } from '../common/i18n-strings';
import {
baseProperties,
contentDisplayGroups,
groupedContentDisplay,
groupedContentDisplayOptions,
} from './shared-configs';

export default function ContentDisplayGroupsPage() {
const [preferences, setPreferences] = useState<CollectionPreferencesProps.Preferences>({
contentDisplay: groupedContentDisplay,
});

return (
<SpaceBetween size="l">
<h1>Content Display with Groups</h1>

<CollectionPreferences
{...baseProperties}
preferences={preferences}
onConfirm={({ detail }) => setPreferences(detail)}
contentDisplayPreference={{
title: 'Column preferences',
description: 'Customize column visibility and order.',
options: groupedContentDisplayOptions,
groups: contentDisplayGroups,
enableColumnFiltering: true,
...contentDisplayPreferenceI18nStrings,
}}
/>

<Box variant="h2">Current preferences.contentDisplay</Box>
<pre
tabIndex={0}
style={{ background: '#f4f4f4', padding: '12px', borderRadius: '4px', overflow: 'auto', maxHeight: '400px' }}
>
{JSON.stringify(preferences.contentDisplay, null, 2)}
</pre>
</SpaceBetween>
);
}
53 changes: 53 additions & 0 deletions pages/collection-preferences/shared-configs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,56 @@ export const customPreference = (customState: boolean) => (
View as
</Checkbox>
);

export const groupedContentDisplayOptions: CollectionPreferencesProps.ContentDisplayOption[] = [
{ id: 'id', label: 'Instance ID', alwaysVisible: true },
{ id: 'name', label: 'Name' },
{ id: 'type', label: 'Instance type' },
{ id: 'az', label: 'Availability zone' },
{ id: 'state', label: 'State' },
{ id: 'cpu', label: 'CPU (%)' },
{ id: 'memory', label: 'Memory (%)' },
{ id: 'netIn', label: 'Network in (MB/s)' },
{ id: 'netOut', label: 'Network out (MB/s)' },
{ id: 'cost', label: 'Monthly cost ($)' },
];

export const contentDisplayGroups: CollectionPreferencesProps.ContentDisplayOptionGroup[] = [
{ id: 'config', label: 'Configuration' },
{ id: 'performance', label: 'Performance' },
{ id: 'network', label: 'Network' },
];

export const groupedContentDisplay: CollectionPreferencesProps.ContentDisplayItem[] = [
{ id: 'id', visible: true },
{ id: 'name', visible: true },
{
type: 'group',
id: 'config',
visible: true,
children: [
{ id: 'type', visible: true },
{ id: 'az', visible: true },
{ id: 'state', visible: true },
],
},
{
type: 'group',
id: 'performance',
visible: true,
children: [
{ id: 'cpu', visible: true },
{ id: 'memory', visible: true },
],
},
{
type: 'group',
id: 'network',
visible: true,
children: [
{ id: 'netIn', visible: true },
{ id: 'netOut', visible: true },
],
},
{ id: 'cost', visible: true },
];
116 changes: 109 additions & 7 deletions src/__tests__/snapshot-tests/__snapshots__/documenter.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8916,6 +8916,9 @@ It contains the following:
- \`title\` (string) - Specifies the text displayed at the top of the preference.
- \`description\` (string) - Specifies the description displayed below the title.
- \`options\` - Specifies an array of options for reordering and visible content selection.
- \`groups\` - (Optional) Specifies an array of column group definitions for multi-level content display. Each group contains:
- \`id\` (string) - A unique identifier for the group.
- \`label\` (string) - The text displayed as the group label.
- \`enableColumnFiltering\` (boolean) - Adds a columns filter.
- \`liveAnnouncementDndStarted\` ((position: number, total: number) => string) - (Optional) Adds a message to be announced by screen readers when an option is picked.
- \`liveAnnouncementDndDiscarded\` (string) - (Optional) Adds a message to be announced by screen readers when a reordering action is canceled.
Expand All @@ -8929,7 +8932,17 @@ Each option contains the following:
- \`label\` (string) - Specifies a short description of the content.
- \`alwaysVisible\` (boolean) - (Optional) Determines whether the visibility is always on and therefore cannot be toggled. This is set to \`false\` by default.

You must provide an ordered list of the items to display in the \`preferences.contentDisplay\` property.",
You must provide an ordered list of the items to display in the \`preferences.contentDisplay\` property.
Each content display item is one of the following:
- \`ContentDisplayColumn\` - Represents a single column.
- \`type\` ('column') - (Optional) Identifies the entry as a column. Defaults to \`'column'\` when omitted.
- \`id\` (string) - The column identifier.
- \`visible\` (boolean) - Whether the column is visible.
- \`ContentDisplayGroup\` - Represents a column group.
- \`type\` ('group') - Identifies the entry as a group.
- \`id\` (string) - The group identifier.
- \`visible\` (boolean) - Whether the group is visible.
- \`children\` (ReadonlyArray<ContentDisplayItem>) - The columns or nested groups within this group.",
"i18nTag": true,
"inlineType": {
"name": "CollectionPreferencesProps.ContentDisplayPreference",
Expand All @@ -8954,6 +8967,11 @@ You must provide an ordered list of the items to display in the \`preferences.co
"optional": true,
"type": "boolean",
},
{
"name": "groups",
"optional": true,
"type": "ReadonlyArray<CollectionPreferencesProps.ContentDisplayOptionGroup>",
},
{
"inlineType": {
"name": "CollectionPreferencesProps.ContentDisplayPreferenceI18nStrings",
Expand Down Expand Up @@ -37338,9 +37356,23 @@ Returns the current value of the input.",
},
},
{
"description": "Returns options that the user can reorder.",
"description": "Returns the top-level items in the preference list.

For tables **without** column grouping this returns all column options.
For tables **with** column grouping this returns the top-level entries only
(which are group items). Use \`.findChildrenOptions()\` on a group item to
access the leaf columns nested within it.",
"name": "findOptions",
"parameters": [],
"parameters": [
{
"defaultValue": "{}",
"flags": {
"isOptional": false,
},
"name": "option",
"typeName": "{ group?: boolean | undefined; }",
},
],
"returnType": {
"isNullable": false,
"name": "Array",
Expand Down Expand Up @@ -37379,6 +37411,33 @@ Returns the current value of the input.",
},
{
"methods": [
{
"description": "Returns all child option items nested under this item when it is a group.
Returns \`null\` when this item is a leaf column (has no nested children).

The children are the leaf-level \`ContentDisplayOptionWrapper\`s inside the group's
nested \`InternalList\` — i.e. they already carry a drag handle and visibility toggle.",
"name": "findChildrenOptions",
"parameters": [
{
"defaultValue": "{}",
"flags": {
"isOptional": false,
},
"name": "option",
"typeName": "{ group?: boolean | undefined; }",
},
],
"returnType": {
"isNullable": true,
"name": "Array",
"typeArguments": [
{
"name": "ContentDisplayOptionWrapper",
},
],
},
},
{
"description": "Returns the drag handle for the option item.",
"name": "findDragHandle",
Expand Down Expand Up @@ -37408,7 +37467,8 @@ Returns the current value of the input.",
},
},
{
"description": "Returns the visibility toggle for the option item.",
"description": "Returns the visibility toggle for the option item.
Note that, despite its typings, this may return null for group items since groups do not have a visibility toggle.",
"name": "findVisibilityToggle",
"parameters": [],
"returnType": {
Expand Down Expand Up @@ -48211,9 +48271,23 @@ To find a specific item use the \`findBreadcrumbLink(n)\` function as chaining \
},
},
{
"description": "Returns options that the user can reorder.",
"description": "Returns the top-level items in the preference list.

For tables **without** column grouping this returns all column options.
For tables **with** column grouping this returns the top-level entries only
(which are group items). Use \`.findChildrenOptions()\` on a group item to
access the leaf columns nested within it.",
"name": "findOptions",
"parameters": [],
"parameters": [
{
"defaultValue": "{}",
"flags": {
"isOptional": false,
},
"name": "option",
"typeName": "{ group?: boolean | undefined; }",
},
],
"returnType": {
"isNullable": false,
"name": "MultiElementWrapper",
Expand Down Expand Up @@ -48247,6 +48321,33 @@ To find a specific item use the \`findBreadcrumbLink(n)\` function as chaining \
},
{
"methods": [
{
"description": "Returns all child option items nested under this item when it is a group.
Returns \`null\` when this item is a leaf column (has no nested children).

The children are the leaf-level \`ContentDisplayOptionWrapper\`s inside the group's
nested \`InternalList\` — i.e. they already carry a drag handle and visibility toggle.",
"name": "findChildrenOptions",
"parameters": [
{
"defaultValue": "{}",
"flags": {
"isOptional": false,
},
"name": "option",
"typeName": "{ group?: boolean | undefined; }",
},
],
"returnType": {
"isNullable": true,
"name": "MultiElementWrapper",
"typeArguments": [
{
"name": "ContentDisplayOptionWrapper",
},
],
},
},
{
"description": "Returns the drag handle for the option item.",
"name": "findDragHandle",
Expand All @@ -48266,7 +48367,8 @@ To find a specific item use the \`findBreadcrumbLink(n)\` function as chaining \
},
},
{
"description": "Returns the visibility toggle for the option item.",
"description": "Returns the visibility toggle for the option item.
Note that, despite its typings, this may return null for group items since groups do not have a visibility toggle.",
"name": "findVisibilityToggle",
"parameters": [],
"returnType": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ exports[`test-utils selectors 1`] = `
"awsui_content-before_tc96w",
"awsui_content-density_tc96w",
"awsui_content-display-description_tc96w",
"awsui_content-display-group-children_tc96w",
"awsui_content-display-group-header_tc96w",
"awsui_content-display-no-match_tc96w",
"awsui_content-display-option-content_tc96w",
"awsui_content-display-option-label_tc96w",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import useBrowser from '@cloudscape-design/browser-test-tools/use-browser';

import createWrapper from '../../../../lib/components/test-utils/selectors';
import ContentDisplayPageObject from './pages/content-display-page';

const windowDimensions = {
width: 1200,
height: 1200,
};

const setupTest = (testFn: (page: ContentDisplayPageObject) => Promise<void>) => {
return useBrowser(async browser => {
const page = new ContentDisplayPageObject(browser);
await browser.url('#/light/collection-preferences/content-display-groups');
await page.setWindowSize(windowDimensions);
page.wrapper = createWrapper().findCollectionPreferences();
await page.openCollectionPreferencesModal();
await testFn(page);
});
};

describe('Collection preferences - Grouped Content Display', () => {
test(
'renders group headers and leaf options',
setupTest(async page => {
const modal = page.wrapper.findModal().findContentDisplayPreference();
const options = modal.findOptions();

// Should have options rendered
const texts = await page.getElementsText(options.toSelector());
expect(texts.length).toBeGreaterThan(0);

// Should contain group labels
const content = await page.getText(modal.toSelector());
expect(content).toContain('Configuration');
expect(content).toContain('Performance');
expect(content).toContain('Network');
})
);

test(
'toggles visibility of a leaf option within a group',
setupTest(async page => {
const modal = page.wrapper.findModal().findContentDisplayPreference();
const options = modal.findOptions();
const firstOption = options.get(1);
const toggle = firstOption.findVisibilityToggle().findNativeInput();

// Toggle visibility
await page.click(toggle.toSelector());
})
);

test(
'reorders a group item with drag and drop',
setupTest(async page => {
const modal = page.wrapper.findModal().findContentDisplayPreference();
const options = modal.findOptions();

// Get initial order
const initialTexts = await page.getElementsText(options.toSelector());
expect(initialTexts.length).toBeGreaterThan(0);

// Drag first item down
const activeDragHandle = options.get(1).findDragHandle();
const targetDragHandle = options.get(3).findDragHandle();
await page.dragAndDropTo(activeDragHandle.toSelector(), targetDragHandle.toSelector());

// Order should have changed
const newTexts = await page.getElementsText(options.toSelector());
expect(newTexts).not.toEqual(initialTexts);
})
);

test(
'filters options within groups',
setupTest(async page => {
const modal = page.wrapper.findModal().findContentDisplayPreference();
const filterInput = modal.findTextFilter().findInput().findNativeInput();

// Type a filter
await page.click(filterInput.toSelector());
await page.keys('Network');

// Should show filtered results
const content = await page.getText(modal.toSelector());
expect(content).toContain('Network');
})
);

test(
'nested list has aria-label matching group name',
setupTest(async page => {
const modal = page.wrapper.findModal().findContentDisplayPreference();
// Verify nested lists exist by checking content
const content = await page.getText(modal.toSelector());
expect(content).toContain('Configuration');
})
);
});
Loading
Loading