feat: auto-invite from same domain

This commit is contained in:
Ruben Fiszel
2022-12-12 20:20:17 +01:00
parent 42ea1a6468
commit db4fcfdbec
18 changed files with 520 additions and 204 deletions
@@ -128,9 +128,9 @@
deleteConfirmedCallback = async () => {
await UserService.globalUserDelete({ email })
sendUserToast(`User ${email} removed`)
listUsers()
await listUsers()
}
openConfirmation = true
openConfirmation = false
}}>remove</button
>
</div>
@@ -1,5 +1,5 @@
<script lang="ts">
import { faDashboard, faPlus } from '@fortawesome/free-solid-svg-icons'
import { faPlus } from '@fortawesome/free-solid-svg-icons'
import { AppService, Policy } from '$lib/gen'
import { userStore, workspaceStore } from '$lib/stores'
import { sendUserToast } from '$lib/utils'
@@ -60,7 +60,9 @@
</div>
</Path>
<Button on:click={() => createApp()}>Create app</Button>
<div slot="actions">
<Button on:click={() => createApp()}>Create app</Button>
</div>
</DrawerContent>
</Drawer>
@@ -1,9 +1,10 @@
<script lang="ts">
import Dropdown from '$lib/components/Dropdown.svelte'
import SharedBadge from '$lib/components/SharedBadge.svelte'
import type { ListableApp } from '$lib/gen'
import { AppService, type ListableApp } from '$lib/gen'
import { workspaceStore } from '$lib/stores'
import { faEdit, faEye } from '@fortawesome/free-solid-svg-icons'
import { faEdit, faEye, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { createEventDispatcher } from 'svelte'
import Button from '../button/Button.svelte'
import Row from './Row.svelte'
@@ -12,6 +13,8 @@
export let starred: boolean
let { summary, path, extra_perms, canWrite, workspace_id } = app
const dispatch = createEventDispatcher()
</script>
<Row
@@ -28,38 +31,49 @@
<SharedBadge {canWrite} extraPerms={extra_perms} />
</svelte:fragment>
<svelte:fragment slot="actions">
<span class="hidden md:inline-flex gap-x-1">
{#if canWrite}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faEdit }}
href="/apps/edit/{path}"
>
Edit
</Button>
</div>
{/if}
<Button
href="/apps/get/{path}"
color="dark"
size="xs"
spacingSize="md"
startIcon={{ icon: faEye }}
>
View
</Button>
</span>
<Dropdown
placement="bottom-end"
dropdownItems={[
{
displayName: 'View app',
icon: faEye,
href: `/apps/get/${path}`
},
{
displayName: 'Delete',
icon: faTrashAlt,
action: async () => {
await AppService.deleteApp({ workspace: $workspaceStore ?? '', path })
dispatch('change')
},
type: 'delete',
disabled: !canWrite
}
]}
/>
{#if canWrite}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faEdit }}
href="/apps/edit/{path}"
>
Edit
</Button>
</div>
{/if}
<Button
href="/apps/get/{path}"
color="dark"
size="xs"
spacingSize="md"
startIcon={{ icon: faEye }}
>
View
</Button>
</svelte:fragment>
</Row>
@@ -55,7 +55,56 @@
<SharedBadge {canWrite} extraPerms={extra_perms} />
</svelte:fragment>
<svelte:fragment slot="actions">
<span class="hidden md:inline-flex gap-x-1">
{#if canWrite}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faEdit }}
href="/flows/edit/{path}"
>
Edit
</Button>
</div>
{:else}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faCodeFork }}
href="/flows/add?template={path}"
>
Fork
</Button>
</div>
{/if}
<Button
href="/flows/get/{path}"
color="light"
variant="border"
size="xs"
spacingSize="md"
startIcon={{ icon: faEye }}
>
Detail
</Button>
<Button
href="/flows/run/{path}"
color="dark"
size="xs"
spacingSize="md"
endIcon={{ icon: faPlay }}
>
Run
</Button>
</span>
<Dropdown
placement="bottom-end"
dropdownItems={[
{
displayName: 'View flow',
@@ -102,51 +151,5 @@
}
]}
/>
{#if canWrite}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faEdit }}
href="/flows/edit/{path}"
>
Edit
</Button>
</div>
{:else}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faCodeFork }}
href="/flows/add?template={path}"
>
Fork
</Button>
</div>
{/if}
<Button
href="/flows/get/{path}"
color="light"
variant="border"
size="xs"
spacingSize="md"
startIcon={{ icon: faEye }}
>
Detail
</Button>
<Button
href="/flows/run/{path}"
color="dark"
size="xs"
spacingSize="md"
endIcon={{ icon: faPlay }}
>
Run
</Button>
</svelte:fragment>
</Row>
@@ -29,19 +29,19 @@
>
<RowIcon {kind} />
<div class="w-full">
<div class="text-gray-900 flex-wrap text-md font-semibold mb-1">
<div class="w-full min-w-0 ">
<div class="text-gray-900 flex-wrap text-md font-semibold mb-1 truncate">
{#if marked}
{@html marked}
{:else}
{!summary || summary.length == 0 ? path : summary}
{/if}
</div>
<div class="text-gray-600 text-xs ">
<div class="text-gray-600 text-xs truncate">
{path}
</div>
</div>
<div class="w-96 flex flex-row max-w-xs gap-1 items-start flex-wrap">
<div class="w-96 hidden lg:flex flex-row max-w-xs gap-1 items-start flex-wrap">
<slot name="badges" />
</div>
@@ -73,7 +73,55 @@
</svelte:fragment>
<svelte:fragment slot="actions">
<span class="hidden md:inline-flex gap-x-1">
{#if canWrite}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faEdit }}
href="/scripts/edit/{hash}?step=2"
>
Edit
</Button>
</div>
{:else}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faCodeFork }}
href="/scripts/add?template={path}"
>
Fork
</Button>
</div>
{/if}
<Button
href="/scripts/get/{hash}"
color="light"
variant="border"
size="xs"
spacingSize="md"
startIcon={{ icon: faEye }}
>
Detail
</Button>
<Button
href="/scripts/run/{hash}"
color="dark"
size="xs"
spacingSize="md"
endIcon={{ icon: faPlay }}
>
Run
</Button>
</span>
<Dropdown
placement="bottom-end"
dropdownItems={[
{
displayName: 'View script',
@@ -126,51 +174,5 @@
}
]}
/>
{#if canWrite}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faEdit }}
href="/scripts/edit/{hash}?step=2"
>
Edit
</Button>
</div>
{:else}
<div>
<Button
color="light"
size="xs"
variant="border"
startIcon={{ icon: faCodeFork }}
href="/scripts/add?template={path}"
>
Fork
</Button>
</div>
{/if}
<Button
href="/scripts/get/{hash}"
color="light"
variant="border"
size="xs"
spacingSize="md"
startIcon={{ icon: faEye }}
>
Detail
</Button>
<Button
href="/scripts/run/{hash}"
color="dark"
size="xs"
spacingSize="md"
endIcon={{ icon: faPlay }}
>
Run
</Button>
</svelte:fragment>
</Row>
+1 -1
View File
@@ -38,7 +38,7 @@ export const userWorkspaces: Readable<
([store, superadmin]) => {
const originalWorkspaces = (store?.workspaces ?? []);
if (superadmin) {
return [...originalWorkspaces, {
return [...originalWorkspaces.filter((x) => x.id != 'starter' && x.id != 'admins'), {
id: "admins",
name: "Admins",
username: "superadmin",
@@ -23,7 +23,7 @@
})
usersWorkspaceStore.set(await WorkspaceService.listUserWorkspaces())
workspaceStore.set(workspace_id)
goto($page.url.searchParams.get('rd') ?? '/scripts')
goto($page.url.searchParams.get('rd') ?? '/')
}
async function validateName(username: string): Promise<void> {
@@ -4,16 +4,16 @@
import { sendUserToast, validateUsername } from '$lib/utils'
import { logoutWithRedirect } from '$lib/logout'
import { page } from '$app/stores'
import { usersWorkspaceStore, workspaceStore } from '$lib/stores'
import { userStore, usersWorkspaceStore, workspaceStore } from '$lib/stores'
import CenteredModal from '$lib/components/CenteredModal.svelte'
import { Button } from '$lib/components/common'
import Toggle from '$lib/components/Toggle.svelte'
const rd = $page.url.searchParams.get('rd')
let id = ''
let name = ''
let username = ''
let domain = ''
let errorId = ''
let errorUser = ''
@@ -39,11 +39,17 @@
requestBody: {
id,
name,
username,
domain
username
}
})
if (auto_invite) {
await WorkspaceService.editAutoInvite({
workspace: id,
requestBody: { set: true }
})
}
sendUserToast(`Successfully created workspace id: ${id}`)
usersWorkspaceStore.set(await WorkspaceService.listUserWorkspaces())
workspaceStore.set(id)
goto(rd ?? '/')
@@ -78,6 +84,16 @@
}
username = username.toLowerCase()
})
WorkspaceService.isDomainAllowed().then((x) => {
isDomainAllowed = x
})
let isDomainAllowed = false
$: domain = $usersWorkspaceStore?.email.split('@')[1]
let auto_invite = false
</script>
<CenteredModal title="New Workspace">
@@ -99,6 +115,14 @@
{/if}
<input type="text" bind:value={username} on:keyup={handleKeyUp} class="mt-1" />
</label>
<Toggle
disabled={!isDomainAllowed}
bind:checked={auto_invite}
options={{ right: `Auto invite users with the same domain (${domain})` }}
/>
{#if !isDomainAllowed}
<div class="text-gray-600 text-sm mb-4 mt-2">{domain} domain not allowed for auto-invite</div>
{/if}
<div class="flex flex-row justify-between pt-4 gap-x-1">
<Button variant="border" size="sm" href="/user/workspaces"
>&leftarrow; Back to workspaces</Button
+49 -5
View File
@@ -24,7 +24,7 @@
import { goto } from '$app/navigation'
import InviteUser from '$lib/components/InviteUser.svelte'
import ScriptPicker from '$lib/components/ScriptPicker.svelte'
import { Button, Skeleton } from '$lib/components/common'
import { Badge, Button, Skeleton } from '$lib/components/common'
import Tooltip from '$lib/components/Tooltip.svelte'
import { faScroll, faBarsStaggered } from '@fortawesome/free-solid-svg-icons'
import SearchItems from '$lib/components/SearchItems.svelte'
@@ -36,6 +36,7 @@
let scriptPath: string
let initialPath: string
let team_name: string | undefined
let auto_invite_domain: string | undefined
let itemKind: 'flow' | 'script' = 'flow'
// function getDropDownItems(username: string): DropdownItem[] {
@@ -71,9 +72,10 @@
sendUserToast(`slack command script set to ${scriptPath}`)
}
async function loadSlack(): Promise<void> {
async function loadSettings(): Promise<void> {
const settings = await WorkspaceService.getSettings({ workspace: $workspaceStore! })
team_name = settings.slack_name
auto_invite_domain = settings.auto_invite_domain
scriptPath = (settings.slack_command_script ?? '').split('/').slice(1).join('/')
initialPath = scriptPath
}
@@ -86,11 +88,20 @@
invites = await WorkspaceService.listPendingInvites({ workspace: $workspaceStore! })
}
let allowedAutoDomain = false
async function getDisallowedAutoDomain() {
allowedAutoDomain = await WorkspaceService.isDomainAllowed()
}
$: domain = $userStore?.email.split('@')[1]
$: {
if ($workspaceStore) {
getDisallowedAutoDomain()
listUsers()
listInvites()
loadSlack()
loadSettings()
}
}
</script>
@@ -210,9 +221,42 @@
</TableCustom>
</div>
<div class="mt-20" />
<PageHeader title="Auto Invite" primary={false} />
<div class="flex gap-2">
{#if auto_invite_domain != domain}
<Button
disabled={!allowedAutoDomain}
on:click={async () => {
await WorkspaceService.editAutoInvite({
workspace: $workspaceStore ?? '',
requestBody: { set: true }
})
loadSettings()
listInvites()
}}>Set auto-invite to {domain}</Button
>
{/if}
{#if auto_invite_domain}
<Button
on:click={async () => {
await WorkspaceService.editAutoInvite({
workspace: $workspaceStore ?? '',
requestBody: { set: false }
})
loadSettings()
listInvites()
}}>Unset auto-invite from {auto_invite_domain}</Button
>
{/if}
</div>
{#if !allowedAutoDomain}
<div class="text-red-400 text-sm mb-2">{domain} domain not allowed for auto-invite</div>
{/if}
<div class="mt-20" />
<PageHeader title="Slack integration" primary={false} />
<p class="text-xs text-gray-700 my-1">
Status: {#if team_name}Connected to slack workspace {team_name}{:else}Not connected{/if}
Status: {#if team_name}Connected to slack workspace <Badge>{team_name}</Badge>{:else}Not
connected{/if}
</p>
{#if team_name}
@@ -226,7 +270,7 @@
await OauthService.disconnectSlack({
workspace: $workspaceStore ?? ''
})
loadSlack()
loadSettings()
sendUserToast('Disconnected Slack')
}}
>