@keycloakify/keycloak-ui-shared 260103.0.1 → 260200.0.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/keycloak-theme/shared/keycloak-ui-shared/controls/OrganizationTable.tsx +3 -0
- package/keycloak-theme/shared/keycloak-ui-shared/controls/SwitchControl.tsx +2 -1
- package/keycloak-theme/shared/keycloak-ui-shared/controls/TextAreaControl.tsx +1 -0
- package/keycloak-theme/shared/keycloak-ui-shared/controls/select-control/SelectControl.tsx +4 -0
- package/keycloak-theme/shared/keycloak-ui-shared/controls/select-control/SingleSelectControl.tsx +12 -3
- package/keycloak-theme/shared/keycloak-ui-shared/controls/table/KeycloakDataTable.tsx +40 -29
- package/keycloak-theme/shared/keycloak-ui-shared/controls/table/TableToolbar.tsx +1 -1
- package/keycloak-theme/shared/keycloak-ui-shared/masthead/Masthead.tsx +3 -0
- package/keycloak-theme/shared/keycloak-ui-shared/select/KeycloakSelect.tsx +1 -1
- package/keycloak-theme/shared/keycloak-ui-shared/select/TypeaheadSelect.tsx +5 -1
- package/keycloak-theme/shared/keycloak-ui-shared/user-profile/LocaleSelector.tsx +1 -1
- package/keycloak-theme/shared/keycloak-ui-shared/user-profile/TextComponent.tsx +1 -1
- package/keycloak-theme/shared/keycloak-ui-shared/user-profile/utils.ts +2 -1
- package/package.json +8 -8
|
@@ -67,6 +67,7 @@ export type OrganizationTableProps = PropsWithChildren & {
|
|
|
67
67
|
toolbarItem?: ReactNode;
|
|
68
68
|
isPaginated?: boolean;
|
|
69
69
|
isSearching?: boolean;
|
|
70
|
+
searchPlaceholderKey?: string;
|
|
70
71
|
onSelect?: (orgs: OrganizationRepresentation[]) => void;
|
|
71
72
|
onDelete?: (org: OrganizationRepresentation) => void;
|
|
72
73
|
deleteLabel?: string;
|
|
@@ -77,6 +78,7 @@ export const OrganizationTable = ({
|
|
|
77
78
|
toolbarItem,
|
|
78
79
|
isPaginated = false,
|
|
79
80
|
isSearching = false,
|
|
81
|
+
searchPlaceholderKey,
|
|
80
82
|
onSelect,
|
|
81
83
|
onDelete,
|
|
82
84
|
deleteLabel = "delete",
|
|
@@ -91,6 +93,7 @@ export const OrganizationTable = ({
|
|
|
91
93
|
isPaginated={isPaginated}
|
|
92
94
|
isSearching={isSearching}
|
|
93
95
|
ariaLabelKey="organizationList"
|
|
96
|
+
searchPlaceholderKey={searchPlaceholderKey}
|
|
94
97
|
toolbarItem={toolbarItem}
|
|
95
98
|
onSelect={onSelect}
|
|
96
99
|
canSelectAll={onSelect !== undefined}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "react-hook-form";
|
|
13
13
|
import { SwitchProps, Switch } from "../../@patternfly/react-core";
|
|
14
14
|
import { FormLabel } from "./FormLabel";
|
|
15
|
+
import { debeerify } from "../user-profile/utils";
|
|
15
16
|
|
|
16
17
|
export type SwitchControlProps<
|
|
17
18
|
T extends FieldValues,
|
|
@@ -55,7 +56,7 @@ export const SwitchControl = <
|
|
|
55
56
|
<Switch
|
|
56
57
|
{...props}
|
|
57
58
|
id={props.name}
|
|
58
|
-
data-testid={props.name}
|
|
59
|
+
data-testid={debeerify(props.name)}
|
|
59
60
|
label={labelOn}
|
|
60
61
|
isChecked={stringify ? value === "true" : value}
|
|
61
62
|
onChange={(e, checked) => {
|
|
@@ -53,6 +53,10 @@ export type SelectControlProps<
|
|
|
53
53
|
menuAppendTo?: string;
|
|
54
54
|
placeholderText?: string;
|
|
55
55
|
chipGroupProps?: ChipGroupProps;
|
|
56
|
+
onSelect?: (
|
|
57
|
+
value: string | string[],
|
|
58
|
+
onChangeHandler: (value: string | string[]) => void,
|
|
59
|
+
) => void;
|
|
56
60
|
};
|
|
57
61
|
|
|
58
62
|
export const isSelectBasedOptions = (
|
package/keycloak-theme/shared/keycloak-ui-shared/controls/select-control/SingleSelectControl.tsx
CHANGED
|
@@ -36,6 +36,8 @@ export const SingleSelectControl = <
|
|
|
36
36
|
options,
|
|
37
37
|
controller,
|
|
38
38
|
labelIcon,
|
|
39
|
+
isDisabled,
|
|
40
|
+
onSelect,
|
|
39
41
|
...rest
|
|
40
42
|
}: SelectControlProps<T, P>) => {
|
|
41
43
|
const {
|
|
@@ -60,6 +62,7 @@ export const SingleSelectControl = <
|
|
|
60
62
|
render={({ field: { onChange, value } }) => (
|
|
61
63
|
<Select
|
|
62
64
|
{...rest}
|
|
65
|
+
variant="default"
|
|
63
66
|
onClick={() => setOpen(!open)}
|
|
64
67
|
onOpenChange={() => setOpen(false)}
|
|
65
68
|
selected={
|
|
@@ -81,7 +84,8 @@ export const SingleSelectControl = <
|
|
|
81
84
|
isExpanded={open}
|
|
82
85
|
isFullWidth
|
|
83
86
|
status={get(errors, name) ? MenuToggleStatus.danger : undefined}
|
|
84
|
-
aria-label=
|
|
87
|
+
aria-label={label}
|
|
88
|
+
isDisabled={isDisabled}
|
|
85
89
|
>
|
|
86
90
|
{isSelectBasedOptions(options)
|
|
87
91
|
? options.find(
|
|
@@ -92,8 +96,13 @@ export const SingleSelectControl = <
|
|
|
92
96
|
</MenuToggle>
|
|
93
97
|
)}
|
|
94
98
|
onSelect={(_event, v) => {
|
|
95
|
-
const option = v?.toString()
|
|
96
|
-
|
|
99
|
+
const option = v?.toString()!;
|
|
100
|
+
const convertedValue = Array.isArray(value) ? [option] : option;
|
|
101
|
+
if (onSelect) {
|
|
102
|
+
onSelect(convertedValue, onChange);
|
|
103
|
+
} else {
|
|
104
|
+
onChange(convertedValue);
|
|
105
|
+
}
|
|
97
106
|
setOpen(false);
|
|
98
107
|
}}
|
|
99
108
|
isOpen={open}
|
|
@@ -160,24 +160,31 @@ function DataTable<T>({
|
|
|
160
160
|
};
|
|
161
161
|
|
|
162
162
|
const updateState = (rowIndex: number, isSelected: boolean) => {
|
|
163
|
-
if (
|
|
164
|
-
const
|
|
165
|
-
updateSelectedRows(
|
|
166
|
-
isSelected
|
|
167
|
-
? [...selectedRows, ...rows.map((row) => row.data)]
|
|
168
|
-
: selectedRows.filter(
|
|
169
|
-
(v) => !rowsSelectedOnPageIds.includes(get(v, "id")),
|
|
170
|
-
),
|
|
171
|
-
);
|
|
163
|
+
if (isRadio) {
|
|
164
|
+
const selectedRow = isSelected ? [rows[rowIndex].data] : [];
|
|
165
|
+
updateSelectedRows(selectedRow);
|
|
172
166
|
} else {
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
167
|
+
if (rowIndex === -1) {
|
|
168
|
+
const rowsSelectedOnPageIds = rowsSelectedOnPage.map((v) =>
|
|
169
|
+
get(v, "id"),
|
|
170
|
+
);
|
|
176
171
|
updateSelectedRows(
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
172
|
+
isSelected
|
|
173
|
+
? [...selectedRows, ...rows.map((row) => row.data)]
|
|
174
|
+
: selectedRows.filter(
|
|
175
|
+
(v) => !rowsSelectedOnPageIds.includes(get(v, "id")),
|
|
176
|
+
),
|
|
180
177
|
);
|
|
178
|
+
} else {
|
|
179
|
+
if (isSelected) {
|
|
180
|
+
updateSelectedRows([...selectedRows, rows[rowIndex].data]);
|
|
181
|
+
} else {
|
|
182
|
+
updateSelectedRows(
|
|
183
|
+
selectedRows.filter(
|
|
184
|
+
(v) => get(v, "id") !== (rows[rowIndex] as IRow).data.id,
|
|
185
|
+
),
|
|
186
|
+
);
|
|
187
|
+
}
|
|
181
188
|
}
|
|
182
189
|
}
|
|
183
190
|
};
|
|
@@ -250,17 +257,21 @@ function DataTable<T>({
|
|
|
250
257
|
{index % 2 === 0 ? (
|
|
251
258
|
<Tr>
|
|
252
259
|
<Td
|
|
253
|
-
expand={
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
260
|
+
expand={
|
|
261
|
+
rows[index + 1].cells.length === 0
|
|
262
|
+
? undefined
|
|
263
|
+
: {
|
|
264
|
+
isExpanded: !!expandedRows[index],
|
|
265
|
+
rowIndex: index,
|
|
266
|
+
expandId: "expandable-row-",
|
|
267
|
+
onToggle: (_, rowIndex, isOpen) => {
|
|
268
|
+
onCollapse(isOpen, rowIndex);
|
|
269
|
+
const expand = [...expandedRows];
|
|
270
|
+
expand[index] = isOpen;
|
|
271
|
+
setExpandedRows(expand);
|
|
272
|
+
},
|
|
273
|
+
}
|
|
274
|
+
}
|
|
264
275
|
/>
|
|
265
276
|
<CellRenderer
|
|
266
277
|
row={row}
|
|
@@ -552,7 +563,7 @@ export function KeycloakDataTable<T>({
|
|
|
552
563
|
|
|
553
564
|
return (
|
|
554
565
|
<>
|
|
555
|
-
{(
|
|
566
|
+
{(!noData || searching) && (
|
|
556
567
|
<PaginatingTableToolbar
|
|
557
568
|
id={id}
|
|
558
569
|
count={rowLength}
|
|
@@ -575,7 +586,7 @@ export function KeycloakDataTable<T>({
|
|
|
575
586
|
<>
|
|
576
587
|
{toolbarItem} <ToolbarItem variant="separator" />{" "}
|
|
577
588
|
<ToolbarItem>
|
|
578
|
-
<Button variant="link" onClick={refresh}>
|
|
589
|
+
<Button variant="link" onClick={refresh} data-testid="refresh">
|
|
579
590
|
<SyncAltIcon /> {t("refresh")}
|
|
580
591
|
</Button>
|
|
581
592
|
</ToolbarItem>
|
|
@@ -623,9 +634,9 @@ export function KeycloakDataTable<T>({
|
|
|
623
634
|
}
|
|
624
635
|
/>
|
|
625
636
|
)}
|
|
626
|
-
{loading && <KeycloakSpinner />}
|
|
627
637
|
</PaginatingTableToolbar>
|
|
628
638
|
)}
|
|
639
|
+
{loading && <KeycloakSpinner />}
|
|
629
640
|
{!loading && noData && !searching && emptyState}
|
|
630
641
|
</>
|
|
631
642
|
);
|
|
@@ -58,6 +58,7 @@ type KeycloakMastheadProps = MastheadMainProps & {
|
|
|
58
58
|
kebabDropdownItems?: ReactNode[];
|
|
59
59
|
dropdownItems?: ReactNode[];
|
|
60
60
|
toolbarItems?: ReactNode[];
|
|
61
|
+
toolbar?: ReactNode;
|
|
61
62
|
};
|
|
62
63
|
|
|
63
64
|
const KeycloakMasthead = ({
|
|
@@ -72,6 +73,7 @@ const KeycloakMasthead = ({
|
|
|
72
73
|
kebabDropdownItems,
|
|
73
74
|
dropdownItems = [],
|
|
74
75
|
toolbarItems,
|
|
76
|
+
toolbar,
|
|
75
77
|
...rest
|
|
76
78
|
}: KeycloakMastheadProps) => {
|
|
77
79
|
const { t } = useTranslation();
|
|
@@ -106,6 +108,7 @@ const KeycloakMasthead = ({
|
|
|
106
108
|
<img src={src} alt={alt} className={className} />
|
|
107
109
|
</MastheadBrand>
|
|
108
110
|
<MastheadContent>
|
|
111
|
+
{toolbar}
|
|
109
112
|
<Toolbar>
|
|
110
113
|
<ToolbarContent>
|
|
111
114
|
{toolbarItems?.map((item, index) => (
|
|
@@ -19,7 +19,7 @@ export const propertyToString = (prop: string | number | undefined) =>
|
|
|
19
19
|
|
|
20
20
|
export type KeycloakSelectProps = Omit<
|
|
21
21
|
SelectProps,
|
|
22
|
-
"name" | "toggle" | "selected" | "onClick" | "onSelect"
|
|
22
|
+
"name" | "toggle" | "selected" | "onClick" | "onSelect" | "variant"
|
|
23
23
|
> & {
|
|
24
24
|
toggleId?: string;
|
|
25
25
|
onFilter?: (value: string) => JSX.Element[];
|
|
@@ -119,7 +119,11 @@ export const TypeaheadSelect = ({
|
|
|
119
119
|
{...rest}
|
|
120
120
|
onClick={toggle}
|
|
121
121
|
onOpenChange={(isOpen) => onToggle?.(isOpen)}
|
|
122
|
-
onSelect={(_, value) =>
|
|
122
|
+
onSelect={(_, value) => {
|
|
123
|
+
onSelect?.(value || "");
|
|
124
|
+
onFilter?.("");
|
|
125
|
+
setFilterValue("");
|
|
126
|
+
}}
|
|
123
127
|
maxMenuHeight={propertyToString(maxHeight)}
|
|
124
128
|
popperProps={{ direction, width: propertyToString(width) }}
|
|
125
129
|
toggle={(ref) => (
|
|
@@ -47,7 +47,7 @@ export const LocaleSelector = ({
|
|
|
47
47
|
name="attributes.locale"
|
|
48
48
|
label={t("selectALocale")}
|
|
49
49
|
controller={{ defaultValue: "" }}
|
|
50
|
-
options={locales}
|
|
50
|
+
options={[{ key: "", value: t("defaultLocale") }, ...locales]}
|
|
51
51
|
variant={locales.length >= 10 ? "typeahead" : "single"}
|
|
52
52
|
/>
|
|
53
53
|
</FormProvider>
|
|
@@ -77,12 +77,13 @@ export function setUserProfileServerError<T>(
|
|
|
77
77
|
).forEach((e) => {
|
|
78
78
|
const params = Object.assign(
|
|
79
79
|
{},
|
|
80
|
-
e.params?.map((p) => (isBundleKey(p
|
|
80
|
+
e.params?.map((p) => (isBundleKey(p?.toString()) ? t(unWrap(p)) : p)),
|
|
81
81
|
);
|
|
82
82
|
setError(fieldName(e.field) as keyof T, {
|
|
83
83
|
message: t(
|
|
84
84
|
isBundleKey(e.errorMessage) ? unWrap(e.errorMessage) : e.errorMessage,
|
|
85
85
|
{
|
|
86
|
+
/* eslint-disable @typescript-eslint/no-misused-spread */
|
|
86
87
|
...params,
|
|
87
88
|
defaultValue: e.errorMessage || e.field,
|
|
88
89
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keycloakify/keycloak-ui-shared",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "260200.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git://github.com/keycloakify/keycloak-ui-shared.git"
|
|
@@ -9,19 +9,19 @@
|
|
|
9
9
|
"author": "The Keycloak Team, re-packaged by u/garronej",
|
|
10
10
|
"homepage": "https://github.com/keycloakify/keycloak-ui-shared",
|
|
11
11
|
"peerDependencies": {
|
|
12
|
-
"@patternfly/react-core": "^5.4.
|
|
12
|
+
"@patternfly/react-core": "^5.4.14",
|
|
13
13
|
"@patternfly/react-icons": "^5.4.2",
|
|
14
14
|
"@patternfly/react-styles": "^5.4.1",
|
|
15
|
-
"@patternfly/react-table": "^5.4.
|
|
16
|
-
"i18next": "^24.2.
|
|
15
|
+
"@patternfly/react-table": "^5.4.16",
|
|
16
|
+
"i18next": "^24.2.3",
|
|
17
|
+
"keycloak-js": "^26.2.0",
|
|
17
18
|
"lodash-es": "^4.17.21",
|
|
18
19
|
"react": "^18.3.1",
|
|
19
20
|
"react-hook-form": "7.54.2",
|
|
20
|
-
"react-i18next": "^15.4.
|
|
21
|
-
"@keycloak/keycloak-admin-client": "26.
|
|
22
|
-
"keycloak-js": "26.1.3",
|
|
21
|
+
"react-i18next": "^15.4.1",
|
|
22
|
+
"@keycloak/keycloak-admin-client": "26.2.0",
|
|
23
23
|
"@types/lodash-es": "^4.17.12",
|
|
24
|
-
"@types/react": "^18.3.
|
|
24
|
+
"@types/react": "^18.3.18"
|
|
25
25
|
},
|
|
26
26
|
"publishConfig": {
|
|
27
27
|
"access": "public"
|