@workos-inc/widgets 1.1.5 → 1.2.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/dist/cjs/lib/organization-switcher.d.ts +10 -1
- package/dist/cjs/lib/organization-switcher.d.ts.map +1 -1
- package/dist/cjs/lib/organization-switcher.js +31 -3
- package/dist/cjs/lib/organization-switcher.js.map +1 -1
- package/dist/cjs/workos-widgets.client.d.ts +6 -0
- package/dist/cjs/workos-widgets.client.d.ts.map +1 -1
- package/dist/cjs/workos-widgets.client.js +23 -3
- package/dist/cjs/workos-widgets.client.js.map +1 -1
- package/dist/esm/lib/organization-switcher.d.ts +10 -1
- package/dist/esm/lib/organization-switcher.d.ts.map +1 -1
- package/dist/esm/lib/organization-switcher.js +31 -3
- package/dist/esm/lib/organization-switcher.js.map +1 -1
- package/dist/esm/workos-widgets.client.d.ts +6 -0
- package/dist/esm/workos-widgets.client.d.ts.map +1 -1
- package/dist/esm/workos-widgets.client.js +25 -5
- package/dist/esm/workos-widgets.client.js.map +1 -1
- package/package.json +8 -9
- package/src/api/api-provider.tsx +0 -158
- package/src/api/constants.ts +0 -1
- package/src/api/endpoint.ts +0 -3097
- package/src/api/errors.ts +0 -48
- package/src/api/index.ts +0 -2
- package/src/api/utils.ts +0 -42
- package/src/api/widgets-api-client.ts +0 -87
- package/src/card-list.tsx +0 -26
- package/src/index.ts +0 -9
- package/src/lib/add-mfa-dialog.tsx +0 -379
- package/src/lib/api/config.ts +0 -9
- package/src/lib/api/user.ts +0 -98
- package/src/lib/change-password-dialog.tsx +0 -290
- package/src/lib/constants.ts +0 -3
- package/src/lib/copy-button.tsx +0 -53
- package/src/lib/delete-user-dialog.tsx +0 -110
- package/src/lib/edit-user-profile-dialog.tsx +0 -181
- package/src/lib/edit-user-role-dialog.tsx +0 -178
- package/src/lib/elements.tsx +0 -428
- package/src/lib/elevated-access.tsx +0 -261
- package/src/lib/error-boundary.tsx +0 -166
- package/src/lib/errors.ts +0 -49
- package/src/lib/generic-error.tsx +0 -70
- package/src/lib/icon-panel.tsx +0 -26
- package/src/lib/icons.tsx +0 -21
- package/src/lib/invite-user-dialog.tsx +0 -327
- package/src/lib/logout-all-sessions-dialog.tsx +0 -82
- package/src/lib/logout-dialog.tsx +0 -85
- package/src/lib/marker.tsx +0 -39
- package/src/lib/oauth-icons.tsx +0 -138
- package/src/lib/organization-switcher.tsx +0 -156
- package/src/lib/otp-input.tsx +0 -276
- package/src/lib/resend-invite-dialog.tsx +0 -145
- package/src/lib/reset-mfa-dialog.tsx +0 -104
- package/src/lib/revoke-invite-dialog.tsx +0 -111
- package/src/lib/save-button.tsx +0 -113
- package/src/lib/search-provider.tsx +0 -51
- package/src/lib/set-password-dialog.tsx +0 -204
- package/src/lib/use-dialog-close.tsx +0 -19
- package/src/lib/use-is-hydrated.ts +0 -13
- package/src/lib/use-layout-effect.ts +0 -6
- package/src/lib/use-security-settings.tsx +0 -49
- package/src/lib/user-actions-dropdown.tsx +0 -157
- package/src/lib/user-profile.tsx +0 -227
- package/src/lib/user-security.tsx +0 -187
- package/src/lib/user-sessions.tsx +0 -204
- package/src/lib/users-filter.tsx +0 -62
- package/src/lib/users-management-context.tsx +0 -74
- package/src/lib/users-management-state.ts +0 -165
- package/src/lib/users-management.tsx +0 -594
- package/src/lib/users-search.tsx +0 -73
- package/src/lib/utils.ts +0 -131
- package/src/lib/widgets-context.ts +0 -29
- package/src/organization-switcher.client.tsx +0 -81
- package/src/user-profile.client.tsx +0 -55
- package/src/user-security.client.tsx +0 -55
- package/src/user-sessions.client.tsx +0 -100
- package/src/users-management.client.tsx +0 -73
- package/src/workos-widgets.client.tsx +0 -75
- /package/{src → dist/css}/base.css +0 -0
- /package/{src → dist/css}/lib/card-list.css +0 -0
- /package/{src → dist/css}/lib/marker.css +0 -0
- /package/{src → dist/css}/lib/save-button.css +0 -0
- /package/{src → dist/css}/styles.css +0 -0
- /package/{src → dist/css}/users-management.css +0 -0
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Box, Button, Card, Flex, Text } from "@radix-ui/themes";
|
|
4
|
-
import clsx from "clsx";
|
|
5
|
-
import { Badge, SecondaryButton, Skeleton } from "./elements";
|
|
6
|
-
import {
|
|
7
|
-
getComparativeReadableDate,
|
|
8
|
-
getUserLocation,
|
|
9
|
-
parseUserAgent,
|
|
10
|
-
} from "./utils";
|
|
11
|
-
import { LogoutDialog } from "./logout-dialog";
|
|
12
|
-
import { LogoutAllSessionsDialog } from "./logout-all-sessions-dialog";
|
|
13
|
-
import { ActiveSession } from "../api";
|
|
14
|
-
import * as CardList from "../card-list";
|
|
15
|
-
import { IconPanel } from "./icon-panel";
|
|
16
|
-
import { useState } from "react";
|
|
17
|
-
import { GenericError } from "./generic-error";
|
|
18
|
-
import { LaptopIcon, MobileIcon } from "@radix-ui/react-icons";
|
|
19
|
-
|
|
20
|
-
interface UserSessionsProps {
|
|
21
|
-
sessionsData: ActiveSession[];
|
|
22
|
-
currentSessionId: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export const UserSessions = ({
|
|
26
|
-
sessionsData: sessions,
|
|
27
|
-
currentSessionId,
|
|
28
|
-
}: UserSessionsProps) => {
|
|
29
|
-
const currentSession = sessions.find(
|
|
30
|
-
(session) => session.id === currentSessionId,
|
|
31
|
-
);
|
|
32
|
-
const otherSessions = sessions.filter(
|
|
33
|
-
(session) => session.id !== currentSessionId,
|
|
34
|
-
);
|
|
35
|
-
const [openLogoutDialog, setOpenLogoutDialog] = useState(false);
|
|
36
|
-
const [sessionToSignOut, setSessionToSignOut] =
|
|
37
|
-
useState<ActiveSession | null>(null);
|
|
38
|
-
const [openLogoutAllSessionsDialog, setOpenLogoutAllSessionsDialog] =
|
|
39
|
-
useState(false);
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<Flex
|
|
43
|
-
direction="column"
|
|
44
|
-
gap="4"
|
|
45
|
-
className={clsx("woswidgets-widget")}
|
|
46
|
-
data-woswidgets-widget-id="user-sessions"
|
|
47
|
-
>
|
|
48
|
-
<CardList.Root>
|
|
49
|
-
{currentSession && (
|
|
50
|
-
<CardList.Item>
|
|
51
|
-
<UserSession session={currentSession} isCurrentSession />
|
|
52
|
-
</CardList.Item>
|
|
53
|
-
)}
|
|
54
|
-
|
|
55
|
-
{otherSessions.map((session) => (
|
|
56
|
-
<CardList.Item key={session.id}>
|
|
57
|
-
<UserSession
|
|
58
|
-
session={session}
|
|
59
|
-
onSignOut={() => {
|
|
60
|
-
setSessionToSignOut(session);
|
|
61
|
-
setOpenLogoutDialog(true);
|
|
62
|
-
}}
|
|
63
|
-
/>
|
|
64
|
-
</CardList.Item>
|
|
65
|
-
))}
|
|
66
|
-
</CardList.Root>
|
|
67
|
-
|
|
68
|
-
{sessions.length > 1 && (
|
|
69
|
-
<Card size="2">
|
|
70
|
-
<Flex gap="2" justify="between" align="center">
|
|
71
|
-
<Box>
|
|
72
|
-
<Text size="2" highContrast weight="bold" as="p">
|
|
73
|
-
Sign out of all other devices
|
|
74
|
-
</Text>
|
|
75
|
-
<Text size="2" color="gray" as="p">
|
|
76
|
-
Remove access from all devices except this one
|
|
77
|
-
</Text>
|
|
78
|
-
</Box>
|
|
79
|
-
|
|
80
|
-
<SecondaryButton
|
|
81
|
-
onClick={() => {
|
|
82
|
-
setOpenLogoutAllSessionsDialog(true);
|
|
83
|
-
}}
|
|
84
|
-
>
|
|
85
|
-
Sign out
|
|
86
|
-
</SecondaryButton>
|
|
87
|
-
</Flex>
|
|
88
|
-
</Card>
|
|
89
|
-
)}
|
|
90
|
-
|
|
91
|
-
{sessionToSignOut && (
|
|
92
|
-
<LogoutDialog
|
|
93
|
-
session={sessionToSignOut}
|
|
94
|
-
open={openLogoutDialog}
|
|
95
|
-
onOpenChange={setOpenLogoutDialog}
|
|
96
|
-
/>
|
|
97
|
-
)}
|
|
98
|
-
|
|
99
|
-
<LogoutAllSessionsDialog
|
|
100
|
-
currentSessionId={currentSessionId}
|
|
101
|
-
open={openLogoutAllSessionsDialog}
|
|
102
|
-
onOpenChange={setOpenLogoutAllSessionsDialog}
|
|
103
|
-
/>
|
|
104
|
-
</Flex>
|
|
105
|
-
);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
export function UserSessionsLoading() {
|
|
109
|
-
return (
|
|
110
|
-
<Card size="2">
|
|
111
|
-
<Flex gap="4" align="center">
|
|
112
|
-
<Skeleton>
|
|
113
|
-
<IconPanel />
|
|
114
|
-
</Skeleton>
|
|
115
|
-
|
|
116
|
-
<Flex direction="column">
|
|
117
|
-
<Text size="2" highContrast weight="bold" as="p" mb="-2px">
|
|
118
|
-
<Skeleton>The location</Skeleton>
|
|
119
|
-
</Text>
|
|
120
|
-
|
|
121
|
-
<Text size="2" color="gray" as="p">
|
|
122
|
-
<Skeleton>The location</Skeleton>
|
|
123
|
-
</Text>
|
|
124
|
-
</Flex>
|
|
125
|
-
</Flex>
|
|
126
|
-
</Card>
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function UserSessionsError({ error }: { error: unknown }) {
|
|
131
|
-
return (
|
|
132
|
-
<Card size="2">
|
|
133
|
-
<GenericError error={error} />
|
|
134
|
-
</Card>
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
interface UserSessionProps {
|
|
139
|
-
session: ActiveSession;
|
|
140
|
-
isCurrentSession?: boolean;
|
|
141
|
-
onSignOut?: (session: ActiveSession) => void;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const UserSession = ({
|
|
145
|
-
session,
|
|
146
|
-
isCurrentSession = false,
|
|
147
|
-
onSignOut,
|
|
148
|
-
}: UserSessionProps) => {
|
|
149
|
-
const userAgent = parseUserAgent(session.userAgent);
|
|
150
|
-
const userLocation = getUserLocation(
|
|
151
|
-
session.currentLocation,
|
|
152
|
-
session.ipAddress,
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
return (
|
|
156
|
-
<Flex gap="4" align="center">
|
|
157
|
-
<IconPanel>
|
|
158
|
-
{userAgent.isMobile ? <MobileIcon /> : <LaptopIcon />}
|
|
159
|
-
</IconPanel>
|
|
160
|
-
|
|
161
|
-
<Flex direction="column">
|
|
162
|
-
<Text size="2" highContrast weight="bold" as="p" mb="-2px">
|
|
163
|
-
{userAgent.pretty}
|
|
164
|
-
</Text>
|
|
165
|
-
|
|
166
|
-
<Flex gap="1" align="center">
|
|
167
|
-
<Text size="2" color="gray" as="p">
|
|
168
|
-
{userLocation}
|
|
169
|
-
</Text>
|
|
170
|
-
|
|
171
|
-
{isCurrentSession && <Badge ml="2">This device</Badge>}
|
|
172
|
-
|
|
173
|
-
{!isCurrentSession && session.lastActivityAt && (
|
|
174
|
-
<>
|
|
175
|
-
<Text size="2" color="gray">
|
|
176
|
-
∙
|
|
177
|
-
</Text>
|
|
178
|
-
<Text size="2" color="gray">
|
|
179
|
-
Last seen{" "}
|
|
180
|
-
{getComparativeReadableDate(
|
|
181
|
-
new Date(),
|
|
182
|
-
new Date(session.lastActivityAt),
|
|
183
|
-
)}
|
|
184
|
-
</Text>
|
|
185
|
-
</>
|
|
186
|
-
)}
|
|
187
|
-
</Flex>
|
|
188
|
-
</Flex>
|
|
189
|
-
|
|
190
|
-
{!isCurrentSession && (
|
|
191
|
-
<Flex ml="auto" mr="2">
|
|
192
|
-
<Button
|
|
193
|
-
variant="ghost"
|
|
194
|
-
onClick={() => {
|
|
195
|
-
onSignOut?.(session);
|
|
196
|
-
}}
|
|
197
|
-
>
|
|
198
|
-
Sign out
|
|
199
|
-
</Button>
|
|
200
|
-
</Flex>
|
|
201
|
-
)}
|
|
202
|
-
</Flex>
|
|
203
|
-
);
|
|
204
|
-
};
|
package/src/lib/users-filter.tsx
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import { Select } from "@radix-ui/themes";
|
|
4
|
-
import * as React from "react";
|
|
5
|
-
import { SelectContent, SelectItem, SelectTrigger } from "./elements";
|
|
6
|
-
import { useUsersManagementContext } from "./users-management-context";
|
|
7
|
-
import { MemberRole } from "../api";
|
|
8
|
-
|
|
9
|
-
const ALL_ROLES_NAME = "All";
|
|
10
|
-
const ALL_ROLES_VALUE = "null";
|
|
11
|
-
|
|
12
|
-
type UsersFilterProps = React.ComponentPropsWithoutRef<typeof Select.Root> & {
|
|
13
|
-
roles: MemberRole[] | undefined;
|
|
14
|
-
disabled?: boolean;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const UsersFilter: React.FC<UsersFilterProps> = ({
|
|
18
|
-
roles,
|
|
19
|
-
disabled,
|
|
20
|
-
}) => {
|
|
21
|
-
const {
|
|
22
|
-
dispatch,
|
|
23
|
-
state: { role },
|
|
24
|
-
} = useUsersManagementContext();
|
|
25
|
-
|
|
26
|
-
const setFilterParams = (value: string | null) => {
|
|
27
|
-
dispatch({ type: "FILTER_BY_ROLE", role: value });
|
|
28
|
-
};
|
|
29
|
-
const isValidRole = (value: unknown): value is string =>
|
|
30
|
-
roles ? roles.findIndex((role) => role.slug === value) !== -1 : false;
|
|
31
|
-
const filteredRole = isValidRole(role) ? role : ALL_ROLES_VALUE;
|
|
32
|
-
const roleName =
|
|
33
|
-
roles?.find((role) => role.slug === filteredRole)?.name || ALL_ROLES_NAME;
|
|
34
|
-
|
|
35
|
-
const onValueChange = (value: string) => {
|
|
36
|
-
if (value === ALL_ROLES_VALUE) {
|
|
37
|
-
setFilterParams(null);
|
|
38
|
-
} else {
|
|
39
|
-
if (isValidRole(value)) {
|
|
40
|
-
setFilterParams(value);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<Select.Root
|
|
47
|
-
value={roles ? filteredRole : "null"}
|
|
48
|
-
onValueChange={onValueChange}
|
|
49
|
-
disabled={disabled}
|
|
50
|
-
>
|
|
51
|
-
<SelectTrigger>{roles ? roleName : ALL_ROLES_NAME}</SelectTrigger>
|
|
52
|
-
<SelectContent>
|
|
53
|
-
<SelectItem value={ALL_ROLES_VALUE}>{ALL_ROLES_NAME}</SelectItem>
|
|
54
|
-
{roles?.map((role) => (
|
|
55
|
-
<React.Fragment key={role.slug}>
|
|
56
|
-
<SelectItem value={role.slug}>{role.name}</SelectItem>
|
|
57
|
-
</React.Fragment>
|
|
58
|
-
))}
|
|
59
|
-
</SelectContent>
|
|
60
|
-
</Select.Root>
|
|
61
|
-
);
|
|
62
|
-
};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import {
|
|
5
|
-
UsersManagementAction,
|
|
6
|
-
UsersManagementState,
|
|
7
|
-
useUsersManagementState,
|
|
8
|
-
} from "./users-management-state";
|
|
9
|
-
import { ListMetadata } from "../api";
|
|
10
|
-
|
|
11
|
-
export interface UsersManagementContextType {
|
|
12
|
-
state: UsersManagementState;
|
|
13
|
-
dispatch: React.Dispatch<UsersManagementAction>;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const UsersManagementContext = React.createContext<
|
|
17
|
-
UsersManagementContextType | undefined
|
|
18
|
-
>(undefined);
|
|
19
|
-
UsersManagementContext.displayName = "UsersManagementContext";
|
|
20
|
-
|
|
21
|
-
const initialState: UsersManagementState = {
|
|
22
|
-
pagination: null,
|
|
23
|
-
role: null,
|
|
24
|
-
searchQuery: null,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const UsersManagementContextProvider: React.FC<{
|
|
28
|
-
children?: React.ReactNode;
|
|
29
|
-
}> = ({ children }) => {
|
|
30
|
-
const [state, dispatch] = useUsersManagementState(initialState);
|
|
31
|
-
|
|
32
|
-
const context = React.useMemo<UsersManagementContextType>(
|
|
33
|
-
() => ({
|
|
34
|
-
state,
|
|
35
|
-
dispatch,
|
|
36
|
-
}),
|
|
37
|
-
[state, dispatch],
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<UsersManagementContext.Provider value={context}>
|
|
42
|
-
{children}
|
|
43
|
-
</UsersManagementContext.Provider>
|
|
44
|
-
);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const NOOP = () => void 0;
|
|
48
|
-
const EMPTY_PAGINATION: ListMetadata = {};
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* The context may be provided if it is instantiated in the tree above the user.
|
|
52
|
-
*/
|
|
53
|
-
export function useUsersManagementContext(
|
|
54
|
-
initialContext?: UsersManagementContextType | null,
|
|
55
|
-
): UsersManagementContextType {
|
|
56
|
-
const context = React.useContext(UsersManagementContext);
|
|
57
|
-
|
|
58
|
-
if (context) {
|
|
59
|
-
return context;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (initialContext) {
|
|
63
|
-
return initialContext;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
dispatch: NOOP,
|
|
68
|
-
state: {
|
|
69
|
-
pagination: EMPTY_PAGINATION,
|
|
70
|
-
role: null,
|
|
71
|
-
searchQuery: null,
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
}
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import { canUseDOM } from "./utils";
|
|
3
|
-
import { ListMetadata } from "../api";
|
|
4
|
-
|
|
5
|
-
export function useUsersManagementState(initialState: UsersManagementState) {
|
|
6
|
-
const [[state, effects], dispatch] = React.useReducer(reducer, [
|
|
7
|
-
initialState,
|
|
8
|
-
[],
|
|
9
|
-
]);
|
|
10
|
-
|
|
11
|
-
React.useEffect(() => {
|
|
12
|
-
if (window !== window.top) {
|
|
13
|
-
// do not use query params if widget is rendered in an iframe
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const params = new URLSearchParams(window.location.search);
|
|
17
|
-
dispatch({ type: "INIT", params });
|
|
18
|
-
}, []);
|
|
19
|
-
|
|
20
|
-
React.useEffect(() => {
|
|
21
|
-
for (const effect of effects) {
|
|
22
|
-
effect();
|
|
23
|
-
}
|
|
24
|
-
}, [effects]);
|
|
25
|
-
|
|
26
|
-
return [state, dispatch] as const;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function reducer(
|
|
30
|
-
current: StateWithEffects<UsersManagementState>,
|
|
31
|
-
action: UsersManagementAction,
|
|
32
|
-
): StateWithEffects<UsersManagementState> {
|
|
33
|
-
const effects: EffectFn[] = [];
|
|
34
|
-
const exec = (fn: () => void) => {
|
|
35
|
-
const effect = () => {
|
|
36
|
-
if (!effect.disposed) {
|
|
37
|
-
effect.disposed = true;
|
|
38
|
-
fn();
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
effect.disposed = false;
|
|
42
|
-
effects.push(effect);
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const [currentState] = current;
|
|
46
|
-
switch (action.type) {
|
|
47
|
-
case "INIT": {
|
|
48
|
-
const { params } = action;
|
|
49
|
-
let role, searchQuery;
|
|
50
|
-
if ((role = params.get("ak_role"))) {
|
|
51
|
-
return [{ ...currentState, searchQuery: null, role }, effects];
|
|
52
|
-
}
|
|
53
|
-
if ((searchQuery = params.get("ak_q"))) {
|
|
54
|
-
return [{ ...currentState, searchQuery, role: null }, effects];
|
|
55
|
-
}
|
|
56
|
-
return current;
|
|
57
|
-
}
|
|
58
|
-
case "SET_PAGINATION": {
|
|
59
|
-
const { pagination } = action;
|
|
60
|
-
if (
|
|
61
|
-
(pagination.after &&
|
|
62
|
-
pagination.after === currentState.pagination?.after) ||
|
|
63
|
-
(pagination.before &&
|
|
64
|
-
pagination.before === currentState.pagination?.before)
|
|
65
|
-
) {
|
|
66
|
-
return current;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return [{ ...currentState, pagination }, effects];
|
|
70
|
-
}
|
|
71
|
-
case "FILTER_BY_ROLE": {
|
|
72
|
-
if (action.role === currentState.role) {
|
|
73
|
-
return current;
|
|
74
|
-
}
|
|
75
|
-
const { role } = action;
|
|
76
|
-
exec(() =>
|
|
77
|
-
updateQueryParams(
|
|
78
|
-
{ ak_role: role, ak_q: null },
|
|
79
|
-
{ replaceState: true },
|
|
80
|
-
),
|
|
81
|
-
);
|
|
82
|
-
return [
|
|
83
|
-
{ ...currentState, pagination: null, role, searchQuery: null },
|
|
84
|
-
effects,
|
|
85
|
-
];
|
|
86
|
-
}
|
|
87
|
-
case "FILTER_BY_SEARCH": {
|
|
88
|
-
if (action.searchQuery === currentState.searchQuery) {
|
|
89
|
-
return current;
|
|
90
|
-
}
|
|
91
|
-
const { searchQuery } = action;
|
|
92
|
-
exec(() =>
|
|
93
|
-
updateQueryParams(
|
|
94
|
-
{ ak_role: null, ak_q: searchQuery },
|
|
95
|
-
{ replaceState: true },
|
|
96
|
-
),
|
|
97
|
-
);
|
|
98
|
-
return [
|
|
99
|
-
{ ...currentState, pagination: null, role: null, searchQuery },
|
|
100
|
-
effects,
|
|
101
|
-
];
|
|
102
|
-
//
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
105
|
-
default:
|
|
106
|
-
return current;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export interface UsersManagementState {
|
|
111
|
-
searchQuery: string | null;
|
|
112
|
-
role: string | null;
|
|
113
|
-
pagination: ListMetadata | null;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export type UsersManagementAction =
|
|
117
|
-
| { type: "INIT"; params: URLSearchParams }
|
|
118
|
-
| { type: "FILTER_BY_SEARCH"; searchQuery: string | null }
|
|
119
|
-
| { type: "FILTER_BY_ROLE"; role: string | null }
|
|
120
|
-
| { type: "SET_PAGINATION"; pagination: ListMetadata };
|
|
121
|
-
|
|
122
|
-
type EffectFn = {
|
|
123
|
-
(): void;
|
|
124
|
-
disposed: boolean;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
type StateWithEffects<State> = [State, EffectFn[]];
|
|
128
|
-
|
|
129
|
-
function updateQueryParams(
|
|
130
|
-
newParams: { [key: string]: { toString(): string } | null },
|
|
131
|
-
args: { replaceState?: boolean } = {},
|
|
132
|
-
) {
|
|
133
|
-
if (!canUseDOM) {
|
|
134
|
-
throw new Error("Cannot update query params on the server");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (window !== window.top) {
|
|
138
|
-
// do not update query params if widget is rendered in an iframe
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const initialSearch = window.location.search;
|
|
143
|
-
const params = new URLSearchParams(initialSearch);
|
|
144
|
-
Object.entries(newParams).forEach(([key, value]) => {
|
|
145
|
-
if (value != null && value !== "") {
|
|
146
|
-
params.set(key, String(value));
|
|
147
|
-
} else {
|
|
148
|
-
params.delete(key);
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
if (initialSearch === `?${params.toString()}`) {
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const newUrl = params.toString()
|
|
157
|
-
? `${window.location.pathname}?${params}`
|
|
158
|
-
: window.location.pathname;
|
|
159
|
-
|
|
160
|
-
if (args.replaceState) {
|
|
161
|
-
window.history.replaceState({}, "", newUrl);
|
|
162
|
-
} else {
|
|
163
|
-
window.history.pushState({}, "", newUrl);
|
|
164
|
-
}
|
|
165
|
-
}
|