@niledatabase/react 2.3.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.esm.js CHANGED
@@ -1,2 +1,1196 @@
1
- import*as e from"react";import t,{createContext as r,useMemo as a,useContext as n,useState as o,useEffect as l}from"react";import i from"@niledatabase/browser";import{QueryClient as c,QueryClientProvider as s,useMutation as m}from"@tanstack/react-query";import u from"@mui/material/CssBaseline";import{CssVarsProvider as d}from"@mui/joy/styles";import p from"@mui/joy/Box";import f from"@mui/joy/Button";import h from"@mui/joy/Stack";import g from"@mui/joy/Typography";import E from"@mui/joy/Alert";import{useFormContext as b,Controller as y,useForm as x,FormProvider as w}from"react-hook-form";import v from"@mui/joy/Input";import S from"@mui/joy/FormControl";import C from"@mui/joy/FormHelperText";import k from"@mui/icons-material/Error";import T from"@mui/joy/FormLabel";import j from"@mui/joy/Select";import P from"@mui/joy/Option";import U from"@mui/joy/Tooltip";import{Switch as I,Modal as q,ModalDialog as F,Stack as R,Typography as B,FormControl as M,FormLabel as O,Input as V,Button as A}from"@mui/joy";import L from"@mui/joy/Checkbox";import D from"@mui/joy/List";import $ from"@mui/joy/ListItem";import{DataGrid as N}from"@mui/x-data-grid";import z from"@mui/icons-material/Add";import G from"lodash/isNull";import H from"lodash/isUndefined";import W from"@mui/icons-material/CopyAll";import Q from"@mui/icons-material/CheckCircleOutlined";function J({theme:e,children:r,slotProps:a}){return t.createElement(d,{...a,theme:e},t.createElement(u,{enableColorScheme:!0}),r)}const K=new c,X=r({api:new i({basePath:"https://api.thenile.dev",credentials:"include"}),basePath:""}),{Provider:Y}=X,Z=({children:e})=>t.createElement(s,{client:K},e),_=e=>{const{children:r,theme:n,slotProps:o,tenantId:l,QueryProvider:c=Z,basePath:s="https://api.thenile.dev",api:m}=e,u=a((()=>({api:m??new i({basePath:s,credentials:"include"}),tenantId:String(l),basePath:s})),[m,s,l]);return t.createElement(c,null,t.createElement(J,{slotProps:o?.provider,theme:n},t.createElement(Y,{value:u},r)))},ee=()=>n(X),te=()=>{const{basePath:e,tenantId:t}=ee();return a((()=>({tenantId:t,basePath:e})),[e,t])},re=()=>ee().api;var ae;function ne(){return ne=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var a in r)Object.prototype.hasOwnProperty.call(r,a)&&(e[a]=r[a])}return e},ne.apply(this,arguments)}var oe=function(t){return e.createElement("svg",ne({xmlns:"http://www.w3.org/2000/svg",width:18,height:18},t),ae||(ae=e.createElement("g",{fillRule:"evenodd"},e.createElement("path",{fill:"#EA4335",d:"M9 3.48c1.69 0 2.83.73 3.48 1.34l2.54-2.48C13.46.89 11.43 0 9 0 5.48 0 2.44 2.02.96 4.96l2.91 2.26C4.6 5.05 6.62 3.48 9 3.48"}),e.createElement("path",{fill:"#4285F4",d:"M17.64 9.2c0-.74-.06-1.28-.19-1.84H9v3.34h4.96c-.1.83-.64 2.08-1.84 2.92l2.84 2.2c1.7-1.57 2.68-3.88 2.68-6.62"}),e.createElement("path",{fill:"#FBBC05",d:"M3.88 10.78A5.5 5.5 0 0 1 3.58 9c0-.62.11-1.22.29-1.78L.96 4.96A9 9 0 0 0 0 9c0 1.45.35 2.82.96 4.04z"}),e.createElement("path",{fill:"#34A853",d:"M9 18c2.43 0 4.47-.8 5.96-2.18l-2.84-2.2c-.76.53-1.78.9-3.12.9-2.38 0-4.4-1.57-5.12-3.74L.97 13.04C2.45 15.98 5.48 18 9 18"}),e.createElement("path",{fill:"none",d:"M0 0h18v18H0z"}))))};function le(e){const{databaseId:r,newTenantName:a}=e,{basePath:n}=te(),o=`${n}/databases/${encodeURIComponent(r??"")}/users/oidc/google/login`,l=a?"?newTenant="+encodeURIComponent(a):"",i=(e?.href??o)+l;return t.createElement(p,{component:"a",href:i,display:"flex",flex:1,sx:{textDecoration:"none"}},t.createElement(p,null,t.createElement(f,{sx:{padding:0,textTransform:"initial",flex:1},"aria-label":"log in with google"},t.createElement(h,{direction:"row",alignItems:"center",p:0,flex:1,fontFamily:"Roboto, sans-serif",fontSize:"14px",display:"inline-flex",color:"rgb(255 255, 255)",boxShadow:"rgb(0 0 0 / 24%) 0px 2px 2px 0px rgb(0 0 0 / 24%) 0px 0px 1px 0px",borderRadius:"4px",border:"1px solid transparent",fontWeight:"500",sx:{backgroundColor:"rgb(66 133, 244)"}},t.createElement(p,{padding:"11px",display:"flex",border:"1px solid rgb(66, 133, 244)",borderRadius:"4px",sx:{background:"rgb(255, 255, 255)"}},t.createElement(oe,{"aria-hidden":"true"})),t.createElement(p,{padding:"10px",flex:1},t.createElement(g,{sx:{color:"white"},fontWeight:700,fontFamily:"Roboto, sans-serif",fontSize:"14px",height:"20px"},"Continue with Google"))))))}function ie(t){const{options:r,attribute:a,display:n,helperText:o}=t,{watch:l,control:i}=b(),c=l(a.name),s={};return o&&(s.color="danger"),e.createElement(y,{name:a.name,rules:{required:Boolean(a.required)},control:i,render:({field:t})=>e.createElement(h,null,e.createElement(T,{htmlFor:`${t.name}`},n.label),e.createElement(p,{role:"group","aria-labelledby":a.name,sx:{borderRadius:"var(--joy-radius-sm)",p:.5,border:o?"1px solid var(--joy-palette-danger-outlinedBorder)":"none"}},e.createElement(D,{orientation:"horizontal",wrap:!0,sx:{"--List-gap":"8px"}},r.map((n=>(s.id=String(n.value),e.createElement($,{key:`${n.value}-${n.label}`},e.createElement(L,{overlay:r.length>1,...s,checked:c.includes(n.value),disableIcon:r.length>1,variant:"soft",label:n.label,onChange:e=>{if(a.allowMultiple)if(e.target.checked)c?t.onChange(c.concat(n.value)):t.onChange([n.value]);else{const e=c.filter((e=>e!==n.value));e.length>0?t.onChange(e):t.onChange("")}else e.target.checked?t.onChange(n.value):t.onChange("")}}))))))),e.createElement(g,{sx:{color:"var(--joy-palette-danger-500)"},level:"body-sm"},o))})}var ce;!function(e){e.Text="text",e.Password="password",e.Select="select",e.Number="number",e.Float="float",e.Checkbox="checkbox",e.Switch="switch"}(ce||(ce={}));const se=e=>!0===e.allowMultiple&&!Array.isArray(e.defaultValue)&&e.defaultValue?"number"==typeof e.defaultValue?[e.defaultValue]:[String(e.defaultValue)]:e.defaultValue??"";function me(e){const{error:r,attr:a}=e;return r?t.createElement(U,{title:r,color:"danger",sx:{cursor:"pointer"}},t.createElement(T,null,a.label??a.name,t.createElement(k,{sx:{ml:.5,"--Icon-color":"#c41c1c"},fontSize:"small"}))):t.createElement(T,null,a.label??a.name)}function ue(e){const{mutation:r,buttonText:a,attributes:n,cancelButton:o,loading:l,successMessage:i}=e,c=t.useMemo((()=>n.reduce(((e,t)=>(e[t.name]=se(t),e)),{})),[n]),s=x({defaultValues:c}),{register:m,control:u,handleSubmit:d,formState:{errors:g}}=s,E=t.useCallback((e=>{r.mutate(e)}),[r]);return t.createElement(w,{...s},t.createElement(h,{component:"form",onSubmit:d((e=>E(e))),spacing:2},n.map((e=>{const r={},a={key:e.name,label:e.label??e.name,id:e.label??e.name,placeholder:e.placeholder??e.label??e.name,error:Boolean(g[e.name]),disabled:Boolean(e.disabled)},n=e.options??[],o=e.helpText??"";let l="";switch(e.required&&(l=g[e.name]?`${e.label??e.name} is required`:"",r.required=!0),e.type){case ce.Switch:return t.createElement(S,{key:a.key,id:a.id,orientation:"horizontal",sx:{alignItems:"center"}},t.createElement(p,null,t.createElement(me,{error:l,attr:e}),t.createElement(C,{id:`${e.name}-helper-text`},o)),t.createElement(y,{control:u,rules:{required:Boolean(e.required)},name:e.name,render:({field:r})=>{const a={};return g[e.name]&&(a.color="danger"),t.createElement(I,{id:`switch-field-${e.name}`,...a,...r,checked:Boolean(r.value),onChange:e=>{r.onChange(e.target.checked)},color:r.value?"success":"neutral",endDecorator:r.value?n[0].label:n[1].label})}}));case ce.Checkbox:return t.createElement(ie,{key:a.key,attribute:e,display:a,options:n,helperText:o});case ce.Select:return t.createElement(S,{key:a.key,id:a.id},t.createElement(me,{error:l,attr:e}),t.createElement(y,{control:u,rules:{required:Boolean(e.required)},name:e.name,render:({field:r})=>{const l={};g[e.name]&&(l.color="danger");const i=String(r.value);return t.createElement(h,null,t.createElement(j,{id:`select-field-${e.name}`,placeholder:`${a.placeholder}...`,...l,...r,value:i,onChange:(e,t)=>{r.onChange(t)}},n.map((e=>t.createElement(P,{key:String(e.value??""),value:e.value},e.label)))),t.createElement(C,{id:`${e.name}-helper-text`},o))}}));case ce.Password:return t.createElement(S,{key:a.key,id:a.id},t.createElement(me,{error:l,attr:e}),t.createElement(v,{...a,...m(e.name,r),type:ce.Password}),t.createElement(C,{id:`${e.name}-helper-text`},o));case ce.Number:return t.createElement(S,{key:a.key,id:a.id},t.createElement(me,{error:l,attr:e}),t.createElement(v,{...a,...m(e.name,r),type:ce.Number}),t.createElement(C,{id:`${e.name}-helper-text`},o));case ce.Text:default:return t.createElement(S,{key:a.key,id:a.id},t.createElement(me,{error:l,attr:e}),t.createElement(v,{...a,...m(e.name,r)}),t.createElement(C,{id:`${e.name}-helper-text`},o))}})),o?t.createElement(h,{spacing:2,direction:"row"},o,t.createElement(p,null,t.createElement(f,{type:"submit"},a))):t.createElement(p,null,t.createElement(h,{direction:"row",gap:2},t.createElement(f,{type:"submit",loading:l},a),i))))}function de(e){const[r,a]=t.useState(),{buttonText:n="Sign up",onSuccess:o,onError:l,attributes:i,beforeMutate:c}=e,s=re(),u=m((async e=>{a(void 0);const t=(c&&c(e))??e,{email:r,password:n,preferredName:o,newTenant:l,...i}=t;return Object.keys(i).length>0&&console.warn("additional metadata not supported yet."),s.auth.signUp({signUpRequest:{email:r,password:n,preferredName:o,newTenant:l}})}),{onSuccess:o,onError:(e,t)=>{a(e.message),l&&l(e,t)}}),d=t.useMemo((()=>{const e=[{name:"email",label:"Email",type:ce.Text,defaultValue:"",required:!0},{name:"password",label:"Password",type:ce.Password,defaultValue:"",required:!0}];return i&&i.length>0?e.concat(i):e}),[i]);return t.createElement(h,{gap:2},r?t.createElement(E,{color:"danger"},r):null,t.createElement(ue,{mutation:u,buttonText:n,attributes:d}))}function pe(e){const[r,a]=t.useState(),{attributes:n,onSuccess:o,onError:l,beforeMutate:i}=e,c=re(),s=m((async e=>{a(void 0);const t=(i&&i(e))??e;return await c.auth.login({loginRequest:t})}),{onSuccess:o,onError:l}),u=t.useMemo((()=>{const e=[{name:"email",label:"Email",type:ce.Text,defaultValue:"",required:!0},{name:"password",label:"Password",type:ce.Password,defaultValue:"",required:!0}];return n&&n.length>0?e.concat(n):e}),[n]);return t.createElement(h,{gap:2},r?t.createElement(E,{color:"danger"},r):null,t.createElement(ue,{mutation:s,buttonText:"Log in",attributes:u}))}function fe(e){const{attributes:r,onSuccess:a,onError:n,beforeMutate:o,nextButtonText:l="Next",loginButtonText:i="Log in",disableSSO:c=!1}=e,s=re(),[u,d]=t.useState(c?i:l),p=m((async e=>{const t=(o&&o(e))??e;return await s.auth.login({loginRequest:{email:t.email,password:t.password},sso:!c})}),{onSuccess:(e,t)=>{e&&(e?.redirectURI?window.location.href=e.redirectURI:u!==i?d(i):a&&a(e,t))},onError:(e,t)=>{u===i?n&&n(e,t):d(i)}}),f=t.useMemo((()=>{const e=[{name:"email",label:"Email",type:ce.Text,defaultValue:"",required:!0}];return u===i&&e.push({name:"password",label:"Password",type:ce.Password,defaultValue:"",required:!0}),r&&r.length>0?e.concat(r):e}),[r,u,i]);return t.createElement(ue,{mutation:p,buttonText:u,attributes:f})}function he(e){const{open:r,setOpen:a,refetch:n}=e,{tenantId:o}=te(),l=re(),[i,c]=t.useState(),{watch:s,register:u,handleSubmit:d}=x(),p=s("email");t.useEffect((()=>{null!=i&&c()}),[p]);const f=m((e=>l.users.createTenantUser({signUpRequest:e,tenantId:String(o)})),{onSuccess(e){n&&n(e),a(!1)},onError(e){e instanceof Error&&c(e.message)}}),h=t.useCallback((async e=>{c(""),f.mutate(e)}),[f]);return t.createElement(q,{open:r},t.createElement(F,null,t.createElement(R,{spacing:2},t.createElement(B,{level:"h4"},"Create user"),t.createElement(t.Fragment,null,i&&t.createElement(B,{color:"danger"},i)),t.createElement(R,{component:"form",sx:{width:"40ch"},spacing:1,onSubmit:d((e=>h(e)))},t.createElement(M,{sx:{"--FormHelperText-color":"var(--joy-palette-danger-500)"}},t.createElement(O,{htmlFor:"email"},"Email"),t.createElement(V,{...u("email"),fullWidth:!0,size:"lg",id:"email",name:"email",autoComplete:"current-email",required:!0,error:Boolean(i)})),t.createElement(M,{sx:{"--FormHelperText-color":"var(--joy-palette-danger-500)"}},t.createElement(O,{htmlFor:"password"},"Password"),t.createElement(V,{...u("password"),fullWidth:!0,size:"lg",id:"password",autoComplete:"current-password",type:"password",required:!0})),t.createElement(R,{direction:"row",sx:{pt:2},spacing:2},t.createElement(A,{onClick:()=>a(!1),variant:"plain"},"Cancel"),t.createElement(A,{type:"submit"},"Create"))))))}function ge(e){const{allowCreation:r,buttonText:a,onUserCreateSuccess:n}=e,[l,i]=o(!1);return r?t.createElement(h,{alignItems:"flex-end",gap:1},t.createElement(he,{open:l,setOpen:i,refetch:n}),t.createElement(f,{startDecorator:t.createElement(z,null),size:"sm",onClick:()=>i(!0)},a)):null}const Ee=e=>Object.keys(e).reduce(((t,r)=>{const a=e[r];return a instanceof Set?t[r]=Array.from(a).join(", "):Array.isArray(a)?t[r]=a.join(", "):t[r]=a,t}),{}),be=(e,t,r)=>{if(!e)return[[],[]];const a=e.map(Ee),n=Object.keys(a[0]),o={},l=n?.map((e=>{const n=function(e,t,r){let a=r&&e?r.measureText(String(e)).width:50;a+=27;let n=a;return n=16+Math.ceil(r?r.measureText(t.reduce(((t,r)=>{let a=r[String(e)];return(G(a)||H(a))&&(a=""),a=a?.toString(),t.length>a.length?t:a}),"")).width:50),n<a&&(n=a),n+=8,n}(e,a,t),l=e.slice();if(r.includes(l))return null==o[l]?o[l]=l.length:o[l]+=1,{field:l.padEnd(o[l]),headerName:l.padEnd(o[l]),width:n}})).filter(Boolean)??[];return[l,a]};function ye(e,t){const r=function(){const[e,t]=o();return l((()=>{const e=document.createElement("canvas").getContext("2d");e&&(e.font="18px Roboto",t(e))}),[]),e}(),[n,i]=a((()=>be(e,r,t)),[e,r,t]);return[n,i]}function xe(e){const{data:r,allowCreation:a=!0,buttonText:n="Add a user",onUserCreateSuccess:o,slots:l,include:i=["email","preferedName"]}=e,c={width:"100%",height:"100%",...l?.dataGrid??{}},[s,m]=ye(r,i);return t.createElement(h,{flex:1},t.createElement(ge,{allowCreation:a,buttonText:n,onUserCreateSuccess:o}),t.createElement(N,{sx:c,rows:m,columns:s,hideFooter:!0}))}function we(e){const{config:r,providerName:a,onSuccess:n,onError:o,allowEdit:l=!0,configurationGuide:i}=e,c=re(),[s,u]=t.useState(!1),[d,p]=t.useState(!1),[f,b]=t.useState(r),y=t.useRef(),x=t.useMemo((()=>{const e=[{name:"enabled",label:"Allow Okta logins",type:ce.Switch,defaultValue:!0===f?.enabled,options:[{label:"Enabled"},{label:"Disabled"}],disabled:!l},{name:"clientId",label:"Client id",type:ce.Text,defaultValue:f?.clientId??"",required:!0,disabled:!l},{name:"configUrl",label:"Config url",type:ce.Text,defaultValue:f?.configUrl??"",helpText:"The URL of the .well-known/openid-configuration for the identity provider",required:!0,disabled:!l},{name:"emailDomains",label:"Email domains",type:ce.Text,defaultValue:f?.emailDomains?.join(", ")??"",required:!0,helpText:"A comma seperated list of email domains (yourDomain.com) to be used",disabled:!l}];return f?.clientId||e.splice(2,0,{name:"clientSecret",label:"Client secret",type:ce.Password,defaultValue:"",required:!0,disabled:!l}),e}),[l,f?.clientId,f?.configUrl,f?.emailDomains,f?.enabled]),w=m((e=>{u(!0);const t={providerName:a.toLowerCase(),updateProviderRequest:{...e,emailDomains:e.emailDomains.split(",")}};return null!=f?c.auth.updateProvider(t):c.auth.createProvider(t)}),{onSuccess:(e,t)=>{b(e),p(!0),n&&n(e,t)},onError:o,onSettled:(e,t,r)=>{u(!1),y.current&&clearTimeout(y.current),y.current=setTimeout((()=>{p(!1)}),3e3),e||(t&&!t?.message.includes("Unterminated string")||b({enabled:r.enabled,clientId:r.clientId,configUrl:r.configUrl,emailDomains:r.emailDomains.split(", ")}),p(!0),n&&n(e,r))}});return t.useEffect((()=>{})),t.createElement(h,{gap:2,position:"relative"},t.createElement(g,{level:"h4"},"Step 1"),i,t.createElement(g,{level:"h4"},"Step 2"),t.createElement(ue,{mutation:w,buttonText:"Update",attributes:x,loading:s,successMessage:t.createElement(E,{color:"success",sx:{opacity:d?1:0,transition:"opacity 200ms",height:"0.9rem"},startDecorator:t.createElement(Q,null)},t.createElement(g,{textAlign:"center",fontSize:"sm"},"Provider updated"))}))}function ve({callbackUrl:e}){const[r,a]=t.useState(!1),n=t.useRef();return t.useEffect((()=>{n.current&&clearTimeout(n.current),n.current=setTimeout((()=>{a(!1)}),3250)}),[r]),t.createElement(h,{gap:2},t.createElement(g,null,"In order for Okta to redirect properly, provide the following URL as the"," ",t.createElement(p,{component:"span",sx:{fontFamily:"monospace"}},"Sign-in redirect URIs")," ","in the admin configuration of your application."),t.createElement(v,{onClick:async()=>{e&&(await navigator.clipboard.writeText(e),a(!0))},sx:e=>({input:{cursor:"pointer"},span:{cursor:"pointer"},"&:hover svg":{"--Icon-color":e.palette.primary[500]}}),value:e,readOnly:!0,endDecorator:t.createElement(U,{title:"Copy Okta redirect URL"},t.createElement(p,{position:"relative",width:r?"82px":"24px",height:"24px"},t.createElement(p,{position:"absolute",top:"0",left:"0",sx:{opacity:r?0:1,transition:"opacity 300ms"}},t.createElement(W,null)),t.createElement(p,{position:"absolute",top:"0",left:"0",sx:{opacity:r?1:0,transition:"opacity 300ms"}},t.createElement(h,{direction:"row",gap:1},t.createElement(Q,null),t.createElement(g,{color:"primary"},"Copied!")))))}))}function Se(e){const{callbackUrl:r,providers:a,...n}=e;if(!a)return null;const o=a?.find((e=>"okta"===e.provider));return t.createElement(we,{...n,config:o,providerName:"Okta",configurationGuide:t.createElement(ve,{callbackUrl:r})})}export{ce as FormAttributeType,le as GoogleLoginButton,_ as NileProvider,Se as Okta,we as SSOForm,fe as SingleSignOnForm,pe as UserLoginForm,de as UserSignupForm,xe as UserTenantList};
1
+ import * as React from 'react';
2
+ import React__default, { useMemo, useContext, createContext, useState, useEffect } from 'react';
3
+ import Browser from '@niledatabase/browser';
4
+ import { QueryClientProvider, QueryClient, useMutation } from '@tanstack/react-query';
5
+ import CssBaseline from '@mui/material/CssBaseline';
6
+ import { CssVarsProvider } from '@mui/joy/styles';
7
+ import Box from '@mui/joy/Box';
8
+ import Button from '@mui/joy/Button';
9
+ import Stack from '@mui/joy/Stack';
10
+ import Typography from '@mui/joy/Typography';
11
+ import Alert from '@mui/joy/Alert';
12
+ import { useFormContext, Controller, useForm, FormProvider } from 'react-hook-form';
13
+ import Input from '@mui/joy/Input';
14
+ import FormControl from '@mui/joy/FormControl';
15
+ import FormHelperText from '@mui/joy/FormHelperText';
16
+ import Error$1 from '@mui/icons-material/Error';
17
+ import FormLabel from '@mui/joy/FormLabel';
18
+ import Select from '@mui/joy/Select';
19
+ import Option from '@mui/joy/Option';
20
+ import Tooltip from '@mui/joy/Tooltip';
21
+ import { Switch, Modal, ModalDialog, Stack as Stack$1, Typography as Typography$1, FormControl as FormControl$1, FormLabel as FormLabel$1, Input as Input$1, Button as Button$1 } from '@mui/joy';
22
+ import Checkbox from '@mui/joy/Checkbox';
23
+ import List from '@mui/joy/List';
24
+ import ListItem from '@mui/joy/ListItem';
25
+ import { DataGrid } from '@mui/x-data-grid';
26
+ import Add from '@mui/icons-material/Add';
27
+ import CopyAll from '@mui/icons-material/CopyAll';
28
+ import CheckCircleOutlined from '@mui/icons-material/CheckCircleOutlined';
29
+
30
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
31
+ function Themer({
32
+ theme,
33
+ children,
34
+ slotProps
35
+ }) {
36
+ return /*#__PURE__*/React__default.createElement(CssVarsProvider, {
37
+ ...slotProps,
38
+ theme: theme
39
+ }, /*#__PURE__*/React__default.createElement(CssBaseline, {
40
+ enableColorScheme: true
41
+ }), children);
42
+ }
43
+
44
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
45
+ const queryClient = /*#__PURE__*/new QueryClient();
46
+ const defaultContext = {
47
+ api: /*#__PURE__*/new Browser({
48
+ basePath: 'https://api.thenile.dev',
49
+ credentials: 'include'
50
+ }),
51
+ basePath: ''
52
+ };
53
+ const context = /*#__PURE__*/createContext(defaultContext);
54
+ const {
55
+ Provider
56
+ } = context;
57
+ const BaseQueryProvider = ({
58
+ children
59
+ }) => {
60
+ return /*#__PURE__*/React__default.createElement(QueryClientProvider, {
61
+ client: queryClient
62
+ }, children);
63
+ };
64
+ const NileProvider = props => {
65
+ const {
66
+ children,
67
+ theme,
68
+ slotProps,
69
+ tenantId,
70
+ QueryProvider = BaseQueryProvider,
71
+ basePath = 'https://api.thenile.dev',
72
+ api
73
+ } = props;
74
+ const values = useMemo(() => {
75
+ return {
76
+ api: api ?? new Browser({
77
+ basePath,
78
+ credentials: 'include'
79
+ }),
80
+ tenantId: String(tenantId),
81
+ basePath
82
+ };
83
+ }, [api, basePath, tenantId]);
84
+ return /*#__PURE__*/React__default.createElement(QueryProvider, null, /*#__PURE__*/React__default.createElement(Themer, {
85
+ slotProps: slotProps?.provider,
86
+ theme: theme
87
+ }, /*#__PURE__*/React__default.createElement(Provider, {
88
+ value: values
89
+ }, children)));
90
+ };
91
+ const useNileContext = () => {
92
+ return useContext(context);
93
+ };
94
+ const useNileConfig = () => {
95
+ const {
96
+ basePath,
97
+ tenantId
98
+ } = useNileContext();
99
+ return useMemo(() => ({
100
+ tenantId,
101
+ basePath
102
+ }), [basePath, tenantId]);
103
+ };
104
+ const useApi = () => {
105
+ return useNileContext().api;
106
+ };
107
+
108
+ var _g;
109
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
110
+ var SvgGoogle = function SvgGoogle(props) {
111
+ return /*#__PURE__*/React.createElement("svg", _extends({
112
+ xmlns: "http://www.w3.org/2000/svg",
113
+ width: 18,
114
+ height: 18
115
+ }, props), _g || (_g = /*#__PURE__*/React.createElement("g", {
116
+ fillRule: "evenodd"
117
+ }, /*#__PURE__*/React.createElement("path", {
118
+ fill: "#EA4335",
119
+ d: "M9 3.48c1.69 0 2.83.73 3.48 1.34l2.54-2.48C13.46.89 11.43 0 9 0 5.48 0 2.44 2.02.96 4.96l2.91 2.26C4.6 5.05 6.62 3.48 9 3.48"
120
+ }), /*#__PURE__*/React.createElement("path", {
121
+ fill: "#4285F4",
122
+ d: "M17.64 9.2c0-.74-.06-1.28-.19-1.84H9v3.34h4.96c-.1.83-.64 2.08-1.84 2.92l2.84 2.2c1.7-1.57 2.68-3.88 2.68-6.62"
123
+ }), /*#__PURE__*/React.createElement("path", {
124
+ fill: "#FBBC05",
125
+ d: "M3.88 10.78A5.5 5.5 0 0 1 3.58 9c0-.62.11-1.22.29-1.78L.96 4.96A9 9 0 0 0 0 9c0 1.45.35 2.82.96 4.04z"
126
+ }), /*#__PURE__*/React.createElement("path", {
127
+ fill: "#34A853",
128
+ d: "M9 18c2.43 0 4.47-.8 5.96-2.18l-2.84-2.2c-.76.53-1.78.9-3.12.9-2.38 0-4.4-1.57-5.12-3.74L.97 13.04C2.45 15.98 5.48 18 9 18"
129
+ }), /*#__PURE__*/React.createElement("path", {
130
+ fill: "none",
131
+ d: "M0 0h18v18H0z"
132
+ }))));
133
+ };
134
+
135
+ const LOGIN_PATH = 'users/oidc/google/login';
136
+ /**
137
+ * A component for a Google login button, according to their design language.
138
+ * This works when an identity provider is configured in the admin dashboard.
139
+ * @param props href: a string to override the URL provided by the context
140
+ * @returns a JSX.Element to render
141
+ */
142
+ function GoogleSSOButton(props) {
143
+ const {
144
+ databaseId,
145
+ newTenantName
146
+ } = props;
147
+ const {
148
+ basePath
149
+ } = useNileConfig();
150
+ const encodedDatabase = encodeURIComponent(databaseId ?? '');
151
+ const contextHref = `${basePath}/databases/${encodedDatabase}/${LOGIN_PATH}`;
152
+ const query = newTenantName ? '?newTenant=' + encodeURIComponent(newTenantName) : '';
153
+ const href = (props?.href ?? contextHref) + query;
154
+ return /*#__PURE__*/React__default.createElement(Box, {
155
+ component: "a",
156
+ href: href,
157
+ display: "flex",
158
+ flex: 1,
159
+ sx: {
160
+ textDecoration: 'none'
161
+ }
162
+ }, /*#__PURE__*/React__default.createElement(Box, null, /*#__PURE__*/React__default.createElement(Button, {
163
+ sx: {
164
+ padding: 0,
165
+ textTransform: 'initial',
166
+ flex: 1
167
+ },
168
+ "aria-label": "log in with google"
169
+ }, /*#__PURE__*/React__default.createElement(Stack, {
170
+ direction: "row",
171
+ alignItems: "center",
172
+ p: 0,
173
+ flex: 1,
174
+ fontFamily: "Roboto, sans-serif",
175
+ fontSize: "14px",
176
+ display: "inline-flex",
177
+ color: "rgb(255 255, 255)",
178
+ boxShadow: "rgb(0 0 0 / 24%) 0px 2px 2px 0px rgb(0 0 0 / 24%) 0px 0px 1px 0px",
179
+ borderRadius: "4px",
180
+ border: "1px solid transparent",
181
+ fontWeight: "500",
182
+ sx: {
183
+ backgroundColor: 'rgb(66 133, 244)'
184
+ }
185
+ }, /*#__PURE__*/React__default.createElement(Box, {
186
+ padding: "11px",
187
+ display: "flex",
188
+ border: "1px solid rgb(66, 133, 244)",
189
+ borderRadius: "4px",
190
+ sx: {
191
+ background: 'rgb(255, 255, 255)'
192
+ }
193
+ }, /*#__PURE__*/React__default.createElement(SvgGoogle, {
194
+ "aria-hidden": "true"
195
+ })), /*#__PURE__*/React__default.createElement(Box, {
196
+ padding: "10px",
197
+ flex: 1
198
+ }, /*#__PURE__*/React__default.createElement(Typography, {
199
+ sx: {
200
+ color: 'white'
201
+ },
202
+ fontWeight: 700,
203
+ fontFamily: "Roboto, sans-serif",
204
+ fontSize: "14px",
205
+ height: "20px"
206
+ }, "Continue with Google"))))));
207
+ }
208
+
209
+ function CheckGroup(props) {
210
+ const {
211
+ options,
212
+ attribute,
213
+ display,
214
+ helperText
215
+ } = props;
216
+ const {
217
+ watch,
218
+ control
219
+ } = useFormContext();
220
+ const currentVals = watch(attribute.name);
221
+ const checkProps = {};
222
+ if (helperText) {
223
+ checkProps.color = 'danger';
224
+ }
225
+ return /*#__PURE__*/React.createElement(Controller, {
226
+ name: attribute.name,
227
+ rules: {
228
+ required: Boolean(attribute.required)
229
+ },
230
+ control: control,
231
+ render: ({
232
+ field
233
+ }) => {
234
+ return /*#__PURE__*/React.createElement(Stack, null, /*#__PURE__*/React.createElement(FormLabel, {
235
+ htmlFor: `${field.name}`
236
+ }, display.label), /*#__PURE__*/React.createElement(Box, {
237
+ role: "group",
238
+ "aria-labelledby": attribute.name,
239
+ sx: {
240
+ borderRadius: 'var(--joy-radius-sm)',
241
+ p: 0.5,
242
+ border: helperText ? '1px solid var(--joy-palette-danger-outlinedBorder)' : 'none'
243
+ }
244
+ }, /*#__PURE__*/React.createElement(List, {
245
+ orientation: "horizontal",
246
+ wrap: true,
247
+ sx: {
248
+ '--List-gap': '8px'
249
+ }
250
+ }, options.map(item => {
251
+ checkProps.id = String(item.value);
252
+ return /*#__PURE__*/React.createElement(ListItem, {
253
+ key: `${item.value}-${item.label}`
254
+ }, /*#__PURE__*/React.createElement(Checkbox, {
255
+ overlay: options.length > 1,
256
+ ...checkProps,
257
+ checked: currentVals.includes(item.value),
258
+ disableIcon: options.length > 1,
259
+ variant: "soft",
260
+ label: item.label,
261
+ onChange: event => {
262
+ if (attribute.allowMultiple) {
263
+ if (event.target.checked) {
264
+ if (!currentVals) {
265
+ field.onChange([item.value]);
266
+ } else {
267
+ field.onChange(currentVals.concat(item.value));
268
+ }
269
+ } else {
270
+ const remaining = currentVals.filter(val => val !== item.value);
271
+ if (remaining.length > 0) {
272
+ field.onChange(remaining);
273
+ } else {
274
+ field.onChange('');
275
+ }
276
+ }
277
+ } else {
278
+ if (event.target.checked) {
279
+ field.onChange(item.value);
280
+ } else {
281
+ field.onChange('');
282
+ }
283
+ }
284
+ }
285
+ }));
286
+ }))), /*#__PURE__*/React.createElement(Typography, {
287
+ sx: {
288
+ color: 'var(--joy-palette-danger-500)'
289
+ },
290
+ level: "body-sm"
291
+ }, helperText));
292
+ }
293
+ });
294
+ }
295
+
296
+ var AttributeType;
297
+ (function (AttributeType) {
298
+ AttributeType["Text"] = "text";
299
+ AttributeType["Password"] = "password";
300
+ AttributeType["Select"] = "select";
301
+ AttributeType["Number"] = "number";
302
+ AttributeType["Float"] = "float";
303
+ AttributeType["Checkbox"] = "checkbox";
304
+ AttributeType["Switch"] = "switch";
305
+ })(AttributeType || (AttributeType = {}));
306
+
307
+ const getAttributeDefault = attribute => {
308
+ // have to look to see if it is an enum
309
+ if (attribute.allowMultiple === true) {
310
+ if (!Array.isArray(attribute.defaultValue) && attribute.defaultValue) {
311
+ if (typeof attribute.defaultValue === 'number') {
312
+ return [attribute.defaultValue];
313
+ }
314
+ return [String(attribute.defaultValue)];
315
+ }
316
+ }
317
+ return attribute.defaultValue ?? '';
318
+ };
319
+ function Labler(props) {
320
+ const {
321
+ error,
322
+ attr
323
+ } = props;
324
+ if (error) {
325
+ return /*#__PURE__*/React__default.createElement(Tooltip, {
326
+ title: error,
327
+ color: "danger",
328
+ sx: {
329
+ cursor: 'pointer'
330
+ }
331
+ }, /*#__PURE__*/React__default.createElement(FormLabel, null, attr.label ?? attr.name, /*#__PURE__*/React__default.createElement(Error$1, {
332
+ sx: {
333
+ ml: 0.5,
334
+ '--Icon-color': '#c41c1c'
335
+ },
336
+ fontSize: "small"
337
+ })));
338
+ }
339
+ return /*#__PURE__*/React__default.createElement(FormLabel, null, attr.label ?? attr.name);
340
+ }
341
+ function SimpleForm(props) {
342
+ const {
343
+ mutation,
344
+ buttonText,
345
+ attributes,
346
+ cancelButton,
347
+ loading,
348
+ successMessage
349
+ } = props;
350
+ const defaultValues = React__default.useMemo(() => attributes.reduce((accum, attr) => {
351
+ accum[attr.name] = getAttributeDefault(attr);
352
+ return accum;
353
+ }, {}), [attributes]);
354
+ const methods = useForm({
355
+ defaultValues
356
+ });
357
+ const {
358
+ register,
359
+ control,
360
+ handleSubmit,
361
+ formState: {
362
+ errors
363
+ }
364
+ } = methods;
365
+ const onSubmit = React__default.useCallback(
366
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
+ data => {
368
+ mutation.mutate(data);
369
+ }, [mutation]);
370
+ return /*#__PURE__*/React__default.createElement(FormProvider, {
371
+ ...methods
372
+ }, /*#__PURE__*/React__default.createElement(Stack, {
373
+ component: "form",
374
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
375
+ onSubmit: handleSubmit(data => onSubmit(data)),
376
+ spacing: 2
377
+ }, attributes.map(attr => {
378
+ const fieldConfig = {};
379
+ const display = {
380
+ key: attr.name,
381
+ label: attr.label ?? attr.name,
382
+ id: attr.label ?? attr.name,
383
+ placeholder: attr.placeholder ?? attr.label ?? attr.name,
384
+ error: Boolean(errors[attr.name]),
385
+ disabled: Boolean(attr.disabled)
386
+ };
387
+ const options = attr.options ?? [];
388
+ const helperText = attr.helpText ?? '';
389
+ let error = '';
390
+ if (attr.required) {
391
+ error = errors[attr.name] ? `${attr.label ?? attr.name} is required` : '';
392
+ fieldConfig.required = true;
393
+ }
394
+ switch (attr.type) {
395
+ case AttributeType.Switch:
396
+ return /*#__PURE__*/React__default.createElement(FormControl, {
397
+ key: display.key,
398
+ id: display.id,
399
+ orientation: "horizontal",
400
+ sx: {
401
+ alignItems: 'center'
402
+ }
403
+ }, /*#__PURE__*/React__default.createElement(Box, null, /*#__PURE__*/React__default.createElement(Labler, {
404
+ error: error,
405
+ attr: attr
406
+ }), /*#__PURE__*/React__default.createElement(FormHelperText, {
407
+ id: `${attr.name}-helper-text`
408
+ }, helperText)), /*#__PURE__*/React__default.createElement(Controller, {
409
+ control: control,
410
+ rules: {
411
+ required: Boolean(attr.required)
412
+ },
413
+ name: attr.name,
414
+ render: ({
415
+ field
416
+ }) => {
417
+ const color = {};
418
+ if (errors[attr.name]) {
419
+ color.color = 'danger';
420
+ }
421
+ return /*#__PURE__*/React__default.createElement(Switch, {
422
+ id: `switch-field-${attr.name}`,
423
+ ...color,
424
+ ...field,
425
+ checked: Boolean(field.value),
426
+ onChange: event => {
427
+ field.onChange(event.target.checked);
428
+ },
429
+ color: field.value ? 'success' : 'neutral',
430
+ endDecorator: field.value ? options[0].label : options[1].label
431
+ });
432
+ }
433
+ }));
434
+ case AttributeType.Checkbox:
435
+ return /*#__PURE__*/React__default.createElement(CheckGroup, {
436
+ key: display.key,
437
+ attribute: attr,
438
+ display: display,
439
+ options: options,
440
+ helperText: helperText
441
+ });
442
+ case AttributeType.Select:
443
+ return /*#__PURE__*/React__default.createElement(FormControl, {
444
+ key: display.key,
445
+ id: display.id
446
+ }, /*#__PURE__*/React__default.createElement(Labler, {
447
+ error: error,
448
+ attr: attr
449
+ }), /*#__PURE__*/React__default.createElement(Controller, {
450
+ control: control,
451
+ rules: {
452
+ required: Boolean(attr.required)
453
+ },
454
+ name: attr.name,
455
+ render: ({
456
+ field
457
+ }) => {
458
+ const color = {};
459
+ if (errors[attr.name]) {
460
+ color.color = 'danger';
461
+ }
462
+ const value = String(field.value);
463
+ return /*#__PURE__*/React__default.createElement(Stack, null, /*#__PURE__*/React__default.createElement(Select, {
464
+ id: `select-field-${attr.name}`,
465
+ placeholder: `${display.placeholder}...`,
466
+ ...color,
467
+ ...field,
468
+ value: value,
469
+ onChange: (_, newValue) => {
470
+ field.onChange(newValue);
471
+ }
472
+ }, options.map(option => {
473
+ return /*#__PURE__*/React__default.createElement(Option, {
474
+ key: String(option.value ?? ''),
475
+ value: option.value
476
+ }, option.label);
477
+ })), /*#__PURE__*/React__default.createElement(FormHelperText, {
478
+ id: `${attr.name}-helper-text`
479
+ }, helperText));
480
+ }
481
+ }));
482
+ case AttributeType.Password:
483
+ return /*#__PURE__*/React__default.createElement(FormControl, {
484
+ key: display.key,
485
+ id: display.id
486
+ }, /*#__PURE__*/React__default.createElement(Labler, {
487
+ error: error,
488
+ attr: attr
489
+ }), /*#__PURE__*/React__default.createElement(Input, {
490
+ ...display,
491
+ ...register(attr.name, fieldConfig),
492
+ type: AttributeType.Password
493
+ }), /*#__PURE__*/React__default.createElement(FormHelperText, {
494
+ id: `${attr.name}-helper-text`
495
+ }, helperText));
496
+ case AttributeType.Number:
497
+ return /*#__PURE__*/React__default.createElement(FormControl, {
498
+ key: display.key,
499
+ id: display.id
500
+ }, /*#__PURE__*/React__default.createElement(Labler, {
501
+ error: error,
502
+ attr: attr
503
+ }), /*#__PURE__*/React__default.createElement(Input, {
504
+ ...display,
505
+ ...register(attr.name, fieldConfig),
506
+ type: AttributeType.Number
507
+ }), /*#__PURE__*/React__default.createElement(FormHelperText, {
508
+ id: `${attr.name}-helper-text`
509
+ }, helperText));
510
+ case AttributeType.Text:
511
+ default:
512
+ return /*#__PURE__*/React__default.createElement(FormControl, {
513
+ key: display.key,
514
+ id: display.id
515
+ }, /*#__PURE__*/React__default.createElement(Labler, {
516
+ error: error,
517
+ attr: attr
518
+ }), /*#__PURE__*/React__default.createElement(Input, {
519
+ ...display,
520
+ ...register(attr.name, fieldConfig)
521
+ }), /*#__PURE__*/React__default.createElement(FormHelperText, {
522
+ id: `${attr.name}-helper-text`
523
+ }, helperText));
524
+ }
525
+ }), cancelButton ? ( /*#__PURE__*/React__default.createElement(Stack, {
526
+ spacing: 2,
527
+ direction: "row"
528
+ }, cancelButton, /*#__PURE__*/React__default.createElement(Box, null, /*#__PURE__*/React__default.createElement(Button, {
529
+ type: "submit"
530
+ }, buttonText)))) : ( /*#__PURE__*/React__default.createElement(Box, null, /*#__PURE__*/React__default.createElement(Stack, {
531
+ direction: "row",
532
+ gap: 2
533
+ }, /*#__PURE__*/React__default.createElement(Button, {
534
+ type: "submit",
535
+ loading: loading
536
+ }, buttonText), successMessage)))));
537
+ }
538
+
539
+ function SignUpForm(props) {
540
+ const [error, setError] = React__default.useState();
541
+ const {
542
+ buttonText = 'Sign up',
543
+ onSuccess,
544
+ onError,
545
+ attributes,
546
+ beforeMutate
547
+ } = props;
548
+ const api = useApi();
549
+ const mutation = useMutation(async _data => {
550
+ setError(undefined);
551
+ const possibleData = beforeMutate && beforeMutate(_data);
552
+ const data = possibleData ?? _data;
553
+ const {
554
+ email,
555
+ password,
556
+ preferredName,
557
+ newTenant,
558
+ ...metadata
559
+ } = data;
560
+ if (Object.keys(metadata).length > 0) {
561
+ // eslint-disable-next-line no-console
562
+ console.warn('additional metadata not supported yet.');
563
+ }
564
+ return api.auth.signUp({
565
+ signUpRequest: {
566
+ email,
567
+ password,
568
+ preferredName,
569
+ newTenant
570
+ }
571
+ });
572
+ }, {
573
+ onSuccess,
574
+ onError: (e, vars) => {
575
+ setError(e.message);
576
+ onError && onError(e, vars);
577
+ }
578
+ });
579
+ const completeAttributes = React__default.useMemo(() => {
580
+ const mainAttributes = [{
581
+ name: 'email',
582
+ label: 'Email',
583
+ type: AttributeType.Text,
584
+ defaultValue: '',
585
+ required: true
586
+ }, {
587
+ name: 'password',
588
+ label: 'Password',
589
+ type: AttributeType.Password,
590
+ defaultValue: '',
591
+ required: true
592
+ }];
593
+ if (attributes && attributes.length > 0) {
594
+ return mainAttributes.concat(attributes);
595
+ }
596
+ return mainAttributes;
597
+ }, [attributes]);
598
+ return /*#__PURE__*/React__default.createElement(Stack, {
599
+ gap: 2
600
+ }, error ? /*#__PURE__*/React__default.createElement(Alert, {
601
+ color: "danger"
602
+ }, error) : null, /*#__PURE__*/React__default.createElement(SimpleForm, {
603
+ mutation: mutation,
604
+ buttonText: buttonText,
605
+ attributes: completeAttributes
606
+ }));
607
+ }
608
+
609
+ function LoginForm(props) {
610
+ const [error, setError] = React__default.useState();
611
+ const {
612
+ attributes,
613
+ onSuccess,
614
+ onError,
615
+ beforeMutate
616
+ } = props;
617
+ const api = useApi();
618
+ const mutation = useMutation(async _data => {
619
+ setError(undefined);
620
+ const possibleData = beforeMutate && beforeMutate(_data);
621
+ const data = possibleData ?? _data;
622
+ return await api.auth.login({
623
+ loginRequest: data
624
+ });
625
+ }, {
626
+ onSuccess,
627
+ onError
628
+ });
629
+ const completeAttributes = React__default.useMemo(() => {
630
+ const mainAttributes = [{
631
+ name: 'email',
632
+ label: 'Email',
633
+ type: AttributeType.Text,
634
+ defaultValue: '',
635
+ required: true
636
+ }, {
637
+ name: 'password',
638
+ label: 'Password',
639
+ type: AttributeType.Password,
640
+ defaultValue: '',
641
+ required: true
642
+ }];
643
+ if (attributes && attributes.length > 0) {
644
+ return mainAttributes.concat(attributes);
645
+ }
646
+ return mainAttributes;
647
+ }, [attributes]);
648
+ return /*#__PURE__*/React__default.createElement(Stack, {
649
+ gap: 2
650
+ }, error ? /*#__PURE__*/React__default.createElement(Alert, {
651
+ color: "danger"
652
+ }, error) : null, /*#__PURE__*/React__default.createElement(SimpleForm, {
653
+ mutation: mutation,
654
+ buttonText: "Log in",
655
+ attributes: completeAttributes
656
+ }));
657
+ }
658
+
659
+ function SingleSignOnForm(props) {
660
+ const {
661
+ attributes,
662
+ onSuccess,
663
+ onError,
664
+ beforeMutate,
665
+ nextButtonText = 'Next',
666
+ loginButtonText = 'Log in',
667
+ disableSSO = false
668
+ } = props;
669
+ const api = useApi();
670
+ const [buttonText, setButtonText] = React__default.useState(disableSSO ? loginButtonText : nextButtonText);
671
+ const mutation = useMutation(async _data => {
672
+ const possibleData = beforeMutate && beforeMutate(_data);
673
+ const data = possibleData ?? _data;
674
+ return await api.auth.login({
675
+ loginRequest: {
676
+ email: data.email,
677
+ password: data.password
678
+ },
679
+ sso: !disableSSO
680
+ });
681
+ }, {
682
+ onSuccess: (token, data) => {
683
+ if (token) {
684
+ if (token?.redirectURI) {
685
+ window.location.href = token.redirectURI;
686
+ } else if (buttonText !== loginButtonText) {
687
+ setButtonText(loginButtonText);
688
+ } else {
689
+ onSuccess && onSuccess(token, data);
690
+ }
691
+ }
692
+ },
693
+ onError: (error, data) => {
694
+ // it is possible SSO failed, so only show errors on if the password is available
695
+ if (buttonText === loginButtonText) {
696
+ onError && onError(error, data);
697
+ } else {
698
+ setButtonText(loginButtonText);
699
+ }
700
+ }
701
+ });
702
+ const completeAttributes = React__default.useMemo(() => {
703
+ const mainAttributes = [{
704
+ name: 'email',
705
+ label: 'Email',
706
+ type: AttributeType.Text,
707
+ defaultValue: '',
708
+ required: true
709
+ }];
710
+ if (buttonText === loginButtonText) {
711
+ mainAttributes.push({
712
+ name: 'password',
713
+ label: 'Password',
714
+ type: AttributeType.Password,
715
+ defaultValue: '',
716
+ required: true
717
+ });
718
+ }
719
+ if (attributes && attributes.length > 0) {
720
+ return mainAttributes.concat(attributes);
721
+ }
722
+ return mainAttributes;
723
+ }, [attributes, buttonText, loginButtonText]);
724
+ return /*#__PURE__*/React__default.createElement(SimpleForm, {
725
+ mutation: mutation,
726
+ buttonText: buttonText,
727
+ attributes: completeAttributes
728
+ });
729
+ }
730
+
731
+ function AddUser(props) {
732
+ const {
733
+ open,
734
+ setOpen,
735
+ refetch
736
+ } = props;
737
+ const {
738
+ tenantId
739
+ } = useNileConfig();
740
+ const api = useApi();
741
+ const [errorText, setErrorText] = React__default.useState();
742
+ const {
743
+ watch,
744
+ register,
745
+ handleSubmit
746
+ } = useForm();
747
+ const email = watch('email');
748
+ React__default.useEffect(() => {
749
+ if (errorText != null) {
750
+ setErrorText();
751
+ }
752
+ // if email changes, no more error
753
+ // eslint-disable-next-line react-hooks/exhaustive-deps
754
+ }, [email]);
755
+ const mutation = useMutation(data => api.users.createTenantUser({
756
+ signUpRequest: data,
757
+ tenantId: String(tenantId)
758
+ }), {
759
+ onSuccess(data) {
760
+ refetch && refetch(data);
761
+ setOpen(false);
762
+ },
763
+ onError(e) {
764
+ if (e instanceof Error) {
765
+ setErrorText(e.message);
766
+ }
767
+ }
768
+ });
769
+ const handleUpdate = React__default.useCallback(async data => {
770
+ setErrorText('');
771
+ mutation.mutate(data);
772
+ }, [mutation]);
773
+ return /*#__PURE__*/React__default.createElement(Modal, {
774
+ open: open
775
+ }, /*#__PURE__*/React__default.createElement(ModalDialog, null, /*#__PURE__*/React__default.createElement(Stack$1, {
776
+ spacing: 2
777
+ }, /*#__PURE__*/React__default.createElement(Typography$1, {
778
+ level: "h4"
779
+ }, "Create user"), /*#__PURE__*/React__default.createElement(React__default.Fragment, null, errorText && /*#__PURE__*/React__default.createElement(Typography$1, {
780
+ color: "danger"
781
+ }, errorText)), /*#__PURE__*/React__default.createElement(Stack$1, {
782
+ component: "form",
783
+ sx: {
784
+ width: '40ch'
785
+ },
786
+ spacing: 1,
787
+ onSubmit: handleSubmit(data => handleUpdate(data))
788
+ }, /*#__PURE__*/React__default.createElement(FormControl$1, {
789
+ sx: {
790
+ '--FormHelperText-color': 'var(--joy-palette-danger-500)'
791
+ }
792
+ }, /*#__PURE__*/React__default.createElement(FormLabel$1, {
793
+ htmlFor: "email"
794
+ }, "Email"), /*#__PURE__*/React__default.createElement(Input$1, {
795
+ ...register('email'),
796
+ fullWidth: true,
797
+ size: "lg",
798
+ id: "email",
799
+ name: "email",
800
+ autoComplete: "current-email",
801
+ required: true,
802
+ error: Boolean(errorText)
803
+ })), /*#__PURE__*/React__default.createElement(FormControl$1, {
804
+ sx: {
805
+ '--FormHelperText-color': 'var(--joy-palette-danger-500)'
806
+ }
807
+ }, /*#__PURE__*/React__default.createElement(FormLabel$1, {
808
+ htmlFor: "password"
809
+ }, "Password"), /*#__PURE__*/React__default.createElement(Input$1, {
810
+ ...register('password'),
811
+ fullWidth: true,
812
+ size: "lg",
813
+ id: "password",
814
+ autoComplete: "current-password",
815
+ type: "password",
816
+ required: true
817
+ })), /*#__PURE__*/React__default.createElement(Stack$1, {
818
+ direction: "row",
819
+ sx: {
820
+ pt: 2
821
+ },
822
+ spacing: 2
823
+ }, /*#__PURE__*/React__default.createElement(Button$1, {
824
+ onClick: () => setOpen(false),
825
+ variant: "plain"
826
+ }, "Cancel"), /*#__PURE__*/React__default.createElement(Button$1, {
827
+ type: "submit"
828
+ }, "Create"))))));
829
+ }
830
+
831
+ function CreateUser(props) {
832
+ const {
833
+ allowCreation,
834
+ buttonText,
835
+ onUserCreateSuccess
836
+ } = props;
837
+ const [open, setOpen] = useState(false);
838
+ if (!allowCreation) {
839
+ return null;
840
+ }
841
+ return /*#__PURE__*/React__default.createElement(Stack, {
842
+ alignItems: "flex-end",
843
+ gap: 1
844
+ }, /*#__PURE__*/React__default.createElement(AddUser, {
845
+ open: open,
846
+ setOpen: setOpen,
847
+ refetch: onUserCreateSuccess
848
+ }), /*#__PURE__*/React__default.createElement(Button, {
849
+ startDecorator: /*#__PURE__*/React__default.createElement(Add, null),
850
+ size: "sm",
851
+ onClick: () => setOpen(true)
852
+ }, buttonText));
853
+ }
854
+
855
+ function getColumnSize(column, rows, canvasContext) {
856
+ const dataWidthReducer = (longest,
857
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
858
+ nextRow) => {
859
+ let value = nextRow[String(column)];
860
+ if (value == null) {
861
+ value = '';
862
+ }
863
+ value = value?.toString();
864
+ return longest.length > value.length ? longest : value;
865
+ };
866
+ let columnHeaderLen = canvasContext && column ? canvasContext.measureText(String(column)).width : 50;
867
+ /* padding 12, icon-width 15 */
868
+ columnHeaderLen += 15 + 12;
869
+ let width = columnHeaderLen;
870
+ width = 16 + Math.ceil(canvasContext ? canvasContext.measureText(rows.reduce(dataWidthReducer, '')).width : 50);
871
+ if (width < columnHeaderLen) {
872
+ width = columnHeaderLen;
873
+ }
874
+ /* Gracefull */
875
+ width += 8;
876
+ return width;
877
+ }
878
+
879
+ function useTextSizer() {
880
+ const [ctx, setCtx] = useState();
881
+ useEffect(() => {
882
+ const canvas = document.createElement('canvas');
883
+ const canvasContext = canvas.getContext('2d');
884
+ if (canvasContext) {
885
+ canvasContext.font = '18px Roboto';
886
+ setCtx(canvasContext);
887
+ }
888
+ }, []);
889
+ return ctx;
890
+ }
891
+
892
+ const makeRenderable = vals => {
893
+ return Object.keys(vals).reduce((cleaned, key) => {
894
+ const val = vals[key];
895
+ if (val instanceof Set) {
896
+ cleaned[key] = Array.from(val).join(', ');
897
+ } else if (Array.isArray(val)) {
898
+ cleaned[key] = val.join(', ');
899
+ } else {
900
+ cleaned[key] = val;
901
+ }
902
+ return cleaned;
903
+ }, {});
904
+ };
905
+ const parseResults = (data, ctx, include) => {
906
+ if (!data) {
907
+ return [[], []];
908
+ }
909
+ const rows = data.map(makeRenderable);
910
+ const fields = Object.keys(rows[0]);
911
+ const existentCols = {};
912
+ const mapCols = col => {
913
+ const width = getColumnSize(col, rows, ctx);
914
+ const name = col.slice();
915
+ if (include.includes(name)) {
916
+ // add spaces to the end of column names so they are not duplicated in the UI
917
+ if (existentCols[name] == null) {
918
+ existentCols[name] = name.length;
919
+ } else {
920
+ existentCols[name] += 1;
921
+ }
922
+ return {
923
+ field: name.padEnd(existentCols[name]),
924
+ headerName: name.padEnd(existentCols[name]),
925
+ width
926
+ };
927
+ }
928
+ };
929
+ const cols = fields?.map(mapCols).filter(Boolean) ?? [];
930
+ return [cols, rows];
931
+ };
932
+ function useDataParser(data, include) {
933
+ const ctx = useTextSizer();
934
+ const [cols, rows] = useMemo(() => parseResults(data, ctx, include), [data, ctx, include]);
935
+ return [cols, rows];
936
+ }
937
+
938
+ function UserList(props) {
939
+ const {
940
+ data,
941
+ allowCreation = true,
942
+ buttonText = 'Add a user',
943
+ onUserCreateSuccess,
944
+ slots,
945
+ include = ['email', 'preferedName']
946
+ } = props;
947
+ const dataGridSx = {
948
+ width: '100%',
949
+ height: '100%',
950
+ ...(slots?.dataGrid ?? {})
951
+ };
952
+ const [columns, rows] = useDataParser(data, include);
953
+ return /*#__PURE__*/React__default.createElement(Stack, {
954
+ flex: 1
955
+ }, /*#__PURE__*/React__default.createElement(CreateUser, {
956
+ allowCreation: allowCreation,
957
+ buttonText: buttonText,
958
+ onUserCreateSuccess: onUserCreateSuccess
959
+ }), /*#__PURE__*/React__default.createElement(DataGrid, {
960
+ sx: dataGridSx,
961
+ rows: rows,
962
+ columns: columns,
963
+ hideFooter: true
964
+ }));
965
+ }
966
+
967
+ function BaseSSOForm(props) {
968
+ const {
969
+ config,
970
+ providerName,
971
+ onSuccess,
972
+ onError,
973
+ allowEdit = true,
974
+ configurationGuide
975
+ } = props;
976
+ const api = useApi();
977
+ const [loading, setLoading] = React__default.useState(false);
978
+ const [success, setSuccess] = React__default.useState(false);
979
+ const [optimisticConfig, setConfig] = React__default.useState(config);
980
+ const timer = React__default.useRef();
981
+ const attributes = React__default.useMemo(() => {
982
+ const attributes = [{
983
+ name: 'enabled',
984
+ label: 'Allow Okta logins',
985
+ type: AttributeType.Switch,
986
+ defaultValue: optimisticConfig?.enabled === true,
987
+ options: [{
988
+ label: 'Enabled'
989
+ }, {
990
+ label: 'Disabled'
991
+ }],
992
+ disabled: !allowEdit
993
+ }, {
994
+ name: 'clientId',
995
+ label: 'Client id',
996
+ type: AttributeType.Text,
997
+ defaultValue: optimisticConfig?.clientId ?? '',
998
+ required: true,
999
+ disabled: !allowEdit
1000
+ }, {
1001
+ name: 'configUrl',
1002
+ label: 'Config url',
1003
+ type: AttributeType.Text,
1004
+ defaultValue: optimisticConfig?.configUrl ?? '',
1005
+ helpText: 'The URL of the .well-known/openid-configuration for the identity provider',
1006
+ required: true,
1007
+ disabled: !allowEdit
1008
+ }, {
1009
+ name: 'emailDomains',
1010
+ label: 'Email domains',
1011
+ type: AttributeType.Text,
1012
+ defaultValue: optimisticConfig?.emailDomains?.join(', ') ?? '',
1013
+ required: true,
1014
+ helpText: 'A comma seperated list of email domains (yourDomain.com) to be used',
1015
+ disabled: !allowEdit
1016
+ }];
1017
+ if (!optimisticConfig?.clientId) {
1018
+ attributes.splice(2, 0, {
1019
+ name: 'clientSecret',
1020
+ label: 'Client secret',
1021
+ type: AttributeType.Password,
1022
+ defaultValue: '',
1023
+ required: true,
1024
+ disabled: !allowEdit
1025
+ });
1026
+ }
1027
+ return attributes;
1028
+ }, [allowEdit, optimisticConfig?.clientId, optimisticConfig?.configUrl, optimisticConfig?.emailDomains, optimisticConfig?.enabled]);
1029
+ const handleTimer = () => {
1030
+ if (timer.current) {
1031
+ clearTimeout(timer.current);
1032
+ }
1033
+ timer.current = setTimeout(() => {
1034
+ setSuccess(false);
1035
+ }, 3000);
1036
+ };
1037
+ const mutation = useMutation(ssoRequest => {
1038
+ setLoading(true);
1039
+ const payload = {
1040
+ providerName: providerName.toLowerCase(),
1041
+ updateProviderRequest: {
1042
+ ...ssoRequest,
1043
+ emailDomains: ssoRequest.emailDomains.split(',')
1044
+ }
1045
+ };
1046
+ if (optimisticConfig != null) {
1047
+ return api.auth.updateProvider(payload);
1048
+ } else {
1049
+ return api.auth.createProvider(payload);
1050
+ }
1051
+ }, {
1052
+ onSuccess: (data, vars) => {
1053
+ setConfig(data);
1054
+ setSuccess(true);
1055
+ onSuccess && onSuccess(data, vars);
1056
+ },
1057
+ onError,
1058
+ onSettled: (data, error, vars) => {
1059
+ setLoading(false);
1060
+ handleTimer();
1061
+ if (!data) {
1062
+ if (!error || error?.message.includes('Unterminated string')) {
1063
+ // something unexpected happened on the BE, but it's non-fatal
1064
+ setConfig({
1065
+ enabled: vars.enabled,
1066
+ clientId: vars.clientId,
1067
+ configUrl: vars.configUrl,
1068
+ emailDomains: vars.emailDomains.split(', ')
1069
+ });
1070
+ }
1071
+ setSuccess(true);
1072
+ onSuccess && onSuccess(data, vars);
1073
+ }
1074
+ }
1075
+ });
1076
+ React__default.useEffect(() => {
1077
+ });
1078
+ return /*#__PURE__*/React__default.createElement(Stack, {
1079
+ gap: 2,
1080
+ position: "relative"
1081
+ }, /*#__PURE__*/React__default.createElement(Typography, {
1082
+ level: "h4"
1083
+ }, "Step 1"), configurationGuide, /*#__PURE__*/React__default.createElement(Typography, {
1084
+ level: "h4"
1085
+ }, "Step 2"), /*#__PURE__*/React__default.createElement(SimpleForm, {
1086
+ mutation: mutation,
1087
+ buttonText: "Update",
1088
+ attributes: attributes,
1089
+ loading: loading,
1090
+ successMessage: /*#__PURE__*/React__default.createElement(Alert, {
1091
+ color: "success",
1092
+ sx: {
1093
+ opacity: success ? 1 : 0,
1094
+ transition: 'opacity 200ms',
1095
+ height: '0.9rem'
1096
+ },
1097
+ startDecorator: /*#__PURE__*/React__default.createElement(CheckCircleOutlined, null)
1098
+ }, /*#__PURE__*/React__default.createElement(Typography, {
1099
+ textAlign: "center",
1100
+ fontSize: "sm"
1101
+ }, "Provider updated"))
1102
+ }));
1103
+ }
1104
+
1105
+ function ConfigGuide({
1106
+ callbackUrl
1107
+ }) {
1108
+ const [copied, setCopied] = React__default.useState(false);
1109
+ const timer = React__default.useRef();
1110
+ React__default.useEffect(() => {
1111
+ if (timer.current) {
1112
+ clearTimeout(timer.current);
1113
+ }
1114
+ timer.current = setTimeout(() => {
1115
+ setCopied(false);
1116
+ }, 3250);
1117
+ }, [copied]);
1118
+ return /*#__PURE__*/React__default.createElement(Stack, {
1119
+ gap: 2
1120
+ }, /*#__PURE__*/React__default.createElement(Typography, null, "In order for Okta to redirect properly, provide the following URL as the", ' ', /*#__PURE__*/React__default.createElement(Box, {
1121
+ component: "span",
1122
+ sx: {
1123
+ fontFamily: 'monospace'
1124
+ }
1125
+ }, "Sign-in redirect URIs"), ' ', "in the admin configuration of your application."), /*#__PURE__*/React__default.createElement(Input, {
1126
+ onClick: async () => {
1127
+ if (callbackUrl) {
1128
+ await navigator.clipboard.writeText(callbackUrl);
1129
+ setCopied(true);
1130
+ }
1131
+ },
1132
+ sx: theme => ({
1133
+ input: {
1134
+ cursor: 'pointer'
1135
+ },
1136
+ span: {
1137
+ cursor: 'pointer'
1138
+ },
1139
+ '&:hover svg': {
1140
+ '--Icon-color': theme.palette.primary[500]
1141
+ }
1142
+ }),
1143
+ value: callbackUrl,
1144
+ readOnly: true,
1145
+ endDecorator: /*#__PURE__*/React__default.createElement(Tooltip, {
1146
+ title: "Copy Okta redirect URL"
1147
+ }, /*#__PURE__*/React__default.createElement(Box, {
1148
+ position: "relative",
1149
+ width: copied ? '82px' : '24px',
1150
+ height: "24px"
1151
+ }, /*#__PURE__*/React__default.createElement(Box, {
1152
+ position: "absolute",
1153
+ top: "0",
1154
+ left: "0",
1155
+ sx: {
1156
+ opacity: copied ? 0 : 1,
1157
+ transition: 'opacity 300ms'
1158
+ }
1159
+ }, /*#__PURE__*/React__default.createElement(CopyAll, null)), /*#__PURE__*/React__default.createElement(Box, {
1160
+ position: "absolute",
1161
+ top: "0",
1162
+ left: "0",
1163
+ sx: {
1164
+ opacity: !copied ? 0 : 1,
1165
+ transition: 'opacity 300ms'
1166
+ }
1167
+ }, /*#__PURE__*/React__default.createElement(Stack, {
1168
+ direction: "row",
1169
+ gap: 1
1170
+ }, /*#__PURE__*/React__default.createElement(CheckCircleOutlined, null), /*#__PURE__*/React__default.createElement(Typography, {
1171
+ color: "primary"
1172
+ }, "Copied!")))))
1173
+ }));
1174
+ }
1175
+ function Okta(props) {
1176
+ const {
1177
+ callbackUrl,
1178
+ providers,
1179
+ ...remaining
1180
+ } = props;
1181
+ if (!providers) {
1182
+ return null;
1183
+ }
1184
+ const config = providers?.find(provider => provider.provider === 'okta');
1185
+ return /*#__PURE__*/React__default.createElement(BaseSSOForm, {
1186
+ ...remaining,
1187
+ config: config,
1188
+ providerName: "Okta",
1189
+ configurationGuide: /*#__PURE__*/React__default.createElement(ConfigGuide, {
1190
+ callbackUrl: callbackUrl
1191
+ })
1192
+ });
1193
+ }
1194
+
1195
+ export { AttributeType as FormAttributeType, GoogleSSOButton as GoogleLoginButton, NileProvider, Okta, BaseSSOForm as SSOForm, SingleSignOnForm, LoginForm as UserLoginForm, SignUpForm as UserSignupForm, UserList as UserTenantList };
2
1196
  //# sourceMappingURL=react.esm.js.map