Skip to content

Commit 23d66fb

Browse files
committed
feat: add guest auth prompt component
Signed-off-by: skjnldsv <[email protected]>
1 parent 5751d7c commit 23d66fb

File tree

6 files changed

+278
-0
lines changed

6 files changed

+278
-0
lines changed

l10n/messages.pot

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ msgstr ""
1414
msgid "All files"
1515
msgstr ""
1616

17+
msgid "Cancel"
18+
msgstr ""
19+
1720
msgid "Choose"
1821
msgstr ""
1922

@@ -46,6 +49,12 @@ msgstr ""
4649
msgid "Current view selector"
4750
msgstr ""
4851

52+
msgid "Enter your name"
53+
msgstr ""
54+
55+
msgid "Failed to set nickname."
56+
msgstr ""
57+
4958
msgid "Favorites"
5059
msgstr ""
5160

@@ -61,6 +70,9 @@ msgstr ""
6170
msgid "Folder name cannot be empty."
6271
msgstr ""
6372

73+
msgid "Guest identification"
74+
msgstr ""
75+
6476
msgid "Home"
6577
msgstr ""
6678

@@ -94,6 +106,9 @@ msgstr ""
94106
msgid "No matching files"
95107
msgstr ""
96108

109+
msgid "Please enter a name with at least 2 characters."
110+
msgstr ""
111+
97112
msgid "Recent"
98113
msgstr ""
99114

@@ -109,8 +124,17 @@ msgstr ""
109124
msgid "Size"
110125
msgstr ""
111126

127+
msgid "Submit name"
128+
msgstr ""
129+
112130
msgid "Undo"
113131
msgstr ""
114132

115133
msgid "Upload some content or sync with your devices!"
116134
msgstr ""
135+
136+
msgid "You are currently not identified."
137+
msgstr ""
138+
139+
msgid "You cannot leave the name empty."
140+
msgstr ""
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3+
- SPDX-License-Identifier: AGPL-3.0-or-later
4+
-->
5+
6+
<template>
7+
<NcDialog :buttons="dialogButtons"
8+
class="public-auth-prompt"
9+
data-cy-public-auth-prompt-dialog
10+
is-form
11+
no-close
12+
:name="title"
13+
@submit="onSubmit">
14+
<p v-if="text" class="public-auth-prompt__text">
15+
{{ text }}
16+
</p>
17+
18+
<!-- Header -->
19+
<NcNoteCard class="public-auth-prompt__header"
20+
:text="notice"
21+
type="info" />
22+
23+
<!-- Form -->
24+
<NcTextField ref="input"
25+
class="public-auth-prompt__input"
26+
data-cy-public-auth-prompt-dialog-name
27+
:label="t('Name')"
28+
:placeholder="t('Enter your name')"
29+
:required="!cancellable"
30+
v-model="name"
31+
minlength="2"
32+
name="name" />
33+
</NcDialog>
34+
</template>
35+
36+
<script lang="ts">
37+
import { defineComponent } from 'vue'
38+
import { getBuilder } from '@nextcloud/browser-storage'
39+
import { setGuestNickname } from '@nextcloud/auth'
40+
import { showError } from '@nextcloud/dialogs'
41+
42+
import NcButton from '@nextcloud/vue/components/NcButton'
43+
import NcDialog from '@nextcloud/vue/components/NcDialog'
44+
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
45+
import NcTextField from '@nextcloud/vue/components/NcTextField'
46+
47+
import { t } from '../utils/l10n.ts'
48+
49+
const storage = getBuilder('public').build()
50+
51+
export default defineComponent({
52+
name: 'PublicAuthPrompt',
53+
54+
components: {
55+
NcDialog,
56+
NcNoteCard,
57+
NcTextField,
58+
},
59+
60+
props: {
61+
/**
62+
* Preselected nickname
63+
* @default '' No name preselected by default
64+
*/
65+
nickname: {
66+
type: String,
67+
default: '',
68+
},
69+
70+
/**
71+
* Dialog title
72+
*/
73+
title: {
74+
type: String,
75+
default: t('Guest identification'),
76+
},
77+
78+
/**
79+
* Dialog text under the dialog title
80+
* e.g 'Enter your name to access the file'
81+
* @default '' Not shown by default
82+
*/
83+
text: {
84+
type: String,
85+
default: '',
86+
},
87+
88+
/**
89+
* Dialog notice
90+
* @default 'You are currently not identified.'
91+
*/
92+
notice: {
93+
type: String,
94+
default: t('You are currently not identified.'),
95+
},
96+
97+
/**
98+
* Dialog submit button label
99+
* @default 'Submit name'
100+
*/
101+
submitLabel: {
102+
type: String,
103+
default: t('Submit name'),
104+
},
105+
106+
/**
107+
* Whether the dialog is cancellable
108+
* @default false
109+
*/
110+
cancellable: {
111+
type: Boolean,
112+
default: false,
113+
},
114+
},
115+
116+
setup() {
117+
return {
118+
t,
119+
}
120+
},
121+
122+
data() {
123+
return {
124+
name: '',
125+
}
126+
},
127+
128+
computed: {
129+
dialogButtons() {
130+
const cancelButton = {
131+
label: t('Cancel'),
132+
variant: 'tertiary',
133+
callback: () => this.$emit('close'),
134+
}
135+
136+
const submitButton = {
137+
label: this.submitLabel,
138+
type: 'submit',
139+
variant: 'primary',
140+
}
141+
142+
// If the dialog is cancellable, add a cancel button
143+
if (this.cancellable) {
144+
return [cancelButton, submitButton]
145+
}
146+
147+
return [submitButton]
148+
},
149+
},
150+
151+
watch: {
152+
/** Reset name to pre-selected nickname (e.g. Talk / Collabora ) */
153+
nickname: {
154+
handler() {
155+
this.name = this.nickname
156+
},
157+
immediate: true,
158+
},
159+
},
160+
161+
methods: {
162+
onSubmit() {
163+
const input = this.$refs.input as HTMLInputElement
164+
const nickname = this.name.trim()
165+
166+
if (nickname === '') {
167+
// Show error if the nickname is empty
168+
input.setCustomValidity(t('You cannot leave the name empty.'))
169+
input.reportValidity()
170+
input.focus()
171+
return
172+
}
173+
174+
if (nickname.length < 2) {
175+
// Show error if the nickname is too short
176+
input.setCustomValidity(t('Please enter a name with at least 2 characters.'))
177+
input.reportValidity()
178+
input.focus()
179+
return
180+
}
181+
182+
try {
183+
// Set the nickname
184+
setGuestNickname(nickname)
185+
} catch (e) {
186+
showError(t('Failed to set nickname.'))
187+
console.error('Failed to set nickname', e)
188+
input.focus()
189+
return
190+
}
191+
192+
// Set the dialog as shown
193+
storage.setItem('public-auth-prompt-shown', 'true')
194+
195+
// Close the dialog
196+
this.$emit('close', this.name)
197+
},
198+
},
199+
})
200+
</script>
201+
<style scoped lang="scss">
202+
.public-auth-prompt {
203+
&__text {
204+
// Smaller than dialog title
205+
font-size: 1.25em;
206+
margin-block: 0 calc(3 * var(--default-grid-baseline));
207+
}
208+
209+
&__header {
210+
margin-block: 0 calc(3 * var(--default-grid-baseline));
211+
// No extra top margin for the first child
212+
&:first-child {
213+
margin-top: 0;
214+
}
215+
}
216+
217+
&__input {
218+
margin-block: calc(4 * var(--default-grid-baseline)) calc(2 * var(--default-grid-baseline));
219+
}
220+
}
221+
</style>

lib/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,6 @@ export type {
4747
IFilePickerButton,
4848
IFilePickerFilter,
4949
} from './components/types.ts'
50+
51+
export { showGuestUserPrompt } from './public-auth.js'
52+

lib/public-auth.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import type { ComponentProps } from 'vue-component-type-helpers'
7+
import { defineAsyncComponent } from 'vue'
8+
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
9+
10+
import type PublicAuthPrompt from './components/PublicAuthPrompt.vue'
11+
12+
type PublicAuthPromptProps = ComponentProps<typeof PublicAuthPrompt>
13+
14+
/**
15+
* Show the public auth prompt dialog
16+
* This is used to ask the current user their nickname
17+
* as well as show some additional contextual information
18+
* @param props The props to pass to the dialog, see PublicAuthPrompt.vue for details
19+
*/
20+
export function showGuestUserPrompt(props: PublicAuthPromptProps) {
21+
return new Promise((resolve) => {
22+
spawnDialog(
23+
defineAsyncComponent(() => import('./components/PublicAuthPrompt.vue')),
24+
props,
25+
resolve,
26+
)
27+
})
28+
}

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
"typescript-plugin-css-modules": "^5.1.0",
8585
"vite": "^6.3.3",
8686
"vitest": "^3.1.2",
87+
"vue-component-type-helpers": "^2.2.10",
8788
"vue-material-design-icons": "^5.3.1"
8889
},
8990
"engines": {

0 commit comments

Comments
 (0)