@plutocms/supabase 0.9.0 → 0.10.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/.prettierignore +2 -0
- package/CHANGELOG.md +15 -0
- package/FEATURES.md +6 -0
- package/app/components/EnvPersistWarning.vue +30 -13
- package/app/components/SupabaseMessageParts.vue +29 -0
- package/app/components/migrations/MigrationsBanner.vue +3 -4
- package/app/components/navbar/NavbarAdmin.vue +15 -9
- package/app/components/settings/SettingsGeneralPanel.vue +21 -6
- package/app/composables/auth.ts +17 -14
- package/app/pages/admin/(auth)/confirm.vue +6 -5
- package/app/pages/admin/(auth)/forgot-password.vue +15 -11
- package/app/pages/admin/(auth)/login.vue +10 -8
- package/app/pages/admin/(auth)/signup.vue +30 -22
- package/app/pages/admin/(auth)/update-password.vue +15 -12
- package/app/pages/admin/migrations.vue +87 -51
- package/app/pages/admin/setup.vue +88 -74
- package/app/pages/admin.vue +3 -2
- package/app/plugins/pluto-extension.ts +24 -3
- package/app/plugins/pluto-locale-sync.client.ts +30 -0
- package/app/utils/auth-error.ts +53 -0
- package/db/migrations/005_profile_locale.sql +44 -0
- package/i18n/locales/en.json +209 -0
- package/i18n/locales/pt-BR.json +209 -0
- package/package.json +3 -3
- package/server/api/profile/locale.get.ts +39 -0
- package/server/api/profile/locale.post.ts +71 -0
- package/server/api/setup/create.post.ts +6 -4
- package/server/api/users/[id].get.ts +4 -2
- package/server/api/users/index.get.ts +4 -2
- package/server/utils/admin-guard.ts +10 -2
- package/server/utils/capability-guard.ts +18 -4
- package/server/utils/content-adapter.ts +6 -4
- package/server/utils/pending-migrations.ts +0 -0
- package/server/utils/validate.ts +6 -1
- package/shared/types/supabase.ts +7 -0
|
@@ -3,8 +3,11 @@ definePageMeta({
|
|
|
3
3
|
layout: 'auth',
|
|
4
4
|
})
|
|
5
5
|
|
|
6
|
+
const { t } = usePlutoI18n()
|
|
7
|
+
const errorText = usePlutoErrorText()
|
|
8
|
+
|
|
6
9
|
useHead({
|
|
7
|
-
title:
|
|
10
|
+
title: () => t('supabase.auth.signup.pageTitle'),
|
|
8
11
|
})
|
|
9
12
|
|
|
10
13
|
const toast = useToast()
|
|
@@ -44,8 +47,8 @@ async function submitForm() {
|
|
|
44
47
|
})
|
|
45
48
|
|
|
46
49
|
toast.add({
|
|
47
|
-
title: '
|
|
48
|
-
description: '
|
|
50
|
+
title: t('supabase.auth.signup.created'),
|
|
51
|
+
description: t('supabase.auth.signup.createdDescription'),
|
|
49
52
|
icon: 'lucide:check',
|
|
50
53
|
color: 'success',
|
|
51
54
|
})
|
|
@@ -55,9 +58,8 @@ async function submitForm() {
|
|
|
55
58
|
console.error('Error signing up:', error)
|
|
56
59
|
|
|
57
60
|
toast.add({
|
|
58
|
-
title: '
|
|
59
|
-
description:
|
|
60
|
-
error instanceof Error ? error.message : 'An unknown error occurred.',
|
|
61
|
+
title: t('supabase.auth.signup.failed'),
|
|
62
|
+
description: errorText(error, 'supabase.auth.errors.unknown'),
|
|
61
63
|
icon: 'lucide:circle-x',
|
|
62
64
|
color: 'error',
|
|
63
65
|
})
|
|
@@ -77,18 +79,16 @@ async function submitForm() {
|
|
|
77
79
|
<UIcon name="lucide:mail-warning" class="inline-block" />
|
|
78
80
|
</span>
|
|
79
81
|
|
|
80
|
-
<h1 class="text-3xl font-bold">
|
|
82
|
+
<h1 class="text-3xl font-bold">{{ t('supabase.auth.signup.almostThere') }}</h1>
|
|
81
83
|
</hgroup>
|
|
82
84
|
|
|
83
85
|
<p>
|
|
84
|
-
|
|
85
|
-
inbox and follow the instructions to verify your account.
|
|
86
|
+
{{ t('supabase.auth.signup.verificationSent') }}
|
|
86
87
|
</p>
|
|
87
88
|
|
|
88
89
|
<UAlert icon="lucide:check" color="success" variant="outline">
|
|
89
90
|
<template #description>
|
|
90
|
-
|
|
91
|
-
you verify your email.
|
|
91
|
+
{{ t('supabase.auth.signup.closePage') }}
|
|
92
92
|
</template>
|
|
93
93
|
</UAlert>
|
|
94
94
|
|
|
@@ -98,7 +98,7 @@ async function submitForm() {
|
|
|
98
98
|
variant="outline"
|
|
99
99
|
>
|
|
100
100
|
<template #description>
|
|
101
|
-
|
|
101
|
+
{{ t('supabase.auth.signup.checkSpam') }}
|
|
102
102
|
</template>
|
|
103
103
|
</UAlert>
|
|
104
104
|
</div>
|
|
@@ -106,9 +106,9 @@ async function submitForm() {
|
|
|
106
106
|
|
|
107
107
|
<form v-else @submit.prevent="submitForm">
|
|
108
108
|
<div class="flex flex-col gap-y-6">
|
|
109
|
-
<h1 class="text-3xl font-bold">
|
|
109
|
+
<h1 class="text-3xl font-bold">{{ t('supabase.auth.signup.title') }}</h1>
|
|
110
110
|
|
|
111
|
-
<UFormField label="
|
|
111
|
+
<UFormField :label="t('supabase.auth.fields.email')" required>
|
|
112
112
|
<UInput
|
|
113
113
|
v-model="form.email"
|
|
114
114
|
type="email"
|
|
@@ -119,27 +119,31 @@ async function submitForm() {
|
|
|
119
119
|
</UFormField>
|
|
120
120
|
|
|
121
121
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
122
|
-
<UFormField label="
|
|
122
|
+
<UFormField :label="t('supabase.auth.fields.username')" required>
|
|
123
123
|
<UInput
|
|
124
124
|
v-model="form.username"
|
|
125
|
-
placeholder="
|
|
125
|
+
:placeholder="t('supabase.auth.signup.usernamePlaceholder')"
|
|
126
126
|
class="w-full"
|
|
127
127
|
minlength="3"
|
|
128
128
|
required
|
|
129
129
|
/>
|
|
130
130
|
</UFormField>
|
|
131
131
|
|
|
132
|
-
<UFormField label="
|
|
132
|
+
<UFormField :label="t('supabase.auth.fields.displayName')" required>
|
|
133
133
|
<UInput
|
|
134
134
|
v-model="form.display_name"
|
|
135
|
-
placeholder="
|
|
135
|
+
:placeholder="t('supabase.auth.signup.displayNamePlaceholder')"
|
|
136
136
|
class="w-full"
|
|
137
137
|
required
|
|
138
138
|
/>
|
|
139
139
|
</UFormField>
|
|
140
140
|
</div>
|
|
141
141
|
|
|
142
|
-
<UFormField
|
|
142
|
+
<UFormField
|
|
143
|
+
:error="!passwordMatch"
|
|
144
|
+
:label="t('supabase.auth.fields.password')"
|
|
145
|
+
required
|
|
146
|
+
>
|
|
143
147
|
<UInput
|
|
144
148
|
v-model="form.password"
|
|
145
149
|
placeholder="••••"
|
|
@@ -149,7 +153,11 @@ async function submitForm() {
|
|
|
149
153
|
/>
|
|
150
154
|
</UFormField>
|
|
151
155
|
|
|
152
|
-
<UFormField
|
|
156
|
+
<UFormField
|
|
157
|
+
:error="!passwordMatch"
|
|
158
|
+
:label="t('supabase.auth.fields.confirmPassword')"
|
|
159
|
+
required
|
|
160
|
+
>
|
|
153
161
|
<UInput
|
|
154
162
|
v-model="form.confirm_password"
|
|
155
163
|
placeholder="••••"
|
|
@@ -169,7 +177,7 @@ async function submitForm() {
|
|
|
169
177
|
variant="link"
|
|
170
178
|
class="px-0"
|
|
171
179
|
>
|
|
172
|
-
|
|
180
|
+
{{ t('supabase.auth.backToLogin') }}
|
|
173
181
|
</UButton>
|
|
174
182
|
</UFormField>
|
|
175
183
|
|
|
@@ -180,7 +188,7 @@ async function submitForm() {
|
|
|
180
188
|
type="submit"
|
|
181
189
|
class="w-full justify-center sm:w-auto"
|
|
182
190
|
>
|
|
183
|
-
|
|
191
|
+
{{ t('supabase.auth.signup.submit') }}
|
|
184
192
|
</UButton>
|
|
185
193
|
</UFormField>
|
|
186
194
|
</div>
|
|
@@ -3,8 +3,10 @@ definePageMeta({
|
|
|
3
3
|
layout: 'auth',
|
|
4
4
|
})
|
|
5
5
|
|
|
6
|
+
const { t } = usePlutoI18n()
|
|
7
|
+
|
|
6
8
|
useHead({
|
|
7
|
-
title:
|
|
9
|
+
title: () => t('supabase.auth.update.title'),
|
|
8
10
|
})
|
|
9
11
|
|
|
10
12
|
const route = useRoute()
|
|
@@ -57,17 +59,16 @@ async function submitForm() {
|
|
|
57
59
|
<UIcon name="lucide:lock-keyhole" class="inline-block" />
|
|
58
60
|
</span>
|
|
59
61
|
|
|
60
|
-
<h1 class="text-3xl font-bold">
|
|
62
|
+
<h1 class="text-3xl font-bold">{{ t('supabase.auth.update.doneTitle') }}</h1>
|
|
61
63
|
</hgroup>
|
|
62
64
|
|
|
63
65
|
<p>
|
|
64
|
-
|
|
65
|
-
password.
|
|
66
|
+
{{ t('supabase.auth.update.doneDescription') }}
|
|
66
67
|
</p>
|
|
67
68
|
|
|
68
69
|
<div class="flex items-center justify-center">
|
|
69
70
|
<UButton to="/admin/login" color="primary" icon="lucide:log-in">
|
|
70
|
-
|
|
71
|
+
{{ t('supabase.auth.update.goToLogin') }}
|
|
71
72
|
</UButton>
|
|
72
73
|
</div>
|
|
73
74
|
</div>
|
|
@@ -76,11 +77,13 @@ async function submitForm() {
|
|
|
76
77
|
<form v-else @submit.prevent="submitForm">
|
|
77
78
|
<div class="flex flex-col gap-y-6">
|
|
78
79
|
<hgroup class="flex flex-col gap-y-1">
|
|
79
|
-
<h1 class="text-3xl font-bold">
|
|
80
|
-
<p class="text-sm text-muted">
|
|
80
|
+
<h1 class="text-3xl font-bold">{{ t('supabase.auth.update.title') }}</h1>
|
|
81
|
+
<p class="text-sm text-muted">
|
|
82
|
+
{{ t('supabase.auth.update.description') }}
|
|
83
|
+
</p>
|
|
81
84
|
</hgroup>
|
|
82
85
|
|
|
83
|
-
<UFormField label="
|
|
86
|
+
<UFormField :label="t('supabase.auth.update.newPassword')">
|
|
84
87
|
<UInput
|
|
85
88
|
v-model="form.password"
|
|
86
89
|
placeholder="••••"
|
|
@@ -94,10 +97,10 @@ async function submitForm() {
|
|
|
94
97
|
<UFormField
|
|
95
98
|
:error="
|
|
96
99
|
form.confirm_password && !passwordMatch
|
|
97
|
-
? '
|
|
100
|
+
? t('supabase.auth.passwordMismatch')
|
|
98
101
|
: undefined
|
|
99
102
|
"
|
|
100
|
-
label="
|
|
103
|
+
:label="t('supabase.auth.update.confirmNewPassword')"
|
|
101
104
|
>
|
|
102
105
|
<UInput
|
|
103
106
|
v-model="form.confirm_password"
|
|
@@ -120,13 +123,13 @@ async function submitForm() {
|
|
|
120
123
|
icon="lucide:lock-keyhole"
|
|
121
124
|
class="w-full justify-center sm:w-auto"
|
|
122
125
|
>
|
|
123
|
-
|
|
126
|
+
{{ t('supabase.auth.update.submit') }}
|
|
124
127
|
</UButton>
|
|
125
128
|
</UFormField>
|
|
126
129
|
|
|
127
130
|
<UFormField>
|
|
128
131
|
<UButton variant="link" to="/admin/login" class="px-0">
|
|
129
|
-
|
|
132
|
+
{{ t('supabase.auth.backToLogin') }}
|
|
130
133
|
</UButton>
|
|
131
134
|
</UFormField>
|
|
132
135
|
</div>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
const { t } = usePlutoI18n()
|
|
3
|
+
|
|
2
4
|
useHead({
|
|
3
|
-
title: '
|
|
5
|
+
title: () => t('supabase.migrations.title'),
|
|
4
6
|
})
|
|
5
7
|
|
|
6
8
|
const config = useRuntimeConfig()
|
|
@@ -15,6 +17,19 @@ const { status, fetchStatus, pendingCount, refresh, runMigrations } =
|
|
|
15
17
|
|
|
16
18
|
const isDev = import.meta.dev
|
|
17
19
|
|
|
20
|
+
// The text of each result status that the server returns.
|
|
21
|
+
const statusLabels: Record<string, string> = {
|
|
22
|
+
applied: 'supabase.migrations.status.applied',
|
|
23
|
+
skipped: 'supabase.migrations.status.skipped',
|
|
24
|
+
failed: 'supabase.migrations.status.failed',
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function statusText(status: string): string {
|
|
28
|
+
const key = statusLabels[status]
|
|
29
|
+
|
|
30
|
+
return key ? t(key) : status
|
|
31
|
+
}
|
|
32
|
+
|
|
18
33
|
// Only the layers that actually have a pending, or applied, file — used to
|
|
19
34
|
// render per-file detail under each layer below.
|
|
20
35
|
const pendingLayers = computed(
|
|
@@ -86,9 +101,9 @@ async function applyMigrations(useForm: boolean) {
|
|
|
86
101
|
|
|
87
102
|
if (result.success === false) {
|
|
88
103
|
toast.add({
|
|
89
|
-
title: '
|
|
104
|
+
title: t('supabase.migrations.applyFailed'),
|
|
90
105
|
description: result.needsConnectionString
|
|
91
|
-
? '
|
|
106
|
+
? t('supabase.migrations.connectionRequired')
|
|
92
107
|
: undefined,
|
|
93
108
|
icon: 'lucide:circle-x',
|
|
94
109
|
color: 'error',
|
|
@@ -98,7 +113,7 @@ async function applyMigrations(useForm: boolean) {
|
|
|
98
113
|
}
|
|
99
114
|
|
|
100
115
|
toast.add({
|
|
101
|
-
title: '
|
|
116
|
+
title: t('supabase.migrations.applied'),
|
|
102
117
|
icon: 'lucide:check-circle',
|
|
103
118
|
color: 'success',
|
|
104
119
|
})
|
|
@@ -118,9 +133,8 @@ async function applyMigrations(useForm: boolean) {
|
|
|
118
133
|
|
|
119
134
|
if (isDev && useForm && !hasStatusCode) {
|
|
120
135
|
toast.add({
|
|
121
|
-
title: '
|
|
122
|
-
description:
|
|
123
|
-
'Saving a new connection string restarts the dev server. Reconnecting…',
|
|
136
|
+
title: t('supabase.connection.restarting'),
|
|
137
|
+
description: t('supabase.migrations.restartingDescription'),
|
|
124
138
|
icon: 'lucide:refresh-cw',
|
|
125
139
|
color: 'info',
|
|
126
140
|
})
|
|
@@ -134,18 +148,21 @@ async function applyMigrations(useForm: boolean) {
|
|
|
134
148
|
toast.add(
|
|
135
149
|
recovered
|
|
136
150
|
? {
|
|
137
|
-
title: '
|
|
151
|
+
title: t('supabase.connection.reconnected'),
|
|
138
152
|
description:
|
|
139
153
|
pendingCount.value === 0
|
|
140
|
-
? '
|
|
141
|
-
:
|
|
154
|
+
? t('supabase.migrations.reconnectedAllApplied')
|
|
155
|
+
: t('supabase.migrations.reconnectedPending', {
|
|
156
|
+
count: pendingCount.value,
|
|
157
|
+
}),
|
|
142
158
|
icon: 'lucide:check-circle',
|
|
143
159
|
color: 'success',
|
|
144
160
|
}
|
|
145
161
|
: {
|
|
146
|
-
title: '
|
|
147
|
-
description:
|
|
148
|
-
'
|
|
162
|
+
title: t('supabase.connection.stillReconnecting'),
|
|
163
|
+
description: t(
|
|
164
|
+
'supabase.connection.stillReconnectingDescription'
|
|
165
|
+
),
|
|
149
166
|
icon: 'lucide:triangle-alert',
|
|
150
167
|
color: 'warning',
|
|
151
168
|
}
|
|
@@ -159,8 +176,8 @@ async function applyMigrations(useForm: boolean) {
|
|
|
159
176
|
}
|
|
160
177
|
|
|
161
178
|
toast.add({
|
|
162
|
-
title: '
|
|
163
|
-
description: '
|
|
179
|
+
title: t('supabase.migrations.error'),
|
|
180
|
+
description: t('supabase.connection.checkConsole'),
|
|
164
181
|
icon: 'lucide:circle-x',
|
|
165
182
|
color: 'error',
|
|
166
183
|
})
|
|
@@ -172,15 +189,15 @@ async function applyMigrations(useForm: boolean) {
|
|
|
172
189
|
|
|
173
190
|
<template>
|
|
174
191
|
<AdminView>
|
|
175
|
-
<h1 class="text-3xl font-bold lg:text-4xl">
|
|
192
|
+
<h1 class="text-3xl font-bold lg:text-4xl">{{ t('supabase.migrations.title') }}</h1>
|
|
176
193
|
|
|
177
194
|
<UAlert
|
|
178
195
|
v-if="isReconnecting"
|
|
196
|
+
:title="t('supabase.connection.restarting')"
|
|
197
|
+
:description="t('supabase.migrations.reconnectingBanner')"
|
|
179
198
|
color="info"
|
|
180
199
|
variant="outline"
|
|
181
200
|
icon="lucide:refresh-cw"
|
|
182
|
-
title="Dev server restarting"
|
|
183
|
-
description="Saving a new connection string restarts the dev server. Reconnecting — this page will update on its own once it's back."
|
|
184
201
|
/>
|
|
185
202
|
|
|
186
203
|
<div
|
|
@@ -188,7 +205,7 @@ async function applyMigrations(useForm: boolean) {
|
|
|
188
205
|
class="flex items-center gap-x-2"
|
|
189
206
|
>
|
|
190
207
|
<Icon name="svg-spinners:ring-resize" />
|
|
191
|
-
<span>
|
|
208
|
+
<span>{{ t('supabase.migrations.loading') }}</span>
|
|
192
209
|
</div>
|
|
193
210
|
|
|
194
211
|
<template v-else-if="status">
|
|
@@ -196,16 +213,20 @@ async function applyMigrations(useForm: boolean) {
|
|
|
196
213
|
<div class="flex flex-col gap-y-6">
|
|
197
214
|
<UAlert
|
|
198
215
|
v-if="pendingCount === 0"
|
|
216
|
+
:title="t('supabase.migrations.upToDate')"
|
|
217
|
+
:description="t('supabase.migrations.upToDateDescription')"
|
|
199
218
|
color="success"
|
|
200
219
|
variant="outline"
|
|
201
220
|
icon="lucide:check-circle"
|
|
202
|
-
title="Everything is up to date"
|
|
203
|
-
description="No layer needs a database migration."
|
|
204
221
|
/>
|
|
205
222
|
|
|
206
223
|
<div v-else class="flex flex-col gap-y-2">
|
|
207
224
|
<h2 class="font-semibold">
|
|
208
|
-
|
|
225
|
+
{{
|
|
226
|
+
t('supabase.migrations.pendingLayers', {
|
|
227
|
+
count: status.pending.length,
|
|
228
|
+
})
|
|
229
|
+
}}
|
|
209
230
|
</h2>
|
|
210
231
|
<ul class="flex flex-col gap-y-2 text-sm">
|
|
211
232
|
<li v-for="layer in pendingLayers" :key="layer.layerName">
|
|
@@ -221,7 +242,11 @@ async function applyMigrations(useForm: boolean) {
|
|
|
221
242
|
|
|
222
243
|
<div v-if="status.applied.length" class="flex flex-col gap-y-2">
|
|
223
244
|
<h2 class="font-semibold">
|
|
224
|
-
|
|
245
|
+
{{
|
|
246
|
+
t('supabase.migrations.appliedLayers', {
|
|
247
|
+
count: status.applied.length,
|
|
248
|
+
})
|
|
249
|
+
}}
|
|
225
250
|
</h2>
|
|
226
251
|
<ul class="flex flex-col gap-y-2 text-sm">
|
|
227
252
|
<li v-for="layer in appliedLayers" :key="layer.layerName">
|
|
@@ -241,7 +266,7 @@ async function applyMigrations(useForm: boolean) {
|
|
|
241
266
|
class="flex flex-col gap-y-4"
|
|
242
267
|
@submit="applyMigrations(true)"
|
|
243
268
|
>
|
|
244
|
-
<UFormField label="
|
|
269
|
+
<UFormField :label="t('supabase.connection.connectionString')" required>
|
|
245
270
|
<UInput
|
|
246
271
|
v-model="connectionForm.connectionString"
|
|
247
272
|
:disabled="isRunning"
|
|
@@ -250,19 +275,24 @@ async function applyMigrations(useForm: boolean) {
|
|
|
250
275
|
/>
|
|
251
276
|
|
|
252
277
|
<template #help>
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
:to="`https://supabase.com/dashboard/project/${projectId}/database/settings?showConnect=true&connectTab=direct&method=transaction`"
|
|
256
|
-
target="_blank"
|
|
257
|
-
class="underline"
|
|
258
|
-
external
|
|
278
|
+
<SupabaseMessageParts
|
|
279
|
+
:message="t('supabase.connection.connectionStringHelp')"
|
|
259
280
|
>
|
|
260
|
-
|
|
261
|
-
|
|
281
|
+
<template #link>
|
|
282
|
+
<ULink
|
|
283
|
+
:to="`https://supabase.com/dashboard/project/${projectId}/database/settings?showConnect=true&connectTab=direct&method=transaction`"
|
|
284
|
+
target="_blank"
|
|
285
|
+
class="underline"
|
|
286
|
+
external
|
|
287
|
+
>
|
|
288
|
+
{{ t('supabase.connection.connectionStringHelpLink') }}
|
|
289
|
+
</ULink>
|
|
290
|
+
</template>
|
|
291
|
+
</SupabaseMessageParts>
|
|
262
292
|
</template>
|
|
263
293
|
</UFormField>
|
|
264
294
|
|
|
265
|
-
<UFormField label="
|
|
295
|
+
<UFormField :label="t('supabase.connection.password')" required>
|
|
266
296
|
<UInput
|
|
267
297
|
v-model="connectionForm.password"
|
|
268
298
|
:disabled="isRunning"
|
|
@@ -278,32 +308,36 @@ async function applyMigrations(useForm: boolean) {
|
|
|
278
308
|
variant="outline"
|
|
279
309
|
>
|
|
280
310
|
<template #description>
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
<ULink
|
|
284
|
-
to="https://supabase.com/dashboard/project/_/database/settings"
|
|
285
|
-
target="_blank"
|
|
311
|
+
<SupabaseMessageParts
|
|
312
|
+
:message="t('supabase.connection.passwordInfo')"
|
|
286
313
|
>
|
|
287
|
-
|
|
288
|
-
|
|
314
|
+
<template #link>
|
|
315
|
+
<ULink
|
|
316
|
+
to="https://supabase.com/dashboard/project/_/database/settings"
|
|
317
|
+
target="_blank"
|
|
318
|
+
>
|
|
319
|
+
{{ t('supabase.connection.passwordInfoLink') }}
|
|
320
|
+
</ULink>
|
|
321
|
+
</template>
|
|
322
|
+
</SupabaseMessageParts>
|
|
289
323
|
</template>
|
|
290
324
|
</UAlert>
|
|
291
325
|
|
|
292
326
|
<UAlert
|
|
327
|
+
:title="t('supabase.connection.whyTitle')"
|
|
328
|
+
:description="t('supabase.migrations.why')"
|
|
293
329
|
color="warning"
|
|
294
330
|
variant="outline"
|
|
295
|
-
title="Why do I need to provide a database password?"
|
|
296
331
|
icon="lucide:info"
|
|
297
|
-
description="It is used once to open a direct PostgreSQL connection and run the pending layer schemas. It is then written to .env on the server, so future migrations need no prompt. It is never stored anywhere else, and never sent back to your browser."
|
|
298
332
|
/>
|
|
299
333
|
|
|
300
334
|
<UAlert
|
|
301
335
|
v-if="isDev"
|
|
336
|
+
:title="t('supabase.connection.restartTitle')"
|
|
337
|
+
:description="t('supabase.migrations.restartDescription')"
|
|
302
338
|
color="info"
|
|
303
339
|
variant="outline"
|
|
304
|
-
title="This restarts the dev server"
|
|
305
340
|
icon="lucide:refresh-cw"
|
|
306
|
-
description="Saving a new connection string writes it to .env. In development, that restarts the server automatically. The page will briefly show a reconnecting message — this is expected, not an error."
|
|
307
341
|
/>
|
|
308
342
|
|
|
309
343
|
<div class="flex">
|
|
@@ -314,7 +348,7 @@ async function applyMigrations(useForm: boolean) {
|
|
|
314
348
|
icon="lucide:database"
|
|
315
349
|
class="w-full justify-center sm:w-auto"
|
|
316
350
|
>
|
|
317
|
-
|
|
351
|
+
{{ t('supabase.migrations.apply') }}
|
|
318
352
|
</UButton>
|
|
319
353
|
</div>
|
|
320
354
|
</UForm>
|
|
@@ -327,7 +361,7 @@ async function applyMigrations(useForm: boolean) {
|
|
|
327
361
|
class="w-full justify-center sm:w-auto"
|
|
328
362
|
@click="applyMigrations(false)"
|
|
329
363
|
>
|
|
330
|
-
|
|
364
|
+
{{ t('supabase.migrations.apply') }}
|
|
331
365
|
</UButton>
|
|
332
366
|
</div>
|
|
333
367
|
</template>
|
|
@@ -336,7 +370,9 @@ async function applyMigrations(useForm: boolean) {
|
|
|
336
370
|
|
|
337
371
|
<UCard v-if="lastRun">
|
|
338
372
|
<div class="flex flex-col gap-y-4">
|
|
339
|
-
<h2 class="font-semibold">
|
|
373
|
+
<h2 class="font-semibold">
|
|
374
|
+
{{ t('supabase.migrations.lastRun') }}
|
|
375
|
+
</h2>
|
|
340
376
|
|
|
341
377
|
<EnvPersistWarning
|
|
342
378
|
v-if="lastRun.success && lastRun.persisted === false"
|
|
@@ -354,7 +390,7 @@ async function applyMigrations(useForm: boolean) {
|
|
|
354
390
|
<span class="font-mono"
|
|
355
391
|
>{{ result.layerName }}/{{ result.migrationName }}</span
|
|
356
392
|
>
|
|
357
|
-
— {{ result.status }}
|
|
393
|
+
— {{ statusText(result.status) }}
|
|
358
394
|
<span v-if="result.error" class="text-error">
|
|
359
395
|
: {{ result.error }}</span
|
|
360
396
|
>
|
|
@@ -366,11 +402,11 @@ async function applyMigrations(useForm: boolean) {
|
|
|
366
402
|
|
|
367
403
|
<UAlert
|
|
368
404
|
v-else
|
|
405
|
+
:title="t('supabase.migrations.loadFailed')"
|
|
406
|
+
:description="t('supabase.migrations.loadFailedDescription')"
|
|
369
407
|
color="error"
|
|
370
408
|
variant="outline"
|
|
371
409
|
icon="lucide:circle-x"
|
|
372
|
-
title="Could not load migration status"
|
|
373
|
-
description="This isn't the dev-server-restart case above — something else went wrong reading migration status. Check the server console, then try again."
|
|
374
410
|
>
|
|
375
411
|
<template #actions>
|
|
376
412
|
<UButton
|
|
@@ -379,7 +415,7 @@ async function applyMigrations(useForm: boolean) {
|
|
|
379
415
|
icon="lucide:refresh-cw"
|
|
380
416
|
@click="refresh()"
|
|
381
417
|
>
|
|
382
|
-
|
|
418
|
+
{{ t('supabase.migrations.retry') }}
|
|
383
419
|
</UButton>
|
|
384
420
|
</template>
|
|
385
421
|
</UAlert>
|