@reqquest/ui 1.17.0 → 1.19.0
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/app/env.template +5 -0
- package/app/runtime/apply-env.sh +10 -0
- package/app/runtime/nginx.conf +37 -0
- package/app/src/app.css +21 -0
- package/app/src/app.d.ts +13 -0
- package/app/src/app.html +12 -0
- package/app/src/internal/api.ts +1707 -0
- package/app/src/internal/appreq-utils.ts +33 -0
- package/app/src/internal/components/AnnouncementBanner.svelte +47 -0
- package/app/src/internal/components/AppRequestCard.svelte +173 -0
- package/app/src/internal/components/ApplicantOptOutModal.svelte +78 -0
- package/app/src/internal/components/ApplicantProgramList.svelte +276 -0
- package/app/src/internal/components/ApplicantProgramListTooltip.svelte +44 -0
- package/app/src/internal/components/ApplicantPromptPage.svelte +136 -0
- package/app/src/internal/components/ApplicantPromptSkeleton.svelte +12 -0
- package/app/src/internal/components/ApplicationDetailsView.svelte +369 -0
- package/app/src/internal/components/ButtonLoadingIcon.svelte +28 -0
- package/{dist → app/src/internal}/components/DelayedSkeleton.svelte +2 -2
- package/app/src/internal/components/FieldNestedMultiselect.svelte +270 -0
- package/app/src/internal/components/IntroPanel.svelte +41 -0
- package/app/src/internal/components/MissingDefinitionNotification.svelte +20 -0
- package/app/src/internal/components/PeriodPanel.svelte +125 -0
- package/app/src/internal/components/ProgramStatusCell.svelte +134 -0
- package/app/src/internal/components/RenderDisplayComponent.svelte +42 -0
- package/app/src/internal/components/ReviewerActions.svelte +171 -0
- package/app/src/internal/components/ReviewerQuestions.svelte +508 -0
- package/app/src/internal/components/StatusMessageList.svelte +54 -0
- package/app/src/internal/components/SystemDeterminationNotice.svelte +37 -0
- package/app/src/internal/components/TabLinks.svelte +265 -0
- package/app/src/internal/components/WarningIconYellow.svelte +22 -0
- package/app/src/internal/components/index.ts +19 -0
- package/app/src/internal/csv.ts +30 -0
- package/app/src/internal/index.ts +8 -0
- package/app/src/internal/prompt-save-queue.ts +91 -0
- package/app/src/internal/prompt-utils.ts +40 -0
- package/app/src/internal/status-utils.ts +503 -0
- package/app/src/internal/stores/IStateStore.ts +5 -0
- package/app/src/internal/util.ts +27 -0
- package/app/src/routes/+error.svelte +4 -0
- package/app/src/routes/+layout.svelte +134 -0
- package/app/src/routes/+layout.ts +18 -0
- package/app/src/routes/+page.ts +14 -0
- package/app/src/routes/announcement/+page.svelte +164 -0
- package/app/src/routes/announcement/+page.ts +16 -0
- package/app/src/routes/dashboards/applicant/+page.svelte +494 -0
- package/app/src/routes/dashboards/applicant/+page.ts +95 -0
- package/app/src/routes/dashboards/reviewer/+page.svelte +143 -0
- package/app/src/routes/dashboards/reviewer/+page.ts +43 -0
- package/app/src/routes/periods/+page.svelte +158 -0
- package/app/src/routes/periods/+page.ts +13 -0
- package/app/src/routes/periods/[id]/configure/+page.svelte +150 -0
- package/app/src/routes/periods/[id]/configure/+page.ts +10 -0
- package/app/src/routes/requests/+page.svelte +246 -0
- package/app/src/routes/requests/+page.ts +24 -0
- package/app/src/routes/requests/[id]/+layout.ts +11 -0
- package/app/src/routes/requests/[id]/accept/+layout.svelte +80 -0
- package/app/src/routes/requests/[id]/accept/+layout.ts +12 -0
- package/app/src/routes/requests/[id]/accept/+page.ts +13 -0
- package/app/src/routes/requests/[id]/accept/[promptId]/+page.svelte +7 -0
- package/app/src/routes/requests/[id]/accept/[promptId]/+page.ts +10 -0
- package/app/src/routes/requests/[id]/accept/review/+page.svelte +87 -0
- package/app/src/routes/requests/[id]/apply/+layout.svelte +181 -0
- package/app/src/routes/requests/[id]/apply/+layout.ts +12 -0
- package/app/src/routes/requests/[id]/apply/+page.ts +14 -0
- package/app/src/routes/requests/[id]/apply/ProgressNavContainer.svelte +42 -0
- package/app/src/routes/requests/[id]/apply/[promptId]/+page.svelte +23 -0
- package/app/src/routes/requests/[id]/apply/[promptId]/+page.ts +11 -0
- package/app/src/routes/requests/[id]/apply/programs/+page.svelte +71 -0
- package/app/src/routes/requests/[id]/apply/review/+page.svelte +102 -0
- package/app/src/routes/requests/[id]/approve/+layout.svelte +114 -0
- package/app/src/routes/requests/[id]/approve/+page.ts +14 -0
- package/app/src/routes/requests/[id]/approve/ApproveLayout.svelte +164 -0
- package/app/src/routes/requests/[id]/approve/[programKey]/+page.svelte +396 -0
- package/app/src/routes/requests/[id]/approve/[programKey]/+page.ts +15 -0
- package/app/src/routes/requests/[id]/approve/activity/+page.svelte +66 -0
- package/app/src/routes/requests/[id]/approve/activity/+page.ts +12 -0
- package/app/src/routes/requests/[id]/approve/export/+page.ts +12 -0
- package/app/src/routes/requests/[id]/approve/export/+page@[id].svelte +41 -0
- package/app/src/routes/requests/[id]/export/+page.svelte +32 -0
- package/app/src/routes/requests/[id]/export/+page.ts +12 -0
- package/app/src/routes/roles/+layout.svelte +16 -0
- package/app/src/routes/roles/+layout.ts +14 -0
- package/app/src/routes/roles/+page.svelte +225 -0
- package/app/src/routes/roles/+page.ts +13 -0
- package/app/src/routes/roles/[id]/+layout.ts +10 -0
- package/app/src/routes/roles/[id]/+page.svelte +335 -0
- package/app/src/routes/roles/[id]/+page.ts +10 -0
- package/app/src/routes/roles/[id]/ControlWithTooltip.svelte +15 -0
- package/app/src/routes/roles/[id]/TagsWithTooltip.svelte +42 -0
- package/app/src/routes/roles/users/+layout.ts +13 -0
- package/app/src/routes/roles/users/+page.svelte +46 -0
- package/app/src/routes/roles/users/+page.ts +90 -0
- package/app/static/favicon.png +0 -0
- package/bin/reqquest-ui.js +117 -0
- package/cli/config.js +105 -0
- package/cli/sync.js +296 -0
- package/cli/util.js +29 -0
- package/dist/components.md +5 -4
- package/dist/registry.d.ts +17 -0
- package/dist/registry.js +3 -0
- package/package.json +29 -15
- package/dist/components/DelayedSkeleton.svelte.d.ts +0 -21
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ApplicationDetailsView } from '$internal'
|
|
3
|
+
import { uiRegistry } from '$local'
|
|
4
|
+
import type { PageData } from './$types'
|
|
5
|
+
|
|
6
|
+
export let data: PageData
|
|
7
|
+
$: ({ appRequest, appData, prequalPrompts, postqualPrompts, applicationsReview, basicRequestData } = data)
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
{#if appRequest}
|
|
11
|
+
|
|
12
|
+
<div class="export-content max-w-4xl">
|
|
13
|
+
<ApplicationDetailsView
|
|
14
|
+
{appRequest}
|
|
15
|
+
applications={applicationsReview}
|
|
16
|
+
{appData}
|
|
17
|
+
{prequalPrompts}
|
|
18
|
+
{postqualPrompts}
|
|
19
|
+
loading={false}
|
|
20
|
+
{uiRegistry}
|
|
21
|
+
expandable={false}
|
|
22
|
+
printMode
|
|
23
|
+
showWarningsInline={true}
|
|
24
|
+
title={`View ${basicRequestData.applicant.fullname} ${uiRegistry.getWord('appRequest').toLowerCase()}`}
|
|
25
|
+
subtitle={`Complete ${uiRegistry.getWord('appRequest').toLowerCase()} details for review.`}
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
{:else}
|
|
30
|
+
<div class="error">
|
|
31
|
+
<h1>{uiRegistry.getWord('appRequest')} Not Found</h1>
|
|
32
|
+
<p>The requested {uiRegistry.getWord('appRequest').toLowerCase()} could not be loaded.</p>
|
|
33
|
+
</div>
|
|
34
|
+
{/if}
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
/* Reviewer standard: prompt/requirement column 40%, answer column 60%. */
|
|
38
|
+
.export-content {
|
|
39
|
+
--prompt-list-columns: minmax(0, 2fr) minmax(0, 3fr);
|
|
40
|
+
}
|
|
41
|
+
</style>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ApplicationDetailsView } from '$internal'
|
|
3
|
+
import { uiRegistry } from '$local'
|
|
4
|
+
import type { PageData } from './$types'
|
|
5
|
+
|
|
6
|
+
export let data: PageData
|
|
7
|
+
$: ({ appRequest, appData, prequalPrompts, postqualPrompts, applicationsReview } = data)
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
{#if appRequest}
|
|
11
|
+
|
|
12
|
+
<div class="max-w-4xl">
|
|
13
|
+
<ApplicationDetailsView
|
|
14
|
+
{appRequest}
|
|
15
|
+
applications={applicationsReview}
|
|
16
|
+
{appData}
|
|
17
|
+
{prequalPrompts}
|
|
18
|
+
{postqualPrompts}
|
|
19
|
+
loading={false}
|
|
20
|
+
{uiRegistry}
|
|
21
|
+
expandable={false}
|
|
22
|
+
printMode
|
|
23
|
+
showTooltipsAsText
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
{:else}
|
|
28
|
+
<div class="error">
|
|
29
|
+
<h1>Application Not Found</h1>
|
|
30
|
+
<p>The requested application could not be loaded.</p>
|
|
31
|
+
</div>
|
|
32
|
+
{/if}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { api } from '$internal'
|
|
2
|
+
import type { PageLoad } from './$types'
|
|
3
|
+
|
|
4
|
+
export const load: PageLoad = async ({ params, depends, parent }) => {
|
|
5
|
+
const details = await api.getAppRequestForExport(params.id)
|
|
6
|
+
|
|
7
|
+
depends('request:export')
|
|
8
|
+
return {
|
|
9
|
+
...details,
|
|
10
|
+
appData: details.appRequest.data
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { TabLinks } from '@txstate-mws/carbon-svelte'
|
|
3
|
+
import type { LayoutData } from './$types'
|
|
4
|
+
export let data: LayoutData
|
|
5
|
+
$: ({ showTabs } = data)
|
|
6
|
+
const tabs = [
|
|
7
|
+
{ label: 'Role Management', href: '/roles' },
|
|
8
|
+
{ label: 'Users', href: '/roles/users' }
|
|
9
|
+
]
|
|
10
|
+
</script>
|
|
11
|
+
<div class="flow">
|
|
12
|
+
{#if showTabs}
|
|
13
|
+
<TabLinks {tabs} />
|
|
14
|
+
{/if}
|
|
15
|
+
<slot />
|
|
16
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LayoutLoad } from './$types'
|
|
2
|
+
// import { api } from '$internal'
|
|
3
|
+
// import { unifiedAuth } from '@txstate-mws/sveltekit-utils'
|
|
4
|
+
|
|
5
|
+
export const load: LayoutLoad = async input => {
|
|
6
|
+
const lastPath = input.url.pathname.split('/').pop()
|
|
7
|
+
const showTabs = (lastPath === 'roles' || lastPath === 'users')
|
|
8
|
+
// api.fetch = input.fetch
|
|
9
|
+
// await unifiedAuth.handle(api, input)
|
|
10
|
+
// const access = await api.getAccess()
|
|
11
|
+
return { showTabs }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const ssr = false
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ActionSet, ColumnList, FieldMore, FieldTextArea, FieldTextInput, PanelFormDialog } from '@txstate-mws/carbon-svelte'
|
|
3
|
+
import { toasts } from '@txstate-mws/svelte-components'
|
|
4
|
+
import { Button, Modal } from 'carbon-components-svelte'
|
|
5
|
+
import Add from 'carbon-icons-svelte/lib/Add.svelte'
|
|
6
|
+
import SettingsEdit from 'carbon-icons-svelte/lib/SettingsEdit.svelte'
|
|
7
|
+
import { invalidate } from '$app/navigation'
|
|
8
|
+
import { api } from '$internal'
|
|
9
|
+
import type { AccessRoleInput } from '@reqquest/ui'
|
|
10
|
+
import Copy from 'carbon-icons-svelte/lib/Copy.svelte'
|
|
11
|
+
import TrashCan from 'carbon-icons-svelte/lib/TrashCan.svelte'
|
|
12
|
+
import View from 'carbon-icons-svelte/lib/View.svelte'
|
|
13
|
+
import type { DateTime } from 'luxon'
|
|
14
|
+
import { omit, pick } from 'txstate-utils'
|
|
15
|
+
import type { PageData } from './$types'
|
|
16
|
+
|
|
17
|
+
export let data: PageData
|
|
18
|
+
const rolenames = new Set<string>()
|
|
19
|
+
$: ({ roles, access } = data)
|
|
20
|
+
$: {
|
|
21
|
+
rolenames.clear()
|
|
22
|
+
for (const role of roles ?? []) rolenames.add(role.name)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Group updates to Roles accept only the group name and not a group object.
|
|
26
|
+
type AccessRoleUpdateForm = Omit<AccessRoleInput, 'groups'> & { groups: string[], id?: string }
|
|
27
|
+
function transformFromAPI (data: PageData['roles'][number]): AccessRoleUpdateForm {
|
|
28
|
+
return {
|
|
29
|
+
...pick(data, 'id', 'name', 'description'),
|
|
30
|
+
groups: data.groups.map(group => group.groupName)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let createDialog = false
|
|
35
|
+
let editingRole: AccessRoleUpdateForm | undefined
|
|
36
|
+
let isDuplicating = false
|
|
37
|
+
let duplicateSourceId: string | undefined // Source role ID when duplicating (to copy grants)
|
|
38
|
+
let duplicateSourceName: string | undefined // Source role name for success message
|
|
39
|
+
|
|
40
|
+
async function validate (role: AccessRoleUpdateForm) {
|
|
41
|
+
const response = await api.upsertRole(editingRole?.id, role, true, isDuplicating ? duplicateSourceId : undefined)
|
|
42
|
+
return response.messages
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function onSubmit (role: AccessRoleUpdateForm) {
|
|
46
|
+
const response = await api.upsertRole(editingRole?.id, role, false, isDuplicating ? duplicateSourceId : undefined)
|
|
47
|
+
return {
|
|
48
|
+
...response,
|
|
49
|
+
data: role
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function onSaved (event: CustomEvent<AccessRoleUpdateForm>) {
|
|
54
|
+
const roleName = event.detail.name
|
|
55
|
+
let title: string
|
|
56
|
+
let message: string
|
|
57
|
+
if (editingRole?.id) {
|
|
58
|
+
title = 'Role edited'
|
|
59
|
+
message = `The role ${roleName} was successfully edited.`
|
|
60
|
+
} else if (isDuplicating) {
|
|
61
|
+
title = 'Role duplicated'
|
|
62
|
+
message = `The role ${duplicateSourceName} was successfully duplicated as ${roleName}.`
|
|
63
|
+
} else {
|
|
64
|
+
title = 'New role created'
|
|
65
|
+
message = `The role ${roleName} was successfully created.`
|
|
66
|
+
}
|
|
67
|
+
toasts.add({ type: 'success', title, message })
|
|
68
|
+
closeDialog()
|
|
69
|
+
invalidate('api:getRoleList').catch(console.error)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function closeDialog () {
|
|
73
|
+
createDialog = false
|
|
74
|
+
editingRole = undefined
|
|
75
|
+
isDuplicating = false
|
|
76
|
+
duplicateSourceId = undefined
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let deleteDialog = false
|
|
80
|
+
let deleteDialogRole: PageData['roles'][number] | undefined
|
|
81
|
+
function openRoleDeleteDialog (role: PageData['roles'][number]) {
|
|
82
|
+
deleteDialog = true
|
|
83
|
+
deleteDialogRole = role
|
|
84
|
+
}
|
|
85
|
+
function closeRoleDeleteDialog () {
|
|
86
|
+
deleteDialog = false
|
|
87
|
+
deleteDialogRole = undefined
|
|
88
|
+
}
|
|
89
|
+
async function executeRoleDelete () {
|
|
90
|
+
try {
|
|
91
|
+
if (!deleteDialogRole) throw new Error('No role selected for deletion')
|
|
92
|
+
await api.deleteRole(deleteDialogRole.id)
|
|
93
|
+
toasts.add({
|
|
94
|
+
type: 'success',
|
|
95
|
+
title: 'Role deleted',
|
|
96
|
+
message: `The role ${deleteDialogRole.name} was successfully deleted.`
|
|
97
|
+
})
|
|
98
|
+
closeRoleDeleteDialog()
|
|
99
|
+
await invalidate('api:getRoleList')
|
|
100
|
+
} catch (e: any) {
|
|
101
|
+
closeRoleDeleteDialog()
|
|
102
|
+
console.error(e)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
</script>
|
|
106
|
+
|
|
107
|
+
<!-- maxRowActionButton={1} -->
|
|
108
|
+
<!-- title={role.name + '<br>' + role.description} -->
|
|
109
|
+
<ActionSet includeLabels actions={[
|
|
110
|
+
{
|
|
111
|
+
label: 'Create Role',
|
|
112
|
+
icon: Add,
|
|
113
|
+
disabled: !access.createRole,
|
|
114
|
+
onClick: () => {
|
|
115
|
+
createDialog = true
|
|
116
|
+
editingRole = undefined
|
|
117
|
+
isDuplicating = false
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
]}/>
|
|
121
|
+
|
|
122
|
+
{#each roles ?? [] as role, index (role.id)}
|
|
123
|
+
<div class="admin-settings">
|
|
124
|
+
<h2 class="text-lg">{role.name}</h2>
|
|
125
|
+
<p>{role.description}</p>
|
|
126
|
+
<div class="role-list">
|
|
127
|
+
<ColumnList
|
|
128
|
+
title={role.name}
|
|
129
|
+
listActionsMaxButtons={2}
|
|
130
|
+
listActionsIncludeLabels={false}
|
|
131
|
+
listActions={[
|
|
132
|
+
{ label: 'Edit', icon: SettingsEdit, onClick: () => {
|
|
133
|
+
createDialog = true
|
|
134
|
+
editingRole = transformFromAPI(role)
|
|
135
|
+
isDuplicating = false
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
{ label: 'View permissions', icon: View, href: `/roles/${role.id}` },
|
|
139
|
+
{ label: 'Duplicate role', icon: Copy, onClick: () => {
|
|
140
|
+
createDialog = true
|
|
141
|
+
isDuplicating = true
|
|
142
|
+
duplicateSourceId = role.id
|
|
143
|
+
duplicateSourceName = role.name
|
|
144
|
+
const duplicateRole = transformFromAPI(role)
|
|
145
|
+
let name = duplicateRole.name
|
|
146
|
+
while (rolenames.has(name)) {
|
|
147
|
+
const s = name.search(/[0-9]+$/g)
|
|
148
|
+
if (s !== -1) {
|
|
149
|
+
const count = parseInt(name.slice(s))
|
|
150
|
+
name = name.slice(0, s) + (count + 1).toString()
|
|
151
|
+
} else {
|
|
152
|
+
name = name + '-1'
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
editingRole = { ...omit(duplicateRole, 'name', 'id'), name }
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
{ label: 'Delete role', icon: TrashCan, onClick: () => openRoleDeleteDialog(role) }
|
|
159
|
+
]}
|
|
160
|
+
noItemsTitle='There are no groups associated with this Role'
|
|
161
|
+
noItemsSubtitle=''
|
|
162
|
+
columns={[
|
|
163
|
+
{ id: 'group', label: 'Group', get: 'groupName' },
|
|
164
|
+
{ id: 'manager', label: 'Manager', render: row => (row.managers.length > 0) ? row.managers[0].fullname + '<br/>' + row.managers[0].email : 'no manager information' },
|
|
165
|
+
{ id: 'added', label: 'Added Date', render: row => (row.dateAdded) ? (row.dateAdded as DateTime).toFormat('MM/dd/yyyy') : '--/--/----' }
|
|
166
|
+
]}
|
|
167
|
+
rows={role.groups.map(g => ({ ...g, id: g.roleId + g.groupName }))}/>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
{/each}
|
|
171
|
+
|
|
172
|
+
{#if createDialog}
|
|
173
|
+
<PanelFormDialog open title={editingRole?.id ? 'Edit role' : 'Create Role'} preload={editingRole ? pick(editingRole, 'name', 'description', 'groups') : undefined} submit={onSubmit} {validate} on:saved={onSaved} on:cancel={closeDialog} unsavedWarning >
|
|
174
|
+
<p class="panel-description [ text-sm ] ">You can grant or restrict access to various features and data after creating the role.</p>
|
|
175
|
+
<FieldTextInput path="name" labelText="Role Name" required notNull />
|
|
176
|
+
<FieldTextArea path="description" labelText="Description" helperText="This will help other admins understand what the role does." />
|
|
177
|
+
<FieldMore path="groups" legendText="Groups" required>
|
|
178
|
+
<FieldTextInput path="" labelText="Group Name" placeholder="Enter group name"/>
|
|
179
|
+
</FieldMore>
|
|
180
|
+
<svelte:fragment slot="afterform">
|
|
181
|
+
{#if editingRole?.id && !isDuplicating}
|
|
182
|
+
<div class="[ -mt-8 ]">
|
|
183
|
+
<Button kind="secondary" icon={Add} href="/roles/{editingRole.id}">
|
|
184
|
+
Edit permissions
|
|
185
|
+
</Button>
|
|
186
|
+
</div>
|
|
187
|
+
{/if}
|
|
188
|
+
</svelte:fragment>
|
|
189
|
+
</PanelFormDialog>
|
|
190
|
+
{/if}
|
|
191
|
+
<Modal
|
|
192
|
+
bind:open={deleteDialog}
|
|
193
|
+
modalHeading="Delete Role"
|
|
194
|
+
primaryButtonText="Delete"
|
|
195
|
+
secondaryButtonText="Cancel"
|
|
196
|
+
danger
|
|
197
|
+
size="sm"
|
|
198
|
+
on:click:button--secondary={closeRoleDeleteDialog}
|
|
199
|
+
on:submit={executeRoleDelete}>
|
|
200
|
+
<p>Are you sure you want to delete the role {deleteDialogRole?.name}?</p>
|
|
201
|
+
<p>This action cannot be undone.</p>
|
|
202
|
+
</Modal>
|
|
203
|
+
|
|
204
|
+
<style>
|
|
205
|
+
:global(div.admin-settings) {
|
|
206
|
+
margin: 0 0 20px 0;
|
|
207
|
+
background: var(--cds-layer);
|
|
208
|
+
}
|
|
209
|
+
:global(div.admin-settings h2) {
|
|
210
|
+
padding: 8px 8px 0 8px;
|
|
211
|
+
}
|
|
212
|
+
:global(div.admin-settings p) {
|
|
213
|
+
padding: 0 8px 8px 8px;
|
|
214
|
+
line-height: calc(2rem - 10px);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.panel-description {
|
|
218
|
+
margin-bottom: 1rem;
|
|
219
|
+
color: var(--cds-text-01);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.role-list :global(.column-list-head) {
|
|
223
|
+
background: var(--cds-ui-03);
|
|
224
|
+
}
|
|
225
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { api } from '$internal'
|
|
2
|
+
import { error } from '@sveltejs/kit'
|
|
3
|
+
import type { PageLoad } from './$types'
|
|
4
|
+
|
|
5
|
+
export const load: PageLoad = async ({ url, depends, parent }) => {
|
|
6
|
+
const { access } = await parent()
|
|
7
|
+
// access is missing only when the layout failed; it renders layoutError in place of the page, so don't mask it
|
|
8
|
+
if (!access) return {} as never
|
|
9
|
+
if (!access.viewRoleManagement) throw error(403)
|
|
10
|
+
const roles = (await api.getRoleList()) ?? []
|
|
11
|
+
depends('api:getRoleList')
|
|
12
|
+
return { roles, access }
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { api } from '$internal'
|
|
2
|
+
import { keyby } from 'txstate-utils'
|
|
3
|
+
import type { LayoutLoad } from './$types'
|
|
4
|
+
|
|
5
|
+
export const load: LayoutLoad = async ({ depends }) => {
|
|
6
|
+
const controlGroups = await api.getAuthorizationInfo()
|
|
7
|
+
const controlGroupLookup = keyby(controlGroups, 'name')
|
|
8
|
+
depends('api:getAuthorizationInfo')
|
|
9
|
+
return { controlGroups, controlGroupLookup }
|
|
10
|
+
}
|