Skip to content

Commit

Permalink
OIDC Integration (#647)
Browse files Browse the repository at this point in the history
* Radio button components

* Change header to SSO connection

* Support adding oidc connection via wrapper

* Add missing input change handler

* Tweaks to radio component styles

* Support friendlyProviderName for OIDC connection

* Exclude container component from plugin

* Placeholder for empty cell value

* Handle fetch failure using EmptyState component

* Fetch block with try catch

* Fix layout of hint

* Add missing spacing

* Tweaks to wrapper, container components

* Remove empty placeholder

* Minor fixes oidc edit

* Remove classNames from rest spread

* Add missing space

* Set missing className

* Type fix

* Fix toggle connection

* Fix styling for confirm div

* Remove Card

* Type tweak

* Header display fixes

* Cleanup and fix header display

* Type fixes and use id instead of name

* Support toggling off info card display

* Align header styles

* Spinner and checkbox fix
  • Loading branch information
niwsa authored Nov 27, 2023
1 parent 1f98f6e commit 50d31f2
Show file tree
Hide file tree
Showing 34 changed files with 626 additions and 448 deletions.
8 changes: 1 addition & 7 deletions mitosis.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,7 @@ const VUE_OPTIONS = {
api: 'composition',
};

const components = [
'Login',
'CreateOIDCConnection',
'CreateSAMLConnection',
'CreateSSOConnection',
'ConnectionList',
];
const components = ['Login', 'CreateOIDCConnection', 'CreateSAMLConnection', 'ConnectionList'];

const isMitosisNode = (x) => x && x['@type'] === '@builder.io/mitosis/node';

Expand Down
35 changes: 34 additions & 1 deletion overrides/react/src/shared/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SVGAttributes, ComponentPropsWithRef } from 'react';
import type { SVGAttributes, ComponentPropsWithRef, ReactElement, ReactNode } from 'react';

export type SVGProps = SVGAttributes<SVGSVGElement>;

Expand All @@ -23,6 +23,10 @@ export interface EmptyStateProps {
className?: string;
description?: string;
slotLinkPrimary?: any;
/** Decides which icon to show
* @default info
*/
variant?: 'error' | 'info';
}

export interface BadgeProps {
Expand Down Expand Up @@ -60,6 +64,7 @@ export interface CardProps {
arrangement?: 'horizontal' | 'vertical';
children?: any;
title: string;
displayIcon?: boolean;
variant: 'info' | 'success';
}

Expand All @@ -70,6 +75,34 @@ export interface LinkProps {
variant?: 'primary' | 'button';
}

export interface RadioGroupProps {
label: string;
children: ReactElement<RadioProps> | ReactElement<RadioProps>[];
/** The arrangement of radio buttons
* @default 'horizontal'
*/
orientation?: 'horizontal' | 'vertical';
}

export interface RadioProps {
name: string;
checked: boolean;
handleInputChange: (e: any) => void;
/**
* The value of the radio button, used when submitting an HTML form.
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio#Value).
*/
value: string;
/**
* The label for the radio.
*/
children: ReactNode;
/**
* Displays the radio button but can be disabled for selection.
*/
isDisabled?: boolean;
}

export interface LoadingContainerProps {
children?: any;
isBusy: boolean;
Expand Down
5 changes: 5 additions & 0 deletions overrides/svelte/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export interface EmptyStateProps {
className?: string;
description?: string;
slotLinkPrimary?: any;
/** Decides which icon to show
* @default info
*/
variant?: 'error' | 'info';
}

export interface BadgeProps {
Expand Down Expand Up @@ -51,6 +55,7 @@ export interface CardProps {
arrangement?: 'horizontal' | 'vertical';
children?: any;
title: string;
displayIcon?: boolean;
variant: 'info' | 'success';
}

Expand Down
4 changes: 4 additions & 0 deletions overrides/vue/vue3/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export interface EmptyStateProps {
className?: string;
description?: string;
slotLinkPrimary?: any;
/** Decides which icon to show
* @default info
*/
variant?: 'error' | 'info';
}

export interface BadgeProps {
Expand Down
25 changes: 16 additions & 9 deletions src/shared/Card/index.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,26 @@ export default function Card(props: CardProps) {
get flexCss() {
return props.arrangement === 'vertical' ? ' ' + styles['vertical'] : '';
},
get shouldDisplayIcon() {
return typeof props.displayIcon === 'boolean' ? props.displayIcon : true;
},
});

return (
<article class={`${styles.container}${state.variantCss}${state.flexCss}`}>
<h3 class={styles.title}>
<Show when={props.variant === 'success'}>
<CheckMarkIcon svgAttrs={{ class: styles.svg }} />
</Show>
<Show when={props.variant === 'info'}>
<InfoIcon svgAttrs={{ class: styles.svg }} />
</Show>
{props.title}
</h3>
<Show when={props.title}>
<h3 class={styles.title}>
<Show when={state.shouldDisplayIcon}>
<Show when={props.variant === 'success'}>
<CheckMarkIcon svgAttrs={{ class: styles.svg }} />
</Show>
<Show when={props.variant === 'info'}>
<InfoIcon svgAttrs={{ class: styles.svg }} />
</Show>
</Show>
{props.title}
</h3>
</Show>
<div class={styles.body}>{props.children}</div>
</article>
);
Expand Down
26 changes: 12 additions & 14 deletions src/shared/EmptyState/index.lite.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { useStore } from '@builder.io/mitosis';
import { Show, useStore } from '@builder.io/mitosis';
import type { EmptyStateProps } from '../types';
import defaultStyles from './index.module.css';
import ExclamationTriangle from '../icons/ExclamationTriangle.lite';
import InfoIcon from '../icons/InfoIcon.lite';

export default function EmptyState(props: EmptyStateProps) {
const state = useStore({
Expand All @@ -9,22 +11,18 @@ export default function EmptyState(props: EmptyStateProps) {
container: defaultStyles.container + (props.className ? ` ${props.className}` : ''),
};
},
get variantValue() {
return props.variant || 'info';
},
});

return (
<div class={state.classes.container}>
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
stroke-width='1.5'
stroke='currentColor'
class={defaultStyles.svg}>
<path
stroke-linecap='round'
stroke-linejoin='round'
d='M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z'
/>
</svg>
<Show
when={state.variantValue === 'info'}
else={<ExclamationTriangle svgAttrs={{ class: defaultStyles.svg }} />}>
<InfoIcon svgAttrs={{ class: defaultStyles.svg }} />
</Show>
<h4>{props.title}</h4>
{props.description && <p class={defaultStyles.description}>{props.description}</p>}
{/* TODO: Add slot for LinkPrimary */}
Expand Down
27 changes: 27 additions & 0 deletions src/shared/Radio/index.lite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useStore } from '@builder.io/mitosis';
import { RadioProps } from '../types';
import styles from './index.module.css';
import Spacer from '../Spacer/index.lite';

export default function Radio(props: RadioProps) {
const state = useStore({
get id() {
return props.value.replace(/ /g, '');
},
});
return (
<div class={styles.radioDiv}>
<input
type='radio'
value={props.value}
checked={props.checked}
name={props.name}
id={state.id}
class={styles.radio}
onChange={(event) => props.handleInputChange(event)}
/>
<Spacer x={1} />
<label for={state.id}>{props.children}</label>
</div>
);
}
41 changes: 41 additions & 0 deletions src/shared/Radio/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@import url('../common.module.css');

.radioDiv {
display: flex;
align-items: center;
padding: 0.5rem 0.25rem;
}

.radio {
appearance: none;
/* For iOS < 15 to remove gradient background */
background-color: #fff;
/* Not removed via appearance */
margin: 0;
width: 1.5rem;
height: 1.5rem;
border: 1px solid var(--primary-color);
border-radius: 50%;

display: grid;
place-content: center;
}

.radio::before {
content: '';
width: 1rem;
height: 1rem;
border-radius: 50%;
transform: scale(0);
transition: 120ms transform ease-in-out;
box-shadow: inset 1em 1em var(--primary-color);
}

.radio:checked:before {
transform: scale(1);
}

.radio:focus-visible {
outline: max(2px, 0.15em) solid var(--primary-color);
outline-offset: max(2px, 0.15em);
}
33 changes: 33 additions & 0 deletions src/shared/RadioGroup/index.lite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Show, useStore } from '@builder.io/mitosis';
import styles from './index.module.css';
import { RadioGroupProps } from '../types';
import Spacer from '../Spacer/index.lite';

export default function RadioGroup(props: RadioGroupProps) {
const state = useStore({
get id() {
return props.label.replace(/ /g, '');
},
get orientationValue() {
return props.orientation || 'horizontal';
},
});
return (
<div
class={styles.container}
role='radiogroup'
aria-labelledby={state.id}
aria-orientation={state.orientationValue}>
<div class={styles.label} id={state.id}>
{props.label}
</div>
<Show when={state.orientationValue === 'horizontal'}>
<Spacer x={1} />
</Show>
<Show when={state.orientationValue === 'horizontal'}>
<Spacer y={1} />
</Show>
<div class={styles.inputs}>{props.children}</div>
</div>
);
}
12 changes: 12 additions & 0 deletions src/shared/RadioGroup/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.container {
display: flex;
align-items: center;
}

.inputs {
display: flex;
}

[aria-orientation='vertical'] .inputs {
flex-direction: column;
}
5 changes: 0 additions & 5 deletions src/shared/Spinner/index.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
border: 0.3rem solid var(--primary-color);
border-left-color: transparent;
border-radius: 50%;
opacity: 0;
transition: opacity 0.1s;
pointer-events: none;
animation: loading-circle 1s ease-in-out infinite;
Expand All @@ -30,7 +29,3 @@
transform: rotate(360deg);
}
}

.spinner[aria-hidden='false']::after {
opacity: 1;
}
6 changes: 4 additions & 2 deletions src/shared/Table/TableCell.lite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ export default function TableCell(props: TableCellProps) {
},
get cellValue() {
const _col = props.col;
let value = '-';
if (state.isStringColumn) {
return props.rowData[_col as string];
value = props.rowData[_col as string];
} else if (state.isAdvancedColumnType) {
return props.rowData[(_col as TableCol).name];
value = props.rowData[(_col as TableCol).name];
}
return value;
},
get isStringColumn() {
return typeof props.col === 'string';
Expand Down
23 changes: 23 additions & 0 deletions src/shared/fetchData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export async function fetchData(url: string) {
try {
const response = await fetch(url);
const json = await response.json();

if (!response.ok) {
throw new ApiError(response.status, json.error.message);
}
return json;
} catch (error: any) {
const message = error.message || 'Something went wrong';
return { error: { message } };
}
}

class ApiError extends Error {
status: number;

constructor(status: number, message: string) {
super(message);
this.status = status;
}
}
19 changes: 19 additions & 0 deletions src/shared/icons/ExclamationTriangle.lite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { SVGProps } from '../types';

export default function ExclamationTriangle(props: { svgAttrs?: SVGProps }) {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
fill='none'
viewBox='0 0 24 24'
stroke-width='1.5'
stroke='currentColor'
{...props.svgAttrs}>
<path
stroke-linecap='round'
stroke-linejoin='round'
d='M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z'
/>
</svg>
);
}
Loading

0 comments on commit 50d31f2

Please sign in to comment.