Skip to content

Commit ff079b9

Browse files
Org SSO Page updates (#16868)
* Breaking SSO page into components & react-query * wrapper component not needed anymore * position off of bottom instead * add a heading/subheading for consistency * add clientside validation * adding oidcConfig.issuer to api response * updating test * minor cleanup
1 parent 59e58f9 commit ff079b9

File tree

14 files changed

+462
-332
lines changed

14 files changed

+462
-332
lines changed

components/dashboard/src/components/Modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export const ModalFooter: FC<ModalFooterProps> = ({ error, warning, children })
150150
return (
151151
<div className="relative">
152152
{hasAlert && (
153-
<div className="absolute -top-12 left-0 right-0" style={alertStyles}>
153+
<div className="absolute bottom-12 left-0 right-0" style={alertStyles}>
154154
<ModalFooterAlert error={error} warning={warning} />
155155
</div>
156156
)}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { useMutation, useQueryClient } from "@tanstack/react-query";
8+
import { oidcService } from "../../service/public-api";
9+
import { useCurrentOrg } from "../organizations/orgs-query";
10+
import { getOIDCClientsQueryKey, OIDCClientsQueryResults } from "./oidc-clients-query";
11+
12+
type DeleteOIDCClientArgs = {
13+
clientId: string;
14+
};
15+
export const useDeleteOIDCClientMutation = () => {
16+
const queryClient = useQueryClient();
17+
const organization = useCurrentOrg().data;
18+
19+
return useMutation({
20+
mutationFn: async ({ clientId }: DeleteOIDCClientArgs) => {
21+
if (!organization) {
22+
throw new Error("No current organization selected");
23+
}
24+
25+
return await oidcService.deleteClientConfig({
26+
id: clientId,
27+
organizationId: organization.id,
28+
});
29+
},
30+
onSuccess: (_, { clientId }) => {
31+
if (!organization) {
32+
throw new Error("No current organization selected");
33+
}
34+
35+
const queryKey = getOIDCClientsQueryKey(organization.id);
36+
// filter out deleted client immediately
37+
queryClient.setQueryData<OIDCClientsQueryResults>(queryKey, (clients) => {
38+
return clients?.filter((c) => c.id !== clientId);
39+
});
40+
41+
// then invalidate query
42+
queryClient.invalidateQueries({ queryKey });
43+
},
44+
});
45+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { OIDCClientConfig } from "@gitpod/public-api/lib/gitpod/experimental/v1/oidc_pb";
8+
import { useQuery } from "@tanstack/react-query";
9+
import { oidcService } from "../../service/public-api";
10+
import { useCurrentOrg } from "../organizations/orgs-query";
11+
12+
export type OIDCClientsQueryResults = OIDCClientConfig[];
13+
14+
export const useOIDCClientsQuery = () => {
15+
const { data: organization, isLoading } = useCurrentOrg();
16+
17+
return useQuery<OIDCClientsQueryResults>({
18+
queryKey: getOIDCClientsQueryKey(organization?.id ?? ""),
19+
queryFn: async () => {
20+
if (!organization) {
21+
throw new Error("No current organization selected");
22+
}
23+
24+
const { clientConfigs } = await oidcService.listClientConfigs({ organizationId: organization.id });
25+
26+
return clientConfigs;
27+
},
28+
enabled: !isLoading,
29+
});
30+
};
31+
32+
export const getOIDCClientsQueryKey = (organizationId: string) => ["oidc-clients", { organizationId }];
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* Copyright (c) 2023 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { useMutation, useQueryClient } from "@tanstack/react-query";
8+
import { oidcService } from "../../service/public-api";
9+
import { getOIDCClientsQueryKey } from "./oidc-clients-query";
10+
11+
// TODO: find a better way to type this against the API
12+
type UpsertOIDCClientMutationArgs =
13+
| Parameters<typeof oidcService.updateClientConfig>[0]
14+
| Parameters<typeof oidcService.createClientConfig>[0];
15+
16+
export const useUpsertOIDCClientMutation = () => {
17+
const queryClient = useQueryClient();
18+
19+
return useMutation({
20+
mutationFn: async ({ config = {} }: UpsertOIDCClientMutationArgs) => {
21+
if ("id" in config) {
22+
return await oidcService.updateClientConfig({
23+
config,
24+
});
25+
} else {
26+
return await oidcService.createClientConfig({
27+
config,
28+
});
29+
}
30+
},
31+
onSuccess(resp, { config = {} }) {
32+
if (!config || !config.organizationId) {
33+
return;
34+
}
35+
36+
queryClient.invalidateQueries({ queryKey: getOIDCClientsQueryKey(config.organizationId || "") });
37+
},
38+
});
39+
};

components/dashboard/src/teams/GitIntegrationsPage.tsx

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,13 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { FunctionComponent } from "react";
8-
import { Redirect } from "react-router";
9-
import Header from "../components/Header";
10-
import { SpinnerLoader } from "../components/Loader";
11-
import { useCurrentOrg } from "../data/organizations/orgs-query";
127
import { GitIntegrations } from "./git-integrations/GitIntegrations";
138
import { OrgSettingsPage } from "./OrgSettingsPage";
149

15-
export default function GitAuth() {
10+
export default function GitAuthPage() {
1611
return (
17-
<OrgSettingsPageWrapper>
12+
<OrgSettingsPage title="Git Auth" subtitle="Configure Git Auth for GitLab or Github.">
1813
<GitIntegrations />
19-
</OrgSettingsPageWrapper>
20-
);
21-
}
22-
23-
// TODO: Refactor this into OrgSettingsPage so each page doesn't have to do this
24-
export const OrgSettingsPageWrapper: FunctionComponent = ({ children }) => {
25-
const currentOrg = useCurrentOrg();
26-
27-
const title = "Git Auth";
28-
const subtitle = "Configure Git Auth for GitLab, or Github.";
29-
30-
// Render as much of the page as we can in a loading state to avoid content shift
31-
if (currentOrg.isLoading) {
32-
return (
33-
<div className="w-full">
34-
<Header title={title} subtitle={subtitle} />
35-
<div className="w-full">
36-
<SpinnerLoader />
37-
</div>
38-
</div>
39-
);
40-
}
41-
42-
if (!currentOrg.data?.isOwner) {
43-
return <Redirect to={"/"} />;
44-
}
45-
46-
return (
47-
<OrgSettingsPage title={title} subtitle={subtitle}>
48-
{children}
4914
</OrgSettingsPage>
5015
);
51-
};
16+
}

0 commit comments

Comments
 (0)