@descope-ui/descope-multi-sso 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/e2e/descope-multi-sso.spec.ts +214 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-allow-configure-false-1-darwin.png +0 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-allow-create-false-1-darwin.png +0 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-allow-delete-false-1-darwin.png +0 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-create-button-label-My-Add-1-darwin.png +0 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-default-1-darwin.png +0 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-direction-rtl-1-darwin.png +0 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-full-width-true-1-darwin.png +0 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-icons-hidden-1-darwin.png +0 -0
- package/e2e/descope-multi-sso.spec.ts-snapshots/theme-single-item-default-only-1-darwin.png +0 -0
- package/package.json +37 -0
- package/project.json +8 -0
- package/src/component/MultiSsoClass.js +521 -0
- package/src/component/helpers.js +0 -0
- package/src/component/index.js +12 -0
- package/src/theme.js +49 -0
- package/stories/descope-multi-sso.stories.js +132 -0
- package/stories/icons/key.svg +3 -0
- package/stories/icons/launch.svg +6 -0
- package/stories/icons/plus.svg +3 -0
- package/stories/icons/trash.svg +3 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
|
+
|
|
5
|
+
## [3.14.0](https://github.com/descope/web-components-ui/compare/web-components-ui-3.13.3...web-components-ui-3.14.0) (2026-06-08)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **multi-sso:** add MultiSso component ([#1049](https://github.com/descope/web-components-ui/issues/1049)) ([86991ae](https://github.com/descope/web-components-ui/commit/86991aeda2b58b98d0c513fdae519bc2671d05b7))
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { test, expect, Page } from '@playwright/test';
|
|
2
|
+
import { createMultiSsoTestDriver } from 'test-drivers';
|
|
3
|
+
import { getStoryUrl, loopConfig, loopPresets } from 'e2e-utils';
|
|
4
|
+
|
|
5
|
+
const storyName = 'descope-multi-sso';
|
|
6
|
+
const componentName = 'descope-multi-sso';
|
|
7
|
+
|
|
8
|
+
const setupEventListener = (eventName: string) => {
|
|
9
|
+
return `
|
|
10
|
+
window.eventDetails = [];
|
|
11
|
+
document.addEventListener('${eventName}', (event) => {
|
|
12
|
+
window.eventDetails.push(event.detail);
|
|
13
|
+
});
|
|
14
|
+
`;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Helper: goto story and wait for the data-injecting story decorator to settle
|
|
18
|
+
const gotoStory = async (page: Page, args = {}) => {
|
|
19
|
+
await page.goto(getStoryUrl(storyName, args), { waitUntil: 'networkidle' });
|
|
20
|
+
await page.waitForSelector(componentName);
|
|
21
|
+
await page.waitForTimeout(500);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
test.describe('theme', () => {
|
|
25
|
+
test('default', async ({ page }) => {
|
|
26
|
+
await gotoStory(page);
|
|
27
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
28
|
+
expect(
|
|
29
|
+
await component.screenshot({ animations: 'disabled' }),
|
|
30
|
+
).toMatchSnapshot();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
loopConfig(
|
|
34
|
+
{
|
|
35
|
+
direction: ['rtl'],
|
|
36
|
+
'full-width': ['true'],
|
|
37
|
+
'create-button-label': ['My Add'],
|
|
38
|
+
},
|
|
39
|
+
(attr, value) => {
|
|
40
|
+
test(`${attr}: ${value}`, async ({ page }) => {
|
|
41
|
+
await gotoStory(page, { [attr]: value });
|
|
42
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
43
|
+
expect(
|
|
44
|
+
await component.screenshot({ animations: 'disabled' }),
|
|
45
|
+
).toMatchSnapshot();
|
|
46
|
+
});
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
loopPresets(
|
|
51
|
+
{
|
|
52
|
+
'allow-create false': { 'allow-create': 'false' },
|
|
53
|
+
'allow-delete false': { 'allow-delete': 'false' },
|
|
54
|
+
'allow-configure false': { 'allow-configure': 'false' },
|
|
55
|
+
'icons hidden': { showIcons: 'false' },
|
|
56
|
+
'single item (default only)': { numberOfItems: '1' },
|
|
57
|
+
'long labels': {
|
|
58
|
+
label: 'very long name very long name very long name very long name',
|
|
59
|
+
'create-button-label': 'very extremely long name also you know',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
(preset, name) => {
|
|
63
|
+
test(name, async ({ page }) => {
|
|
64
|
+
await gotoStory(page, preset);
|
|
65
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
66
|
+
expect(
|
|
67
|
+
await component.screenshot({ animations: 'disabled' }),
|
|
68
|
+
).toMatchSnapshot();
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test.describe('logic', () => {
|
|
75
|
+
test('dispatches create-clicked event with empty detail when add button is clicked', async ({
|
|
76
|
+
page,
|
|
77
|
+
}) => {
|
|
78
|
+
await page.addInitScript(setupEventListener('create-clicked'));
|
|
79
|
+
await gotoStory(page);
|
|
80
|
+
|
|
81
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
82
|
+
await component.addButton.click();
|
|
83
|
+
await page.waitForTimeout(200);
|
|
84
|
+
|
|
85
|
+
const eventDetail = await page.evaluate(
|
|
86
|
+
() => (window as any).eventDetails[0],
|
|
87
|
+
);
|
|
88
|
+
expect(eventDetail).toBeDefined();
|
|
89
|
+
expect(eventDetail).toStrictEqual({});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('dispatches delete-clicked event with id and name when delete button is clicked', async ({
|
|
93
|
+
page,
|
|
94
|
+
}) => {
|
|
95
|
+
await page.addInitScript(setupEventListener('delete-clicked'));
|
|
96
|
+
await gotoStory(page);
|
|
97
|
+
|
|
98
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
99
|
+
// Row 0 is the default (no delete); row 1 is the first deletable item
|
|
100
|
+
await component.getRow(1).deleteButton.click();
|
|
101
|
+
await page.waitForTimeout(200);
|
|
102
|
+
|
|
103
|
+
const eventDetail = await page.evaluate(
|
|
104
|
+
() => (window as any).eventDetails[0],
|
|
105
|
+
);
|
|
106
|
+
expect(eventDetail).toBeDefined();
|
|
107
|
+
expect(eventDetail).toHaveProperty('id', 'sso-2');
|
|
108
|
+
expect(eventDetail).toHaveProperty('name', 'SSO Configuration 2');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('default row has no delete button', async ({ page }) => {
|
|
112
|
+
await gotoStory(page);
|
|
113
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
114
|
+
await expect(component.getRow(0).deleteButton).toHaveCount(0);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('external link has correct href, target, rel and aria-label', async ({
|
|
118
|
+
page,
|
|
119
|
+
}) => {
|
|
120
|
+
await gotoStory(page);
|
|
121
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
122
|
+
|
|
123
|
+
// Row 0 is the default item with a link
|
|
124
|
+
const link = component.getRow(0).externalLink;
|
|
125
|
+
await expect(link).toHaveAttribute('href', /example\.descope\.com\/sso\//);
|
|
126
|
+
await expect(link).toHaveAttribute('target', '_blank');
|
|
127
|
+
await expect(link).toHaveAttribute('rel', 'noopener noreferrer');
|
|
128
|
+
await expect(link).toHaveAttribute('aria-label', 'Configure');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('delete button has correct data-id, data-name and aria-label', async ({
|
|
132
|
+
page,
|
|
133
|
+
}) => {
|
|
134
|
+
await gotoStory(page);
|
|
135
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
136
|
+
|
|
137
|
+
const deleteBtn = component.getRow(1).deleteButton;
|
|
138
|
+
await expect(deleteBtn).toHaveAttribute('data-id', 'sso-2');
|
|
139
|
+
await expect(deleteBtn).toHaveAttribute('data-name', 'SSO Configuration 2');
|
|
140
|
+
await expect(deleteBtn).toHaveAttribute('aria-label', 'Delete');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test('auth-type badge displays uppercase type text', async ({ page }) => {
|
|
144
|
+
await gotoStory(page);
|
|
145
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
146
|
+
|
|
147
|
+
// Default story has 4 items cycling saml→oidc→none→saml
|
|
148
|
+
// Row 0: saml, Row 1: oidc
|
|
149
|
+
await expect(component.getRow(0).authTypeBadge).toHaveText('SAML');
|
|
150
|
+
await expect(component.getRow(1).authTypeBadge).toHaveText('OIDC');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test('row with authType none shows "Not Configured" text', async ({
|
|
154
|
+
page,
|
|
155
|
+
}) => {
|
|
156
|
+
await gotoStory(page);
|
|
157
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
158
|
+
|
|
159
|
+
// Row 2 has authType 'none' (index 2 → authTypes[2] = 'none')
|
|
160
|
+
await expect(component.getRow(2).notConfigured).toBeVisible();
|
|
161
|
+
await expect(component.getRow(2).notConfigured).toHaveText(
|
|
162
|
+
'Not Configured',
|
|
163
|
+
);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('allow-create=false hides the add button', async ({ page }) => {
|
|
167
|
+
await gotoStory(page, { 'allow-create': 'false' });
|
|
168
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
169
|
+
await expect(component.addButton).toBeHidden();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test('allow-delete=false removes all delete buttons', async ({ page }) => {
|
|
173
|
+
await gotoStory(page, { 'allow-delete': 'false' });
|
|
174
|
+
createMultiSsoTestDriver(page.locator(componentName));
|
|
175
|
+
// No [data-action="delete"] should exist anywhere in the component
|
|
176
|
+
await expect(
|
|
177
|
+
page.locator(componentName).locator('[data-action="delete"]'),
|
|
178
|
+
).toHaveCount(0);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('allow-configure=false removes all external-link anchors', async ({
|
|
182
|
+
page,
|
|
183
|
+
}) => {
|
|
184
|
+
await gotoStory(page, { 'allow-configure': 'false' });
|
|
185
|
+
createMultiSsoTestDriver(page.locator(componentName));
|
|
186
|
+
await expect(
|
|
187
|
+
page.locator(componentName).locator('.external-link'),
|
|
188
|
+
).toHaveCount(0);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test('setData updates the rendered row count', async ({ page }) => {
|
|
192
|
+
await gotoStory(page);
|
|
193
|
+
const component = createMultiSsoTestDriver(page.locator(componentName));
|
|
194
|
+
|
|
195
|
+
await component.setData([
|
|
196
|
+
{
|
|
197
|
+
id: 'sso-1',
|
|
198
|
+
name: 'Only Config',
|
|
199
|
+
isDefault: true,
|
|
200
|
+
link: 'https://example.descope.com/sso/1',
|
|
201
|
+
authType: 'saml',
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: 'sso-2',
|
|
205
|
+
name: 'Second Config',
|
|
206
|
+
link: 'https://example.descope.com/sso/2',
|
|
207
|
+
authType: 'oidc',
|
|
208
|
+
},
|
|
209
|
+
]);
|
|
210
|
+
await page.waitForTimeout(200);
|
|
211
|
+
|
|
212
|
+
await expect(component.rows).toHaveCount(2);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@descope-ui/descope-multi-sso",
|
|
3
|
+
"version": "3.14.0",
|
|
4
|
+
"exports": {
|
|
5
|
+
".": {
|
|
6
|
+
"import": "./src/component/index.js"
|
|
7
|
+
},
|
|
8
|
+
"./theme": {
|
|
9
|
+
"import": "./src/theme.js"
|
|
10
|
+
},
|
|
11
|
+
"./class": {
|
|
12
|
+
"import": "./src/component/MultiSsoClass.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@playwright/test": "1.58.2",
|
|
17
|
+
"e2e-utils": "3.14.0",
|
|
18
|
+
"test-drivers": "3.14.0"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@descope-ui/common": "3.14.0",
|
|
22
|
+
"@descope-ui/theme-globals": "3.14.0",
|
|
23
|
+
"@descope-ui/descope-list": "3.14.0",
|
|
24
|
+
"@descope-ui/descope-list-item": "3.14.0",
|
|
25
|
+
"@descope-ui/descope-text": "3.14.0",
|
|
26
|
+
"@descope-ui/descope-icon": "3.14.0",
|
|
27
|
+
"@descope-ui/descope-button": "3.14.0",
|
|
28
|
+
"@descope-ui/descope-badge": "3.14.0"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"link-workspace-packages": false
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"test": "echo 'No tests defined' && exit 0",
|
|
35
|
+
"test:e2e": "echo 'No e2e tests defined' && exit 0"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import { compose } from '@descope-ui/common/utils';
|
|
2
|
+
import {
|
|
3
|
+
getComponentName,
|
|
4
|
+
injectStyle,
|
|
5
|
+
cloneSlottedNodes,
|
|
6
|
+
forwardAttrs,
|
|
7
|
+
} from '@descope-ui/common/components-helpers';
|
|
8
|
+
import {
|
|
9
|
+
createStyleMixin,
|
|
10
|
+
draggableMixin,
|
|
11
|
+
componentNameValidationMixin,
|
|
12
|
+
createDynamicDataMixin,
|
|
13
|
+
} from '@descope-ui/common/components-mixins';
|
|
14
|
+
import { createBaseClass } from '@descope-ui/common/base-classes';
|
|
15
|
+
import { ButtonClass } from '@descope-ui/descope-button/class';
|
|
16
|
+
import { ListClass } from '@descope-ui/descope-list/class';
|
|
17
|
+
import { IconClass } from '@descope-ui/descope-icon/class';
|
|
18
|
+
import { ListItemClass } from '@descope-ui/descope-list-item/class';
|
|
19
|
+
import { BadgeClass } from '@descope-ui/descope-badge/class';
|
|
20
|
+
import { TextClass } from '@descope-ui/descope-text/class';
|
|
21
|
+
|
|
22
|
+
export const componentName = getComponentName('multi-sso');
|
|
23
|
+
|
|
24
|
+
const resolveAuthType = (authType) => {
|
|
25
|
+
if (!authType || authType === 'none')
|
|
26
|
+
return { label: 'Not Configured', configured: false };
|
|
27
|
+
return { label: authType.toUpperCase(), configured: true };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const itemRenderer = ({ id, name, isDefault, link, authType }, _, ref) => {
|
|
31
|
+
const deleteAction =
|
|
32
|
+
!isDefault && ref?.allowDelete
|
|
33
|
+
? `<span
|
|
34
|
+
class="delete-btn delete-icon"
|
|
35
|
+
data-action="delete"
|
|
36
|
+
role="button"
|
|
37
|
+
tabindex="0"
|
|
38
|
+
title="${ref.deleteTooltipLabel}"
|
|
39
|
+
></span>`
|
|
40
|
+
: '';
|
|
41
|
+
|
|
42
|
+
const externalLinkAction =
|
|
43
|
+
link && ref?.allowConfigure
|
|
44
|
+
? `<a
|
|
45
|
+
class="external-link external-link-icon"
|
|
46
|
+
target="_blank"
|
|
47
|
+
rel="noopener noreferrer"
|
|
48
|
+
title="${ref.configureTooltipLabel}"
|
|
49
|
+
></a>`
|
|
50
|
+
: '';
|
|
51
|
+
|
|
52
|
+
const { label: authTypeLabel, configured } = resolveAuthType(authType);
|
|
53
|
+
const authTypeRow = configured
|
|
54
|
+
? `<div class="auth-type-row">
|
|
55
|
+
<descope-badge class="auth-type-badge" size="xs"></descope-badge>
|
|
56
|
+
</div>`
|
|
57
|
+
: `<div class="auth-type-row">
|
|
58
|
+
<descope-text
|
|
59
|
+
not-configured
|
|
60
|
+
variant="body2"
|
|
61
|
+
mode="secondary"
|
|
62
|
+
>${ref?.notConfiguredLabel}</descope-text>
|
|
63
|
+
</div>`;
|
|
64
|
+
|
|
65
|
+
const template = document.createElement('template');
|
|
66
|
+
|
|
67
|
+
template.innerHTML = `
|
|
68
|
+
<descope-list-item>
|
|
69
|
+
<div class="content">
|
|
70
|
+
<div class="top-row">
|
|
71
|
+
<descope-text
|
|
72
|
+
class="config-name"
|
|
73
|
+
variant="body1"
|
|
74
|
+
mode="primary"
|
|
75
|
+
></descope-text>
|
|
76
|
+
<span class="action">
|
|
77
|
+
${deleteAction}
|
|
78
|
+
${externalLinkAction}
|
|
79
|
+
</span>
|
|
80
|
+
</div>
|
|
81
|
+
${authTypeRow}
|
|
82
|
+
</div>
|
|
83
|
+
</descope-list-item>
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
template.content.querySelector('.config-name').textContent = name;
|
|
87
|
+
|
|
88
|
+
const deleteBtn = template.content.querySelector('.delete-btn');
|
|
89
|
+
if (deleteBtn) {
|
|
90
|
+
deleteBtn.dataset.id = id;
|
|
91
|
+
deleteBtn.dataset.name = name;
|
|
92
|
+
deleteBtn.setAttribute('aria-label', ref.deleteTooltipLabel);
|
|
93
|
+
const deleteIcon = cloneSlottedNodes(ref, 'delete-icon');
|
|
94
|
+
if (deleteIcon) deleteBtn.append(deleteIcon);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const linkBtn = template.content.querySelector('.external-link');
|
|
98
|
+
if (linkBtn) {
|
|
99
|
+
linkBtn.setAttribute('aria-label', ref.configureTooltipLabel);
|
|
100
|
+
if (link) linkBtn.setAttribute('href', link);
|
|
101
|
+
const linkIcon = cloneSlottedNodes(ref, 'external-link-icon');
|
|
102
|
+
if (linkIcon) linkBtn.append(linkIcon);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const authTypeBadge = template.content.querySelector('.auth-type-badge');
|
|
106
|
+
if (authTypeBadge) authTypeBadge.textContent = authTypeLabel;
|
|
107
|
+
return template;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const BaseClass = createBaseClass({
|
|
111
|
+
componentName,
|
|
112
|
+
baseSelector: 'span.wrapper',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
class RawMultiSsoClass extends BaseClass {
|
|
116
|
+
static get observedAttributes() {
|
|
117
|
+
return [
|
|
118
|
+
'label',
|
|
119
|
+
'create-button-label',
|
|
120
|
+
'not-configured-label',
|
|
121
|
+
'delete-tooltip-label',
|
|
122
|
+
'configure-tooltip-label',
|
|
123
|
+
'empty',
|
|
124
|
+
].concat(super.observedAttributes);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
constructor() {
|
|
128
|
+
super();
|
|
129
|
+
|
|
130
|
+
this.attachShadow({ mode: 'open' }).innerHTML = `
|
|
131
|
+
<span class="wrapper">
|
|
132
|
+
<div class="header">
|
|
133
|
+
<slot name="title-icon"></slot>
|
|
134
|
+
<descope-text class="title" variant="body1" mode="primary"></descope-text>
|
|
135
|
+
<descope-button
|
|
136
|
+
class="create-button"
|
|
137
|
+
size="sm"
|
|
138
|
+
variant="link"
|
|
139
|
+
mode="primary"
|
|
140
|
+
data-action="create"
|
|
141
|
+
>
|
|
142
|
+
<slot name="create-button-icon" slot="prefix"></slot>
|
|
143
|
+
<span class="create-button-label"></span>
|
|
144
|
+
</descope-button>
|
|
145
|
+
</div>
|
|
146
|
+
<descope-list></descope-list>
|
|
147
|
+
<slot name="delete-icon" class="hidden"></slot>
|
|
148
|
+
<slot name="external-link-icon" class="hidden"></slot>
|
|
149
|
+
</span>
|
|
150
|
+
`;
|
|
151
|
+
|
|
152
|
+
this.listEl = this.shadowRoot.querySelector('descope-list');
|
|
153
|
+
|
|
154
|
+
injectStyle(
|
|
155
|
+
`
|
|
156
|
+
:host {
|
|
157
|
+
display: inline-block;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
:host(:not([allow-create="true"])) .create-button {
|
|
161
|
+
display: none;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.create-button {
|
|
165
|
+
min-width: 0;
|
|
166
|
+
flex-shrink:1;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.header {
|
|
170
|
+
width: 100%;
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
justify-content: space-between;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
slot[name="title-icon"] {
|
|
177
|
+
display: inline-flex;
|
|
178
|
+
align-items: center;
|
|
179
|
+
flex-shrink: 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.title {
|
|
183
|
+
flex: 1;
|
|
184
|
+
min-width: 0;
|
|
185
|
+
width:0;
|
|
186
|
+
flex-shrink: 0;
|
|
187
|
+
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.title::part(text-wrapper) {
|
|
191
|
+
text-overflow: ellipsis;
|
|
192
|
+
overflow: hidden;
|
|
193
|
+
white-space: nowrap;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.content {
|
|
197
|
+
display: flex;
|
|
198
|
+
flex-direction: column;
|
|
199
|
+
align-items: stretch;
|
|
200
|
+
width: 100%;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.top-row {
|
|
204
|
+
display: flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
justify-content: space-between;
|
|
207
|
+
min-width: 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.config-name {
|
|
211
|
+
display: flex;
|
|
212
|
+
align-items: center;
|
|
213
|
+
min-width: 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.config-name::part(text-wrapper) {
|
|
217
|
+
text-overflow: ellipsis;
|
|
218
|
+
overflow: hidden;
|
|
219
|
+
white-space: nowrap;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.auth-type-row {
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.action {
|
|
228
|
+
display: flex;
|
|
229
|
+
align-items: center;
|
|
230
|
+
flex-shrink: 0;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.hidden {
|
|
234
|
+
display: none;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.delete-btn {
|
|
238
|
+
cursor: pointer;
|
|
239
|
+
display: flex;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.delete-icon > *,
|
|
243
|
+
.external-link-icon > * {
|
|
244
|
+
width: 100%;
|
|
245
|
+
height: 100%;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.external-link {
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
color: inherit;
|
|
251
|
+
display: flex;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
descope-text {
|
|
255
|
+
display: flex;
|
|
256
|
+
align-items: center;
|
|
257
|
+
min-width: 0;
|
|
258
|
+
}
|
|
259
|
+
`,
|
|
260
|
+
this,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
get deleteTooltipLabel() {
|
|
265
|
+
return this.getAttribute('delete-tooltip-label') ?? '';
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
get configureTooltipLabel() {
|
|
269
|
+
return this.getAttribute('configure-tooltip-label') ?? '';
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
init() {
|
|
273
|
+
super.init?.();
|
|
274
|
+
|
|
275
|
+
this.shadowRoot.querySelector('.title').textContent = this.label;
|
|
276
|
+
this.shadowRoot.querySelector('.create-button-label').textContent =
|
|
277
|
+
this.createButtonLabel;
|
|
278
|
+
|
|
279
|
+
this.listEl.itemRenderer = (item, index) => itemRenderer(item, index, this);
|
|
280
|
+
|
|
281
|
+
this.shadowRoot
|
|
282
|
+
.querySelector('[data-action="create"]')
|
|
283
|
+
.addEventListener('click', this.onCreateClick.bind(this));
|
|
284
|
+
this.listEl.addEventListener('click', this.onItemClick.bind(this));
|
|
285
|
+
|
|
286
|
+
forwardAttrs(this.listEl, this, { includeAttrs: ['empty'] });
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
onCreateClick() {
|
|
290
|
+
this.dispatchEvent(
|
|
291
|
+
new CustomEvent('create-clicked', { bubbles: true, detail: {} }),
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
onItemClick(e) {
|
|
296
|
+
const target = e.target.closest('[data-action="delete"]');
|
|
297
|
+
if (!target) return;
|
|
298
|
+
|
|
299
|
+
const id = target.getAttribute('data-id');
|
|
300
|
+
const name = target.getAttribute('data-name');
|
|
301
|
+
if (id) {
|
|
302
|
+
this.dispatchEvent(
|
|
303
|
+
new CustomEvent('delete-clicked', {
|
|
304
|
+
bubbles: true,
|
|
305
|
+
detail: { id, name },
|
|
306
|
+
}),
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
get allowCreate() {
|
|
312
|
+
return this.getAttribute('allow-create') === 'true';
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
get allowDelete() {
|
|
316
|
+
return this.getAttribute('allow-delete') === 'true';
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
get allowConfigure() {
|
|
320
|
+
return this.getAttribute('allow-configure') === 'true';
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
get label() {
|
|
324
|
+
return this.getAttribute('label');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
get createButtonLabel() {
|
|
328
|
+
return this.getAttribute('create-button-label');
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
get notConfiguredLabel() {
|
|
332
|
+
return this.getAttribute('not-configured-label') || 'Not Configured';
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
336
|
+
super.attributeChangedCallback?.(name, oldValue, newValue);
|
|
337
|
+
if (oldValue === newValue) return;
|
|
338
|
+
|
|
339
|
+
if (name === 'label') {
|
|
340
|
+
const el = this.shadowRoot?.querySelector('.title');
|
|
341
|
+
if (el) el.textContent = this.label;
|
|
342
|
+
} else if (name === 'create-button-label') {
|
|
343
|
+
const el = this.shadowRoot?.querySelector('.create-button-label');
|
|
344
|
+
if (el) el.textContent = this.createButtonLabel;
|
|
345
|
+
} else if (name === 'empty') {
|
|
346
|
+
this.listEl.classList.toggle('hidden', newValue === 'true');
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const { host } = {
|
|
352
|
+
host: { selector: () => ':host' },
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
export const MultiSsoClass = compose(
|
|
356
|
+
createStyleMixin({
|
|
357
|
+
mappings: {
|
|
358
|
+
hostWidth: { ...host, property: 'width' },
|
|
359
|
+
hostMinWidth: { ...host, property: 'min-width' },
|
|
360
|
+
hostDirection: [
|
|
361
|
+
{ ...host, property: 'direction' },
|
|
362
|
+
{
|
|
363
|
+
selector: () => 'descope-list-item',
|
|
364
|
+
property: 'direction',
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
selector: () => 'descope-text',
|
|
368
|
+
property: 'direction',
|
|
369
|
+
},
|
|
370
|
+
],
|
|
371
|
+
headerGap: {
|
|
372
|
+
selector: () => '.header',
|
|
373
|
+
property: 'gap',
|
|
374
|
+
},
|
|
375
|
+
headerListGap: {
|
|
376
|
+
selector: () => 'descope-list',
|
|
377
|
+
property: 'margin-top',
|
|
378
|
+
},
|
|
379
|
+
itemContentGap: {
|
|
380
|
+
selector: () => '.content',
|
|
381
|
+
property: 'gap',
|
|
382
|
+
},
|
|
383
|
+
actionGap: {
|
|
384
|
+
selector: () => '.action',
|
|
385
|
+
property: 'gap',
|
|
386
|
+
},
|
|
387
|
+
unconfiguredAuthTypeTextColor: {
|
|
388
|
+
selector: () => '[not-configured]',
|
|
389
|
+
property: TextClass.cssVarList.textColor,
|
|
390
|
+
},
|
|
391
|
+
unconfiguredAuthTypeTextFontStyle: {
|
|
392
|
+
selector: () => '[not-configured]',
|
|
393
|
+
property: 'font-style',
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
buttonMaxWidth: {
|
|
397
|
+
selector: ButtonClass.componentName,
|
|
398
|
+
property: ButtonClass.cssVarList.hostMaxWidth,
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
listItemsGap: {
|
|
402
|
+
property: ListClass.cssVarList.gap,
|
|
403
|
+
},
|
|
404
|
+
listBackgroundColor: {
|
|
405
|
+
selector: () => ListClass.componentName,
|
|
406
|
+
property: ListClass.cssVarList.backgroundColor,
|
|
407
|
+
},
|
|
408
|
+
listBorderRadius: {
|
|
409
|
+
selector: () => ListClass.componentName,
|
|
410
|
+
property: ListClass.cssVarList.borderRadius,
|
|
411
|
+
},
|
|
412
|
+
listBorderWidth: {
|
|
413
|
+
selector: () => ListClass.componentName,
|
|
414
|
+
property: ListClass.cssVarList.borderWidth,
|
|
415
|
+
},
|
|
416
|
+
listBoxShadow: {
|
|
417
|
+
selector: () => ListClass.componentName,
|
|
418
|
+
property: ListClass.cssVarList.boxShadow,
|
|
419
|
+
},
|
|
420
|
+
listPadding: [
|
|
421
|
+
{
|
|
422
|
+
selector: () => ListClass.componentName,
|
|
423
|
+
property: ListClass.cssVarList.verticalPadding,
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
selector: () => ListClass.componentName,
|
|
427
|
+
property: ListClass.cssVarList.horizontalPadding,
|
|
428
|
+
},
|
|
429
|
+
],
|
|
430
|
+
|
|
431
|
+
itemVerticalPadding: {
|
|
432
|
+
selector: ListItemClass.componentName,
|
|
433
|
+
property: ListItemClass.cssVarList.verticalPadding,
|
|
434
|
+
},
|
|
435
|
+
itemHorizontalPadding: {
|
|
436
|
+
selector: ListItemClass.componentName,
|
|
437
|
+
property: ListItemClass.cssVarList.horizontalPadding,
|
|
438
|
+
},
|
|
439
|
+
itemCursor: {
|
|
440
|
+
selector: ListItemClass.componentName,
|
|
441
|
+
property: ListItemClass.cssVarList.cursor,
|
|
442
|
+
},
|
|
443
|
+
itemOutline: {
|
|
444
|
+
selector: ListItemClass.componentName,
|
|
445
|
+
property: ListItemClass.cssVarList.outline,
|
|
446
|
+
},
|
|
447
|
+
itemBorderColor: {
|
|
448
|
+
selector: ListItemClass.componentName,
|
|
449
|
+
property: ListItemClass.cssVarList.borderColor,
|
|
450
|
+
},
|
|
451
|
+
itemBorderRadius: {
|
|
452
|
+
selector: ListItemClass.componentName,
|
|
453
|
+
property: ListItemClass.cssVarList.borderRadius,
|
|
454
|
+
},
|
|
455
|
+
itemBackgroundColor: {
|
|
456
|
+
selector: ListItemClass.componentName,
|
|
457
|
+
property: ListItemClass.cssVarList.backgroundColor,
|
|
458
|
+
},
|
|
459
|
+
badgeBorderColor: {
|
|
460
|
+
selector: () => BadgeClass.componentName,
|
|
461
|
+
property: BadgeClass.cssVarList.borderColor,
|
|
462
|
+
},
|
|
463
|
+
badgeTextColor: {
|
|
464
|
+
selector: () => BadgeClass.componentName,
|
|
465
|
+
property: BadgeClass.cssVarList.textColor,
|
|
466
|
+
},
|
|
467
|
+
badgeBackgroundColor: {
|
|
468
|
+
selector: () => BadgeClass.componentName,
|
|
469
|
+
property: BadgeClass.cssVarList.backgroundColor,
|
|
470
|
+
},
|
|
471
|
+
badgeBorderRadius: {
|
|
472
|
+
selector: () => BadgeClass.componentName,
|
|
473
|
+
property: BadgeClass.cssVarList.borderRadius,
|
|
474
|
+
},
|
|
475
|
+
|
|
476
|
+
titleIconSize: [
|
|
477
|
+
{ selector: () => '::slotted([slot="title-icon"])', property: 'width' },
|
|
478
|
+
{
|
|
479
|
+
selector: () => '::slotted([slot="title-icon"])',
|
|
480
|
+
property: 'height',
|
|
481
|
+
},
|
|
482
|
+
],
|
|
483
|
+
createButtonIconSize: [
|
|
484
|
+
{
|
|
485
|
+
selector: () => '::slotted([slot="create-button-icon"])',
|
|
486
|
+
property: 'width',
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
selector: () => '::slotted([slot="create-button-icon"])',
|
|
490
|
+
property: 'height',
|
|
491
|
+
},
|
|
492
|
+
],
|
|
493
|
+
actionIconSize: [
|
|
494
|
+
{ selector: () => '.delete-icon', property: 'width' },
|
|
495
|
+
{ selector: () => '.delete-icon', property: 'height' },
|
|
496
|
+
{ selector: () => '.external-link-icon', property: 'width' },
|
|
497
|
+
{ selector: () => '.external-link-icon', property: 'height' },
|
|
498
|
+
],
|
|
499
|
+
actionIconColor: [
|
|
500
|
+
{ selector: () => '.delete-icon', property: IconClass.cssVarList.fill },
|
|
501
|
+
{
|
|
502
|
+
selector: () => '.external-link-icon',
|
|
503
|
+
property: IconClass.cssVarList.fill,
|
|
504
|
+
},
|
|
505
|
+
],
|
|
506
|
+
},
|
|
507
|
+
}),
|
|
508
|
+
draggableMixin,
|
|
509
|
+
createDynamicDataMixin({
|
|
510
|
+
targetSelector: 'descope-list',
|
|
511
|
+
itemRenderer,
|
|
512
|
+
rerenderAttrsList: [
|
|
513
|
+
'allow-delete',
|
|
514
|
+
'allow-configure',
|
|
515
|
+
'not-configured-label',
|
|
516
|
+
'delete-tooltip-label',
|
|
517
|
+
'configure-tooltip-label',
|
|
518
|
+
],
|
|
519
|
+
}),
|
|
520
|
+
componentNameValidationMixin,
|
|
521
|
+
)(RawMultiSsoClass);
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import '@descope-ui/descope-list';
|
|
2
|
+
import '@descope-ui/descope-list-item';
|
|
3
|
+
import '@descope-ui/descope-text';
|
|
4
|
+
import '@descope-ui/descope-icon';
|
|
5
|
+
import '@descope-ui/descope-button';
|
|
6
|
+
import '@descope-ui/descope-badge';
|
|
7
|
+
|
|
8
|
+
import { componentName, MultiSsoClass } from './MultiSsoClass';
|
|
9
|
+
|
|
10
|
+
customElements.define(componentName, MultiSsoClass);
|
|
11
|
+
|
|
12
|
+
export { MultiSsoClass, componentName };
|
package/src/theme.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { MultiSsoClass } from './component/MultiSsoClass';
|
|
2
|
+
import globals from '@descope-ui/theme-globals';
|
|
3
|
+
import { getThemeRefs } from '@descope-ui/common/theme-helpers';
|
|
4
|
+
|
|
5
|
+
export const vars = MultiSsoClass.cssVarList;
|
|
6
|
+
const globalRefs = getThemeRefs(globals);
|
|
7
|
+
|
|
8
|
+
const MultiSso = {
|
|
9
|
+
[vars.hostWidth]: '300px',
|
|
10
|
+
|
|
11
|
+
[vars.headerGap]: globalRefs.spacing.md,
|
|
12
|
+
[vars.headerListGap]: globalRefs.spacing.md,
|
|
13
|
+
[vars.itemContentGap]: globalRefs.spacing.md,
|
|
14
|
+
[vars.actionGap]: globalRefs.spacing.sm,
|
|
15
|
+
[vars.unconfiguredAuthTypeTextColor]: globalRefs.colors.surface.dark,
|
|
16
|
+
[vars.unconfiguredAuthTypeTextFontStyle]: 'italic',
|
|
17
|
+
[vars.buttonMaxWidth]: '50%',
|
|
18
|
+
|
|
19
|
+
[vars.listBackgroundColor]: 'transparent',
|
|
20
|
+
[vars.listBorderRadius]: '0',
|
|
21
|
+
[vars.listBorderWidth]: '0',
|
|
22
|
+
[vars.listPadding]: '0',
|
|
23
|
+
[vars.listBoxShadow]: 'none',
|
|
24
|
+
[vars.listItemsGap]: globalRefs.spacing.lg,
|
|
25
|
+
|
|
26
|
+
[vars.itemBorderColor]: globalRefs.colors.surface.light,
|
|
27
|
+
[vars.itemVerticalPadding]: globalRefs.spacing.lg,
|
|
28
|
+
[vars.itemHorizontalPadding]: globalRefs.spacing.lg,
|
|
29
|
+
[vars.itemBorderRadius]: globalRefs.radius.xs,
|
|
30
|
+
[vars.itemOutline]: 'transparent',
|
|
31
|
+
[vars.itemBackgroundColor]: 'transparent',
|
|
32
|
+
[vars.itemCursor]: 'default',
|
|
33
|
+
|
|
34
|
+
[vars.badgeBorderColor]: globalRefs.colors.surface.light,
|
|
35
|
+
[vars.badgeTextColor]: globalRefs.colors.surface.dark,
|
|
36
|
+
[vars.badgeBorderRadius]: globalRefs.radius.xs,
|
|
37
|
+
[vars.badgeBackgroundColor]: globalRefs.colors.surface.main,
|
|
38
|
+
|
|
39
|
+
[vars.titleIconSize]: '24px',
|
|
40
|
+
[vars.createButtonIconSize]: '20px',
|
|
41
|
+
[vars.actionIconSize]: '20px',
|
|
42
|
+
[vars.actionIconColor]: globalRefs.colors.surface.dark,
|
|
43
|
+
|
|
44
|
+
_fullWidth: {
|
|
45
|
+
[vars.hostWidth]: '100%',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default MultiSso;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { componentName } from '../src/component';
|
|
2
|
+
import {
|
|
3
|
+
directionControl,
|
|
4
|
+
fullWidthControl,
|
|
5
|
+
} from '@descope-ui/common/sb-controls';
|
|
6
|
+
import keyIcon from './icons/key.svg';
|
|
7
|
+
import plusIcon from './icons/plus.svg';
|
|
8
|
+
import trashIcon from './icons/trash.svg';
|
|
9
|
+
import launchIcon from './icons/launch.svg';
|
|
10
|
+
|
|
11
|
+
const authTypes = ['saml', 'oidc', 'none'];
|
|
12
|
+
|
|
13
|
+
const generateMockConfigurations = (numberOfItems) =>
|
|
14
|
+
Array.from({ length: Number(numberOfItems) }, (_, i) => ({
|
|
15
|
+
id: `sso-${i + 1}`,
|
|
16
|
+
name: i === 0 ? 'Default SSO configuration' : `SSO Configuration ${i + 1}`,
|
|
17
|
+
isDefault: i === 0,
|
|
18
|
+
link: `https://example.descope.com/sso/${i + 1}`,
|
|
19
|
+
authType: authTypes[i % authTypes.length],
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
const Template = ({
|
|
23
|
+
direction,
|
|
24
|
+
'full-width': fullWidth,
|
|
25
|
+
label,
|
|
26
|
+
'create-button-label': createButtonLabel,
|
|
27
|
+
'allow-create': allowCreate,
|
|
28
|
+
'allow-delete': allowDelete,
|
|
29
|
+
'allow-configure': allowConfigure,
|
|
30
|
+
'delete-tooltip-label': deleteTooltipLabel,
|
|
31
|
+
'configure-tooltip-label': configureTooltipLabel,
|
|
32
|
+
showIcons,
|
|
33
|
+
}) => `
|
|
34
|
+
<${componentName}
|
|
35
|
+
full-width="${fullWidth || false}"
|
|
36
|
+
label="${label || ''}"
|
|
37
|
+
create-button-label="${createButtonLabel || ''}"
|
|
38
|
+
st-host-direction="${direction || ''}"
|
|
39
|
+
allow-create="${allowCreate}"
|
|
40
|
+
allow-delete="${allowDelete}"
|
|
41
|
+
allow-configure="${allowConfigure}"
|
|
42
|
+
delete-tooltip-label="${deleteTooltipLabel || ''}"
|
|
43
|
+
configure-tooltip-label="${configureTooltipLabel || ''}"
|
|
44
|
+
>
|
|
45
|
+
${showIcons ? `<descope-icon st-fill="currentcolor" src="${keyIcon}" src-dark="${keyIcon}" slot="title-icon"></descope-icon>` : ''}
|
|
46
|
+
${showIcons ? `<descope-icon st-fill="currentcolor" src="${plusIcon}" src-dark="${plusIcon}" slot="create-button-icon"></descope-icon>` : ''}
|
|
47
|
+
<descope-icon src="${trashIcon}" src-dark="${trashIcon}" slot="delete-icon"></descope-icon>
|
|
48
|
+
<descope-icon src="${launchIcon}" src-dark="${launchIcon}" slot="external-link-icon"></descope-icon>
|
|
49
|
+
</${componentName}>
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
export default {
|
|
53
|
+
component: componentName,
|
|
54
|
+
title: 'descope-multi-sso',
|
|
55
|
+
decorators: [
|
|
56
|
+
(story, { args }) => {
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
const comp = document.querySelector(componentName);
|
|
59
|
+
if (comp) comp.data = generateMockConfigurations(args.numberOfItems);
|
|
60
|
+
});
|
|
61
|
+
return story();
|
|
62
|
+
},
|
|
63
|
+
(story) => {
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
const comp = document.querySelector(componentName);
|
|
66
|
+
if (!comp) return;
|
|
67
|
+
|
|
68
|
+
const emit = (name, detail) => {
|
|
69
|
+
if (window && window.__STORYBOOK_ADDONS_CHANNEL__) {
|
|
70
|
+
window.__STORYBOOK_ADDONS_CHANNEL__.emit(
|
|
71
|
+
'storybook/actions/action-event',
|
|
72
|
+
{ id: name, data: [detail], options: { name } },
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
comp.addEventListener('create-clicked', (e) =>
|
|
78
|
+
emit('CreateClicked', e.detail),
|
|
79
|
+
);
|
|
80
|
+
comp.addEventListener('delete-clicked', (e) =>
|
|
81
|
+
emit('DeleteClicked', e.detail),
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
return story();
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
argTypes: {
|
|
88
|
+
...directionControl,
|
|
89
|
+
...fullWidthControl,
|
|
90
|
+
label: {
|
|
91
|
+
control: { type: 'text' },
|
|
92
|
+
},
|
|
93
|
+
'create-button-label': {
|
|
94
|
+
control: { type: 'text' },
|
|
95
|
+
},
|
|
96
|
+
numberOfItems: {
|
|
97
|
+
control: { type: 'number', min: 0 },
|
|
98
|
+
},
|
|
99
|
+
showIcons: {
|
|
100
|
+
control: { type: 'boolean' },
|
|
101
|
+
},
|
|
102
|
+
'allow-create': {
|
|
103
|
+
control: { type: 'boolean' },
|
|
104
|
+
},
|
|
105
|
+
'allow-delete': {
|
|
106
|
+
control: { type: 'boolean' },
|
|
107
|
+
},
|
|
108
|
+
'allow-configure': {
|
|
109
|
+
control: { type: 'boolean' },
|
|
110
|
+
},
|
|
111
|
+
'delete-tooltip-label': {
|
|
112
|
+
control: { type: 'text' },
|
|
113
|
+
},
|
|
114
|
+
'configure-tooltip-label': {
|
|
115
|
+
control: { type: 'text' },
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export const Default = Template.bind({});
|
|
121
|
+
|
|
122
|
+
Default.args = {
|
|
123
|
+
label: 'SSO configurations',
|
|
124
|
+
'create-button-label': 'Add',
|
|
125
|
+
numberOfItems: 4,
|
|
126
|
+
showIcons: true,
|
|
127
|
+
'allow-create': true,
|
|
128
|
+
'allow-delete': true,
|
|
129
|
+
'allow-configure': true,
|
|
130
|
+
'delete-tooltip-label': 'Delete',
|
|
131
|
+
'configure-tooltip-label': 'Configure',
|
|
132
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
|
2
|
+
<path d="M12.65 10C11.83 7.67 9.61 6 7 6c-3.31 0-6 2.69-6 6s2.69 6 6 6c2.61 0 4.83-1.67 5.65-4H17v4h4v-4h2v-4H12.65zM7 14c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2z"/>
|
|
3
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path
|
|
3
|
+
d="M19 19H5V5H12V3H5C3.89 3 3 3.9 3 5V19C3 20.1 3.89 21 5 21H19C20.1 21 21 20.1 21 19V12H19V19ZM14 3V5H17.59L7.76 14.83L9.17 16.24L19 6.41V10H21V3H14Z"
|
|
4
|
+
fill="currentColor"
|
|
5
|
+
/>
|
|
6
|
+
</svg>
|