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

Update auth admin design + add support for webhooks and openid connect providers #369

Merged
merged 2 commits into from
Oct 31, 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
31 changes: 30 additions & 1 deletion shared/common/newui/button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import cn from "@edgedb/common/utils/classNames";

import styles from "./button.module.scss";
import Spinner from "../../ui/spinner";
import {PropsWithChildren} from "react";
import {CSSProperties, PropsWithChildren, useEffect, useState} from "react";

interface _BaseButtonProps {
className?: string;
Expand All @@ -12,6 +12,7 @@ interface _BaseButtonProps {
rightIcon?: JSX.Element;
disabled?: boolean;
loading?: boolean;
style?: CSSProperties;
}

export interface ButtonProps extends _BaseButtonProps {
Expand Down Expand Up @@ -107,3 +108,31 @@ export function LinkButton({
</a>
);
}

export function ConfirmButton({onClick, children, ...props}: ButtonProps) {
const [confirming, setConfirming] = useState(false);

useEffect(() => {
if (confirming) {
const timer = setTimeout(() => setConfirming(false), 1000);

return () => clearTimeout(timer);
}
}, [confirming]);

return (
<Button
onClick={() => {
if (confirming) {
setConfirming(false);
onClick?.();
} else {
setConfirming(true);
}
}}
{...props}
>
{confirming ? "Confirm?" : children}
</Button>
);
}
8 changes: 8 additions & 0 deletions shared/common/newui/checkbox/checkbox.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
pointer-events: none;
}

&.readonly {
pointer-events: none;

.check {
opacity: 0.5;
}
}

@include darkTheme {
color: #ccc;

Expand Down
22 changes: 15 additions & 7 deletions shared/common/newui/checkbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,40 @@ import cn from "@edgedb/common/utils/classNames";

import styles from "./checkbox.module.scss";

export interface CheckboxProps {
export type CheckboxProps<Readonly extends boolean> = {
className?: string;
label?: string | JSX.Element;
checked: boolean;
onChange: (checked: boolean) => void;
disabled?: boolean;
}
readOnly?: Readonly;
} & (Readonly extends true
? {
onChange?: (checked: boolean) => void;
}
: {
onChange: (checked: boolean) => void;
});

export function Checkbox({
export function Checkbox<Readonly extends boolean = false>({
className,
label,
checked,
onChange,
disabled,
}: CheckboxProps) {
readOnly,
}: CheckboxProps<Readonly>) {
return (
<label
className={cn(styles.checkbox, className, {
[styles.disabled]: !!disabled,
[styles.readonly]: !!readOnly,
})}
>
<input
type="checkbox"
checked={checked}
onChange={(e) => onChange(e.target.checked)}
disabled={disabled}
onChange={(e) => onChange?.(e.target.checked)}
disabled={disabled || readOnly}
/>
<div className={styles.check} />
{label}
Expand Down
5 changes: 5 additions & 0 deletions shared/common/newui/loadingSkeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import styles from "./loadingSkeleton.module.scss";

export function LoadingSkeleton({ className }: { className?: string }) {
return <div className={`${styles.loadingSkeleton} ${className ?? ""}`} />;
}
30 changes: 30 additions & 0 deletions shared/common/newui/loadingSkeleton/loadingSkeleton.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@import "@edgedb/common/mixins.scss";

.loadingSkeleton {
border-radius: 8px;
background: var(--skeletonBg, #ededed);
background-image: linear-gradient(
90deg,
transparent,
var(--skeletonShimmer, #fafafa) 66%,
transparent
);
background-repeat: no-repeat;
background-size: 100px 100%;
animation: shimmer 2s infinite linear;

@include darkTheme {
--skeletonBg: #2d2d2d;
--skeletonShimmer: #3c3c3c;
}
}

@keyframes shimmer {
0% {
background-position: -100px;
}
50%,
100% {
background-position: calc(100% + 100px);
}
}
33 changes: 33 additions & 0 deletions shared/common/newui/panelTabs/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import cn from "@edgedb/common/utils/classNames";

import styles from "./panelTabs.module.scss";

export interface PanelTabsProps<TabId extends string> {
className?: string;
tabs: {id: TabId; label: string | JSX.Element}[];
selectedTabId: TabId;
setSelectedTabId: (id: TabId) => void;
}

export function PanelTabs<TabId extends string = string>({
className,
tabs,
selectedTabId,
setSelectedTabId,
}: PanelTabsProps<TabId>) {
return (
<div className={cn(styles.panelTabs, className)}>
{tabs.map((tab) => (
<div
key={tab.id}
className={cn(styles.tab, {
[styles.active]: selectedTabId === tab.id,
})}
onClick={() => setSelectedTabId(tab.id)}
>
{tab.label}
</div>
))}
</div>
);
}
94 changes: 94 additions & 0 deletions shared/common/newui/panelTabs/panelTabs.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
@import "@edgedb/common/mixins.scss";

.panelTabs {
grid-column: 1;
grid-row: 1;
display: flex;
flex-direction: column;
gap: 12px;
align-self: start;
position: sticky;
top: 0;
width: max-content;
justify-self: end;
text-align: end;
padding: 64px 24px;
z-index: 1;

.tab {
position: relative;
font-family: "Roboto Flex Variable", sans-serif;
color: var(--secondary_text_color);
text-decoration: none;
font-weight: 500;
padding: 12px 16px;
border-radius: 8px;
cursor: pointer;

&:hover {
background: #fff;
}

&.active {
color: var(--main_text_color);

&:after {
content: "";
position: absolute;
right: 1px;
top: 4px;
bottom: 4px;
width: 2px;
border-radius: 1px;
background: #a565cd;
}
}
}

@include darkTheme {
.tab:hover {
background: var(--Grey12);
}
}

@include isMobile {
border-bottom: 1px solid var(--Grey93, #ededed);
background: var(--Grey99, #fcfcfc);
box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.08);
flex-direction: row;
padding: 0;
width: 100%;
align-items: center;
justify-content: center;
height: 44px;
flex-shrink: 0;

.tab {
padding: 10px 12px;
border-radius: 6px;

&:hover {
background: var(--Grey95, #f2f2f2);
}

&.active:after {
left: 4px;
right: 4px;
top: auto;
bottom: -3px;
height: 2px;
width: auto;
}
}

@include darkTheme {
border-bottom: 1px solid var(--Grey22, #363636);
background: var(--Grey18, #2e2e2e);
box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.2);

.tab:hover {
background: var(--Grey14, #242424);
}
}
}
}
1 change: 1 addition & 0 deletions shared/common/newui/select/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Select as _Select,
SelectProps as _SelectProps,
} from "@edgedb/common/ui/select";
export type {SelectItem, SelectItems} from "@edgedb/common/ui/select";

import styles from "./select.module.scss";

Expand Down
3 changes: 3 additions & 0 deletions shared/common/newui/textInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface TextInputProps extends FieldHeaderProps {
type?: "text" | "password" | "textarea";
error?: string | null;
prefix?: string;
suffixEl?: JSX.Element;
}

export const TextInput = forwardRef(function TextInput(
Expand All @@ -23,6 +24,7 @@ export const TextInput = forwardRef(function TextInput(
headerNote,
error,
prefix,
suffixEl,
...props
}: TextInputProps &
Omit<InputHTMLAttributes<HTMLInputElement | HTMLTextAreaElement>, "type">,
Expand Down Expand Up @@ -53,6 +55,7 @@ export const TextInput = forwardRef(function TextInput(
: undefined,
}}
/>
{suffixEl}
{error != null ? (
<div className={styles.error}>
<InfoIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
.databasePage {
position: relative;
flex-grow: 1;
overflow: hidden;
min-height: 0;
display: grid;
padding: 0 16px 16px 0;
padding: 0 8px 8px 0;
grid-template-areas: "tabs session" "tabs content";
grid-template-columns: auto 1fr;
grid-template-rows: auto 1fr;
Expand Down
32 changes: 2 additions & 30 deletions shared/studio/tabs/ai/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useEffect, useLayoutEffect, useState} from "react";
import {useEffect, useLayoutEffect} from "react";
import {Observer, observer} from "mobx-react-lite";

import cn from "@edgedb/common/utils/classNames";
Expand All @@ -15,7 +15,7 @@ import {PlaygroundTab} from "./playground";
import {PromptsTab} from "./prompts";

import styles from "./aiAdmin.module.scss";
import {Button, ButtonProps, WarningIcon} from "@edgedb/common/newui";
import {WarningIcon} from "@edgedb/common/newui";

const AIAdminPage = observer(function AIAdminPage() {
const state = useTabState(AIAdminState);
Expand Down Expand Up @@ -133,31 +133,3 @@ function AIAdminLayout() {
</div>
);
}

export function ConfirmButton({onClick, children, ...props}: ButtonProps) {
const [confirming, setConfirming] = useState(false);

useEffect(() => {
if (confirming) {
const timer = setTimeout(() => setConfirming(false), 1000);

return () => clearTimeout(timer);
}
}, [confirming]);

return (
<Button
onClick={() => {
if (confirming) {
setConfirming(false);
onClick?.();
} else {
setConfirming(true);
}
}}
{...props}
>
{confirming ? "Confirm?" : children}
</Button>
);
}
2 changes: 1 addition & 1 deletion shared/studio/tabs/ai/prompts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {observer} from "mobx-react-lite";
import cn from "@edgedb/common/utils/classNames";
import {
Button,
ConfirmButton,
ChevronDownIcon,
InfoIcon,
InfoTooltip,
Expand All @@ -16,7 +17,6 @@ import {AIAdminState, AIPromptDraft, PromptChatParticipantRole} from "./state";

import textStyles from "@edgedb/common/newui/textInput/textInput.module.scss";
import styles from "./aiAdmin.module.scss";
import {ConfirmButton} from ".";

export const PromptsTab = observer(function PromptTab() {
const state = useTabState(AIAdminState);
Expand Down
Loading
Loading