-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* clean up org tabs * org users table * user groups * capitalize * delete user group action * fix user group deletion * rerender * class tweaks * add basic table component * apply basic table to project resources table * set user group role * add then set role for user group * conditional item or checkbox item based on role * revoke user group role * bug fix * rename user group dialog * rework forms in user group dialogs * user composite cell * lint * lint * lint * add user to org * remove user from org * fix disabled * add avatar component * set role for org member user * lint * disallow current user to change role or remove themselves * show org invites * fix interface * add member to user group * allow adding user to user group for verified users * organize dialog footer actions * add users to usergroup * wip before edit user group dialog * pending invite copy * update user round for avatar placeholder when no alt * allow add to group for current user * edit user group dialog, remove user from group * lint * remove rename user group dialog * polish user group member users list * pass current user email down * update copy * org groups table role cell, set or update role * clean up * org users table role cell * lint * rework add users * lint * basic table tweaks, widthPercent addition * lint * search in users table, empty text * search in groups table * nit * lint * clean up, hide remove for all-users * lint * pre combobox * use combobox, search and add users in create group dialog * remove unused, clean up for all-users group * lint * ability to add users to usergroup in edit group dialog * remove adding users to usergroup in create group dialog * add avatar circle list, polish typeahead * lint * filter out users that are already in the group * lint * danger text for remove text button * clean up * fix input styles in combobox * remove unused * try * lint * bump typecheck nonsvelte files * add scrollable table config, random color wip * comment * clean up * clean up * clean up * scope out usergroup changes * comment * remove collaborator role option * use random color, non-gray, non-primary-secondary * clean up * Revert "bump typecheck nonsvelte files" This reverts commit e18a898. * add chevron to role change * Reapply "bump typecheck nonsvelte files" This reverts commit 4a5418e. * horizontal line feedback * lint * text danger * deterministic bg color client side * comment out desc from settings * noop comment * Revert "comment out desc from settings" This reverts commit 3e4d6e2. * feedback * update src alt conditionals from avatar * feedback * fix rebase * avoid prop drilling, feedback
- Loading branch information
1 parent
dd0cd06
commit 756095f
Showing
32 changed files
with
2,000 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
199 changes: 199 additions & 0 deletions
199
web-admin/src/features/organizations/users/AddUsersDialog.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
<script lang="ts"> | ||
import { | ||
Dialog, | ||
DialogContent, | ||
DialogHeader, | ||
DialogTitle, | ||
DialogTrigger, | ||
} from "@rilldata/web-common/components/dialog-v2"; | ||
import { Button } from "@rilldata/web-common/components/button/index.js"; | ||
import { defaults, superForm } from "sveltekit-superforms"; | ||
import { yup } from "sveltekit-superforms/adapters"; | ||
import { array, object, string } from "yup"; | ||
import MultiInput from "@rilldata/web-common/components/forms/MultiInput.svelte"; | ||
import UserRoleSelect from "@rilldata/web-admin/features/projects/user-invite/UserRoleSelect.svelte"; | ||
import { RFC5322EmailRegex } from "@rilldata/web-common/components/forms/validation"; | ||
import { eventBus } from "@rilldata/web-common/lib/event-bus/event-bus"; | ||
import { useQueryClient } from "@tanstack/svelte-query"; | ||
import { | ||
createAdminServiceAddOrganizationMemberUser, | ||
getAdminServiceListOrganizationInvitesQueryKey, | ||
getAdminServiceListOrganizationMemberUsersQueryKey, | ||
} from "@rilldata/web-admin/client"; | ||
import { page } from "$app/stores"; | ||
export let open = false; | ||
export let email: string; | ||
export let role: string; | ||
export let isSuperUser: boolean; | ||
$: organization = $page.params.organization; | ||
const queryClient = useQueryClient(); | ||
const addOrganizationMemberUser = | ||
createAdminServiceAddOrganizationMemberUser(); | ||
async function handleCreate( | ||
newEmail: string, | ||
newRole: string, | ||
isSuperUser: boolean = false, | ||
) { | ||
try { | ||
await $addOrganizationMemberUser.mutateAsync({ | ||
organization: organization, | ||
data: { | ||
email: newEmail, | ||
role: newRole, | ||
superuserForceAccess: isSuperUser, | ||
}, | ||
}); | ||
await queryClient.invalidateQueries( | ||
getAdminServiceListOrganizationMemberUsersQueryKey(organization), | ||
); | ||
await queryClient.invalidateQueries( | ||
getAdminServiceListOrganizationInvitesQueryKey(organization), | ||
); | ||
email = ""; | ||
role = ""; | ||
isSuperUser = false; | ||
open = false; | ||
eventBus.emit("notification", { message: "User added to organization" }); | ||
} catch (error) { | ||
console.error("Error adding user to organization", error); | ||
eventBus.emit("notification", { | ||
message: "Error adding user to organization", | ||
type: "error", | ||
}); | ||
} | ||
} | ||
const formId = "add-user-form"; | ||
const initialValues: { | ||
emails: string[]; | ||
role: string; | ||
} = { | ||
emails: [""], | ||
role: "viewer", | ||
}; | ||
const schema = yup( | ||
object({ | ||
emails: array( | ||
string().matches(RFC5322EmailRegex, { | ||
excludeEmptyString: true, | ||
message: "Invalid email", | ||
}), | ||
), // yup's email regex is too simple | ||
role: string().required(), | ||
}), | ||
); | ||
const { form, errors, enhance, submit, submitting } = superForm( | ||
defaults(initialValues, schema), | ||
{ | ||
SPA: true, | ||
validators: schema, | ||
async onUpdate({ form }) { | ||
if (!form.valid) return; | ||
const values = form.data; | ||
const emails = values.emails.map((e) => e.trim()).filter(Boolean); | ||
if (emails.length === 0) return; | ||
const succeeded = []; | ||
let errored = false; | ||
await Promise.all( | ||
emails.map(async (email) => { | ||
try { | ||
await handleCreate(email, values.role, isSuperUser); | ||
succeeded.push(email); | ||
} catch (error) { | ||
console.error("Error adding user to organization", error); | ||
errored = true; | ||
} | ||
}), | ||
); | ||
eventBus.emit("notification", { | ||
type: "success", | ||
message: `Invited ${succeeded.length} ${succeeded.length === 1 ? "person" : "people"} as ${values.role}`, | ||
}); | ||
if (errored) { | ||
eventBus.emit("notification", { | ||
type: "error", | ||
message: | ||
"Some invitations could not be sent. Please check the email addresses and try again.", | ||
}); | ||
} | ||
}, | ||
validationMethod: "oninput", | ||
}, | ||
); | ||
$: hasInvalidEmails = $form.emails.some( | ||
(e, i) => e.length > 0 && $errors.emails?.[i] !== undefined, | ||
); | ||
</script> | ||
|
||
<Dialog | ||
bind:open | ||
onOutsideClick={(e) => { | ||
e.preventDefault(); | ||
open = false; | ||
email = ""; | ||
role = ""; | ||
isSuperUser = false; | ||
}} | ||
onOpenChange={(open) => { | ||
if (!open) { | ||
email = ""; | ||
role = ""; | ||
isSuperUser = false; | ||
} | ||
}} | ||
> | ||
<DialogTrigger asChild> | ||
<div class="hidden"></div> | ||
</DialogTrigger> | ||
<DialogContent class="translate-y-[-200px]"> | ||
<DialogHeader> | ||
<DialogTitle>Add users</DialogTitle> | ||
</DialogHeader> | ||
<form | ||
id={formId} | ||
on:submit|preventDefault={submit} | ||
class="w-full" | ||
use:enhance | ||
> | ||
<MultiInput | ||
id="emails" | ||
placeholder="Add emails, separated by commas" | ||
contentClassName="relative" | ||
bind:values={$form.emails} | ||
errors={$errors.emails} | ||
singular="email" | ||
plural="emails" | ||
> | ||
<div slot="within-input" class="flex items-center h-full"> | ||
<UserRoleSelect bind:value={$form.role} /> | ||
</div> | ||
<svelte:fragment slot="beside-input" let:hasSomeValue> | ||
<Button | ||
submitForm | ||
type="primary" | ||
form={formId} | ||
loading={$submitting} | ||
disabled={hasInvalidEmails || !hasSomeValue} | ||
forcedStyle="height: 32px !important;" | ||
> | ||
Invite | ||
</Button> | ||
</svelte:fragment> | ||
</MultiInput> | ||
</form> | ||
</DialogContent> | ||
</Dialog> |
28 changes: 28 additions & 0 deletions
28
web-admin/src/features/organizations/users/AvatarCircleList.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<script lang="ts"> | ||
import Avatar from "@rilldata/web-common/components/avatar/Avatar.svelte"; | ||
import { getRandomColor } from "@rilldata/web-common/features/themes/color-config"; | ||
export let name: string; | ||
export let email: string; | ||
export let isCurrentUser: boolean = false; | ||
export let pendingAcceptance: boolean = false; | ||
</script> | ||
|
||
<div class="flex items-center gap-2"> | ||
<Avatar | ||
size="h-7 w-7" | ||
alt={pendingAcceptance ? null : name} | ||
bgColor={getRandomColor(email)} | ||
/> | ||
<div class="flex flex-col text-left"> | ||
<span class="text-sm font-medium text-gray-900"> | ||
{name} | ||
<span class="text-gray-500 font-normal"> | ||
{isCurrentUser ? "(You)" : ""} | ||
</span> | ||
</span> | ||
<span class="text-xs text-gray-500" | ||
>{pendingAcceptance ? "Pending invitation" : email}</span | ||
> | ||
</div> | ||
</div> |
Oops, something went wrong.
756095f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉 Published on https://ui.rilldata.in as production
🚀 Deployed on https://67096a6c96a5a4205c34868c--rill-ui-dev.netlify.app