Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for discord+slack oauth providers #306

Merged
merged 2 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions shared/studio/tabs/auth/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,24 @@ export function AzureIcon() {
);
}

export function DiscordIcon() {
return (
<svg
className={styles.oauthIcon}
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M26.308 6.84247C24.4227 5.96933 22.4323 5.3499 20.3879 5C20.1081 5.50591 19.8549 6.02642 19.6295 6.55936C17.4517 6.2274 15.2371 6.2274 13.0593 6.55936C12.8338 6.02648 12.5806 5.50597 12.301 5C10.2552 5.35286 8.26356 5.97376 6.37632 6.84703C2.62968 12.4543 1.61403 17.9224 2.12186 23.3128C4.31598 24.9526 6.77184 26.1998 9.38266 27C9.97054 26.2002 10.4907 25.3517 10.9377 24.4635C10.0887 24.1427 9.26929 23.747 8.48889 23.2808C8.69428 23.1301 8.89515 22.9749 9.08925 22.8242C11.36 23.9044 13.8385 24.4645 16.3478 24.4645C18.8571 24.4645 21.3356 23.9044 23.6064 22.8242C23.8027 22.9863 24.0036 23.1416 24.2067 23.2808C23.4248 23.7477 22.6039 24.1442 21.7533 24.4658C22.1998 25.3535 22.72 26.2013 23.3084 27C25.9215 26.203 28.3792 24.9564 30.5737 23.3151C31.1696 17.0639 29.5558 11.6461 26.308 6.84247ZM11.581 19.9977C10.1658 19.9977 8.99672 18.6986 8.99672 17.1005C8.99672 15.5023 10.1252 14.1918 11.5765 14.1918C13.0277 14.1918 14.1878 15.5023 14.163 17.1005C14.1382 18.6986 13.0232 19.9977 11.581 19.9977ZM21.1146 19.9977C19.6972 19.9977 18.5326 18.6986 18.5326 17.1005C18.5326 15.5023 19.6611 14.1918 21.1146 14.1918C22.5681 14.1918 23.7192 15.5023 23.6944 17.1005C23.6696 18.6986 22.5568 19.9977 21.1146 19.9977Z"
fill="#5865F2"
/>
</svg>
);
}

export function GithubIcon() {
return (
<svg
Expand Down Expand Up @@ -152,3 +170,49 @@ export function GoogleIcon() {
</svg>
);
}

export function SlackIcon() {
return (
<svg
className={styles.oauthIcon}
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8.46254 19.43C8.46254 20.9332 7.23453 22.1612 5.73127 22.1612C4.22801 22.1612 3 20.9332 3 19.43C3 17.9267 4.22801 16.6987 5.73127 16.6987H8.46254V19.43Z"
fill="#E01E5A"
/>
<path
d="M9.83875 19.43C9.83875 17.9267 11.0668 16.6987 12.57 16.6987C14.0733 16.6987 15.3013 17.9267 15.3013 19.43V26.2687C15.3013 27.772 14.0733 29 12.57 29C11.0668 29 9.83875 27.772 9.83875 26.2687V19.43Z"
fill="#E01E5A"
/>
<path
d="M12.57 8.46254C11.0668 8.46254 9.83875 7.23453 9.83875 5.73127C9.83875 4.22801 11.0668 3 12.57 3C14.0733 3 15.3013 4.22801 15.3013 5.73127V8.46254H12.57Z"
fill="#36C5F0"
/>
<path
d="M12.57 9.83881C14.0733 9.83881 15.3013 11.0668 15.3013 12.5701C15.3013 14.0733 14.0733 15.3013 12.57 15.3013H5.73127C4.22801 15.3013 3 14.0733 3 12.5701C3 11.0668 4.22801 9.83881 5.73127 9.83881H12.57Z"
fill="#36C5F0"
/>
<path
d="M23.5375 12.5701C23.5375 11.0668 24.7655 9.83881 26.2688 9.83881C27.772 9.83881 29 11.0668 29 12.5701C29 14.0733 27.772 15.3013 26.2688 15.3013H23.5375V12.5701Z"
fill="#2EB67D"
/>
<path
d="M22.1612 12.57C22.1612 14.0733 20.9332 15.3013 19.43 15.3013C17.9267 15.3013 16.6987 14.0733 16.6987 12.57V5.73127C16.6987 4.22801 17.9267 3 19.43 3C20.9332 3 22.1612 4.22801 22.1612 5.73127V12.57Z"
fill="#2EB67D"
/>
<path
d="M19.4299 23.5374C20.9332 23.5374 22.1612 24.7654 22.1612 26.2686C22.1612 27.7719 20.9332 28.9999 19.4299 28.9999C17.9267 28.9999 16.6987 27.7719 16.6987 26.2686V23.5374H19.4299Z"
fill="#ECB22E"
/>
<path
d="M19.4299 22.1612C17.9267 22.1612 16.6987 20.9332 16.6987 19.43C16.6987 17.9267 17.9267 16.6987 19.4299 16.6987H26.2687C27.772 16.6987 29 17.9267 29 19.43C29 20.9332 27.772 22.1612 26.2687 22.1612H19.4299Z"
fill="#ECB22E"
/>
</svg>
);
}
15 changes: 9 additions & 6 deletions shared/studio/tabs/auth/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ import {
AuthProviderData,
DraftProviderConfig,
ProviderTypename,
providerTypenames,
providers,
DraftUIConfig,
ProviderKind,
OAuthProviderData,
Expand All @@ -33,6 +31,7 @@ import {
smtpSecurity,
DraftAppConfig,
AbstractDraftConfig,
_providersInfo,
} from "./state";

import {encodeB64} from "edgedb/dist/primitives/buffer";
Expand Down Expand Up @@ -449,7 +448,7 @@ const ProvidersPage = observer(function ProvidersPage() {
</div>
{state.draftProviderConfig ? (
<DraftProviderConfigForm draftState={state.draftProviderConfig} />
) : state.providers.length < providerTypenames.length ? (
) : state.providers.length < state.providerTypenames.length ? (
<Button
className={styles.button}
label="Add Provider"
Expand Down Expand Up @@ -889,7 +888,10 @@ function ColorPickerPopup({
);
}

function getProviderSelectItems(existingProviders: Set<string>) {
function getProviderSelectItems(
providers: typeof _providersInfo,
existingProviders: Set<string>
) {
return {
items: [],
groups: Object.entries(
Expand Down Expand Up @@ -925,11 +927,12 @@ const DraftProviderConfigForm = observer(function DraftProviderConfigForm({
const providerItems = useMemo(
() =>
getProviderSelectItems(
state.providersInfo,
new Set(state.providers?.map((p) => p._typename))
),
[state.providers]
);
const providerKind = providers[draftState.selectedProviderType].kind;
const providerKind = _providersInfo[draftState.selectedProviderType].kind;

return (
<div className={styles.addProviderForm}>
Expand Down Expand Up @@ -1048,7 +1051,7 @@ function ProviderCard({provider}: {provider: AuthProviderData}) {
const [deleting, setDeleting] = useState(false);
const [expanded, setExpanded] = useState(false);

const {displayName, icon, kind} = providers[provider._typename];
const {displayName, icon, kind} = _providersInfo[provider._typename];

return (
<div className={styles.providerCard}>
Expand Down
12 changes: 4 additions & 8 deletions shared/studio/tabs/auth/loginUIPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import "@fontsource-variable/roboto-flex";

import cn from "@edgedb/common/utils/classNames";

import {
AuthProviderData,
DraftAppConfig,
providers as providersInfo,
} from "./state";
import {AuthProviderData, DraftAppConfig, _providersInfo} from "./state";

import styles from "./loginuipreview.module.scss";
import {getColourVariables, normaliseHexColor} from "./colourUtils";
Expand All @@ -32,12 +28,12 @@ export function LoginUIPreview({
);

const oauthButtons = providers
.filter((provider) => providersInfo[provider._typename].kind === "OAuth")
.filter((provider) => _providersInfo[provider._typename].kind === "OAuth")
.map((provider) => (
<a key={provider.name}>
{providersInfo[provider._typename].icon}
{_providersInfo[provider._typename].icon}
<span>
Sign in with {providersInfo[provider._typename].displayName}
Sign in with {_providersInfo[provider._typename].displayName}
</span>
</a>
));
Expand Down
54 changes: 45 additions & 9 deletions shared/studio/tabs/auth/state/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ import {
} from "mobx-keystone";
import {parsers} from "../../../components/dataEditor/parsers";
import {connCtx, dbCtx} from "../../../state";
import {AppleIcon, AzureIcon, GithubIcon, GoogleIcon} from "../icons";
import {
AppleIcon,
AzureIcon,
DiscordIcon,
GithubIcon,
GoogleIcon,
SlackIcon,
} from "../icons";

interface AuthAppData {
app_name: string | null;
Expand All @@ -30,8 +37,10 @@ export type OAuthProviderData = {
_typename:
| "ext::auth::AppleOAuthProvider"
| "ext::auth::AzureOAuthProvider"
| "ext::auth::DiscordOAuthProvider"
| "ext::auth::GitHubOAuthProvider"
| "ext::auth::GoogleOAuthProvider";
| "ext::auth::GoogleOAuthProvider"
| "ext::auth::SlackOAuthProvider";
client_id: string;
additional_scope: string;
};
Expand Down Expand Up @@ -72,7 +81,7 @@ export interface SMTPConfigData {

export type ProviderKind = "OAuth" | "Local";

export const providers: {
export const _providersInfo: {
[key in AuthProviderData["_typename"]]: {
kind: ProviderKind;
displayName: string;
Expand All @@ -90,6 +99,11 @@ export const providers: {
displayName: "Azure",
icon: <AzureIcon />,
},
"ext::auth::DiscordOAuthProvider": {
kind: "OAuth",
displayName: "Discord",
icon: <DiscordIcon />,
},
"ext::auth::GitHubOAuthProvider": {
kind: "OAuth",
displayName: "GitHub",
Expand All @@ -100,6 +114,11 @@ export const providers: {
displayName: "Google",
icon: <GoogleIcon />,
},
"ext::auth::SlackOAuthProvider": {
kind: "OAuth",
displayName: "Slack",
icon: <SlackIcon />,
},
// local
"ext::auth::EmailPasswordProviderConfig": {
kind: "Local",
Expand All @@ -108,9 +127,7 @@ export const providers: {
},
};

export type ProviderTypename = keyof typeof providers;

export const providerTypenames = Object.keys(providers) as ProviderTypename[];
export type ProviderTypename = keyof typeof _providersInfo;

@model("AuthAdmin")
export class AuthAdminState extends Model({
Expand All @@ -137,11 +154,30 @@ export class AuthAdminState extends Model({
);
}

@computed
get providersInfo() {
const objects = dbCtx.get(this)!.schemaData?.objectsByName;
const providers = {} as typeof _providersInfo;
for (const providerName of Object.keys(
_providersInfo
) as ProviderTypename[]) {
if (objects?.has(providerName)) {
providers[providerName] = _providersInfo[providerName];
}
}
return providers;
}

@computed
get providerTypenames() {
return Object.keys(this.providersInfo) as ProviderTypename[];
}

@modelAction
addDraftProvider() {
const existingProviders = new Set(this.providers?.map((p) => p._typename));
this.draftProviderConfig = new DraftProviderConfig({
selectedProviderType: providerTypenames.find(
selectedProviderType: this.providerTypenames.find(
(name) => !existingProviders.has(name)
)!,
});
Expand Down Expand Up @@ -824,7 +860,7 @@ export class DraftProviderConfig extends Model({

@computed
get formValid(): boolean {
switch (providers[this.selectedProviderType].kind) {
switch (_providersInfo[this.selectedProviderType].kind) {
case "OAuth":
return !this.oauthClientIdError && !this.oauthSecretError;
case "Local":
Expand All @@ -849,7 +885,7 @@ export class DraftProviderConfig extends Model({
this.error = null;

try {
const provider = providers[this.selectedProviderType];
const provider = _providersInfo[this.selectedProviderType];

await conn.execute(
`configure current database
Expand Down
Loading