Skip to content

Commit 11732c7

Browse files
authored
Merge pull request #1760 from nextcloud-libraries/backport/1759/main
feat: add guest auth prompt
2 parents 961a4d0 + 4453fd2 commit 11732c7

File tree

6 files changed

+235
-1
lines changed

6 files changed

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

lib/public-auth.ts

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

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
@@ -43,6 +43,7 @@
4343
"@mdi/js": "^7.4.47",
4444
"@nextcloud/auth": "^2.4.0",
4545
"@nextcloud/axios": "^2.5.1",
46+
"@nextcloud/browser-storage": "^0.4.0",
4647
"@nextcloud/event-bus": "^3.3.2",
4748
"@nextcloud/files": "^3.10.2",
4849
"@nextcloud/initial-state": "^2.2.0",

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
{
22
"extends": "@vue/tsconfig",
33
"compilerOptions": {
4+
"allowImportingTsExtensions": true,
45
"declaration": true,
56
"esModuleInterop": true,
67
"lib": ["DOM", "ESNext"],
78
"outDir": "./dist",
89
"rootDir": "lib/",
910
"module": "ESNext",
10-
"moduleResolution": "Bundler",
11+
"moduleResolution": "bundler",
1112
"target": "ESNext",
1213
"plugins": [
1314
{ "name": "typescript-plugin-css-modules" }

0 commit comments

Comments
 (0)