added function to refresh the dataloader data (#143)
This commit is contained in:
parent
bfe6e2c236
commit
410c553ac0
10 changed files with 38 additions and 20 deletions
|
@ -63,7 +63,7 @@ export const PageNav: React.FunctionComponent = () => {
|
||||||
<Nav onSelect={onSelect}>
|
<Nav onSelect={onSelect}>
|
||||||
<NavList>
|
<NavList>
|
||||||
<NavItem className="keycloak__page_nav__nav_item__realm-selector">
|
<NavItem className="keycloak__page_nav__nav_item__realm-selector">
|
||||||
<RealmSelector realmList={realmList || []} />
|
<RealmSelector realmList={realmList.data || []} />
|
||||||
</NavItem>
|
</NavItem>
|
||||||
</NavList>
|
</NavList>
|
||||||
<NavGroup title={t("manage")}>
|
<NavGroup title={t("manage")}>
|
||||||
|
|
|
@ -35,7 +35,7 @@ export const ClientScopesSection = () => {
|
||||||
<DataLoader loader={loader}>
|
<DataLoader loader={loader}>
|
||||||
{(scopes) => (
|
{(scopes) => (
|
||||||
<TableToolbar
|
<TableToolbar
|
||||||
count={scopes!.length}
|
count={scopes.data.length}
|
||||||
first={first}
|
first={first}
|
||||||
max={max}
|
max={max}
|
||||||
onNextClick={setFirst}
|
onNextClick={setFirst}
|
||||||
|
@ -50,7 +50,7 @@ export const ClientScopesSection = () => {
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<ClientScopeList clientScopes={scopes} />
|
<ClientScopeList clientScopes={scopes.data} />
|
||||||
</TableToolbar>
|
</TableToolbar>
|
||||||
)}
|
)}
|
||||||
</DataLoader>
|
</DataLoader>
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { exportClient } from "../util";
|
||||||
|
|
||||||
type ClientListProps = {
|
type ClientListProps = {
|
||||||
clients?: ClientRepresentation[];
|
clients?: ClientRepresentation[];
|
||||||
|
refresh: () => void;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ const columns: (keyof ClientRepresentation)[] = [
|
||||||
"baseUrl",
|
"baseUrl",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ClientList = ({ baseUrl, clients }: ClientListProps) => {
|
export const ClientList = ({ baseUrl, clients, refresh }: ClientListProps) => {
|
||||||
const { t } = useTranslation("clients");
|
const { t } = useTranslation("clients");
|
||||||
const httpClient = useContext(HttpClientContext)!;
|
const httpClient = useContext(HttpClientContext)!;
|
||||||
const { realm } = useContext(RealmContext);
|
const { realm } = useContext(RealmContext);
|
||||||
|
@ -106,11 +107,12 @@ export const ClientList = ({ baseUrl, clients }: ClientListProps) => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("common:delete"),
|
title: t("common:delete"),
|
||||||
onClick: (_, rowId) => {
|
onClick: async (_, rowId) => {
|
||||||
try {
|
try {
|
||||||
httpClient.doDelete(
|
await httpClient.doDelete(
|
||||||
`/admin/realms/${realm}/clients/${data[rowId].client.id}`
|
`/admin/realms/${realm}/clients/${data[rowId].client.id}`
|
||||||
);
|
);
|
||||||
|
refresh();
|
||||||
add(t("clientDeletedSuccess"), AlertVariant.success);
|
add(t("clientDeletedSuccess"), AlertVariant.success);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
add(`${t("clientDeleteError")} ${error}`, AlertVariant.danger);
|
add(`${t("clientDeleteError")} ${error}`, AlertVariant.danger);
|
||||||
|
|
|
@ -83,6 +83,7 @@ export const ClientsSection = () => {
|
||||||
>
|
>
|
||||||
<ClientList
|
<ClientList
|
||||||
clients={clients}
|
clients={clients}
|
||||||
|
refresh={loader}
|
||||||
baseUrl={keycloak!.authServerUrl()!}
|
baseUrl={keycloak!.authServerUrl()!}
|
||||||
/>
|
/>
|
||||||
</TableToolbar>
|
</TableToolbar>
|
||||||
|
|
|
@ -8,7 +8,11 @@ import { ClientList } from "../ClientList";
|
||||||
test("renders ClientList", () => {
|
test("renders ClientList", () => {
|
||||||
const container = render(
|
const container = render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
<ClientList clients={clientMock} baseUrl="http://blog.nerdin.ch" />
|
<ClientList
|
||||||
|
clients={clientMock}
|
||||||
|
baseUrl="http://blog.nerdin.ch"
|
||||||
|
refresh={() => {}}
|
||||||
|
/>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
);
|
);
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
|
|
|
@ -4,24 +4,31 @@ import { Spinner } from "@patternfly/react-core";
|
||||||
type DataLoaderProps<T> = {
|
type DataLoaderProps<T> = {
|
||||||
loader: () => Promise<T>;
|
loader: () => Promise<T>;
|
||||||
deps?: any[];
|
deps?: any[];
|
||||||
children: ((arg: T) => any) | React.ReactNode;
|
children: ((arg: Result<T>) => any) | React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Result<T> = {
|
||||||
|
data: T;
|
||||||
|
refresh: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function DataLoader<T>(props: DataLoaderProps<T>) {
|
export function DataLoader<T>(props: DataLoaderProps<T>) {
|
||||||
const [data, setData] = useState<{ result: T } | undefined>(undefined);
|
const [data, setData] = useState<{ result: T } | undefined>(undefined);
|
||||||
useEffect(() => {
|
|
||||||
setData(undefined);
|
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
const result = await props.loader();
|
const result = await props.loader();
|
||||||
setData({ result });
|
setData({ result });
|
||||||
};
|
};
|
||||||
|
useEffect(() => {
|
||||||
|
setData(undefined);
|
||||||
loadData();
|
loadData();
|
||||||
}, [props]);
|
}, [props]);
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
if (props.children instanceof Function) {
|
if (props.children instanceof Function) {
|
||||||
return props.children(data.result);
|
return props.children({
|
||||||
|
data: data.result,
|
||||||
|
refresh: () => loadData(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return props.children;
|
return props.children;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ describe("<DataLoader />", () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(
|
render(
|
||||||
<DataLoader loader={loader}>
|
<DataLoader loader={loader}>
|
||||||
{(data) => (
|
{(result) => (
|
||||||
<div>
|
<div>
|
||||||
{data.map((d, i) => (
|
{result.data.map((d, i) => (
|
||||||
<i key={i}>{d}</i>
|
<i key={i}>{d}</i>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -68,7 +68,7 @@ export const WhoAmIContextProvider = ({ children }: WhoAmIProviderProps) => {
|
||||||
<DataLoader loader={whoAmILoader}>
|
<DataLoader loader={whoAmILoader}>
|
||||||
{(whoamirep) => (
|
{(whoamirep) => (
|
||||||
<WhoAmIContext.Provider
|
<WhoAmIContext.Provider
|
||||||
value={new WhoAmI(keycloak?.realm(), whoamirep)}
|
value={new WhoAmI(keycloak?.realm(), whoamirep.data)}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</WhoAmIContext.Provider>
|
</WhoAmIContext.Provider>
|
||||||
|
|
|
@ -51,7 +51,7 @@ export const RealmRolesSection = () => {
|
||||||
<Divider component="li" key={1} />
|
<Divider component="li" key={1} />
|
||||||
<PageSection padding={{ default: "noPadding" }}>
|
<PageSection padding={{ default: "noPadding" }}>
|
||||||
<TableToolbar
|
<TableToolbar
|
||||||
count={roles!.length}
|
count={roles.data.length}
|
||||||
first={first}
|
first={first}
|
||||||
max={max}
|
max={max}
|
||||||
onNextClick={setFirst}
|
onNextClick={setFirst}
|
||||||
|
@ -68,7 +68,7 @@ export const RealmRolesSection = () => {
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<RolesList roles={roles} />
|
<RolesList roles={roles.data} />
|
||||||
</TableToolbar>
|
</TableToolbar>
|
||||||
</PageSection>
|
</PageSection>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -10,5 +10,9 @@ export default {
|
||||||
} as Meta;
|
} as Meta;
|
||||||
|
|
||||||
export const ClientListExample = () => (
|
export const ClientListExample = () => (
|
||||||
<ClientList clients={clientMock} baseUrl="http://test.nl/" />
|
<ClientList
|
||||||
|
clients={clientMock}
|
||||||
|
baseUrl="http://test.nl/"
|
||||||
|
refresh={() => {}}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue