Move a user profile and password modals to frontend-core to allow sharing

This commit is contained in:
Andrew Kingston 2025-03-07 16:14:12 +00:00
parent b390f92019
commit 3c44c94442
No known key found for this signature in database
23 changed files with 69 additions and 62 deletions

View File

@ -5,8 +5,8 @@
import { appsStore } from "@/stores/portal"
import { API } from "@/api"
import { writable } from "svelte/store"
import { createValidationStore } from "@/helpers/validation/yup"
import * as appValidation from "@/helpers/validation/yup/app"
import { createValidationStore } from "@budibase/frontend-core/src/utils/validation/yup"
import * as appValidation from "@budibase/frontend-core/src/utils/validation/yup/app"
import EditableIcon from "@/components/common/EditableIcon.svelte"
import { isEqual } from "lodash"
import { createEventDispatcher } from "svelte"

View File

@ -12,8 +12,8 @@
import { appsStore, admin, auth } from "@/stores/portal"
import { onMount } from "svelte"
import { goto } from "@roxi/routify"
import { createValidationStore } from "@/helpers/validation/yup"
import * as appValidation from "@/helpers/validation/yup/app"
import { createValidationStore } from "@budibase/frontend-core/src/utils/validation/yup"
import * as appValidation from "@budibase/frontend-core/src/utils/validation/yup/app"
import TemplateCard from "@/components/common/TemplateCard.svelte"
import { lowercase } from "@/helpers"
import { sdk } from "@budibase/shared-core"

View File

@ -6,9 +6,9 @@
Layout,
keepOpen,
} from "@budibase/bbui"
import { createValidationStore } from "@/helpers/validation/yup"
import { createValidationStore } from "@budibase/frontend-core/src/utils/validation/yup"
import { writable, get } from "svelte/store"
import * as appValidation from "@/helpers/validation/yup/app"
import * as appValidation from "@budibase/frontend-core/src/utils/validation/yup/app"
import { appsStore, auth } from "@/stores/portal"
import { onMount } from "svelte"
import { API } from "@/api"

View File

@ -9,7 +9,7 @@
notifications,
} from "@budibase/bbui"
import { downloadFile } from "@budibase/frontend-core"
import { createValidationStore } from "@/helpers/validation/yup"
import { createValidationStore } from "@budibase/frontend-core/src/utils/validation/yup"
export let app
export let published

View File

@ -41,11 +41,6 @@ export const LAYOUT_NAMES = {
},
}
// one or more word characters and whitespace
export const APP_NAME_REGEX = /^[\w\s]+$/
// zero or more non-whitespace characters
export const APP_URL_REGEX = /^[0-9a-zA-Z-_]+$/
export const DefaultAppTheme = {
primaryColor: "var(--spectrum-global-color-blue-600)",
primaryColorHover: "var(--spectrum-global-color-blue-500)",

View File

@ -28,13 +28,13 @@
Constants,
Utils,
RoleUtils,
emailValidator,
} from "@budibase/frontend-core"
import { sdk } from "@budibase/shared-core"
import { API } from "@/api"
import GroupIcon from "../../../portal/users/groups/_components/GroupIcon.svelte"
import RoleSelect from "@/components/common/RoleSelect.svelte"
import UpgradeModal from "@/components/common/users/UpgradeModal.svelte"
import { emailValidator } from "@/helpers/validation"
import { fly } from "svelte/transition"
import InfoDisplay from "../design/[screenId]/[componentId]/_components/Component/InfoDisplay.svelte"
import BuilderGroupPopover from "./BuilderGroupPopover.svelte"

View File

@ -24,13 +24,13 @@
import { goto } from "@roxi/routify"
import { AppStatus } from "@/constants"
import { gradient } from "@/actions"
import ProfileModal from "@/components/settings/ProfileModal.svelte"
import ChangePasswordModal from "@/components/settings/ChangePasswordModal.svelte"
import { ProfileModal, ChangePasswordModal } from "@budibase/frontend-core"
import { processStringSync } from "@budibase/string-templates"
import Spaceman from "assets/bb-space-man.svg"
import Logo from "assets/bb-emblem.svg"
import { UserAvatar } from "@budibase/frontend-core"
import { helpers, sdk } from "@budibase/shared-core"
import { API } from "@/api"
let loaded = false
let userInfoModal
@ -201,10 +201,10 @@
</Page>
</div>
<Modal bind:this={userInfoModal}>
<ProfileModal />
<ProfileModal {API} user={$auth.user} on:save={() => auth.getSelf()} />
</Modal>
<Modal bind:this={changePasswordModal}>
<ChangePasswordModal />
<ChangePasswordModal {API} on:save={() => auth.getSelf()} />
</Modal>
{/if}

View File

@ -12,7 +12,7 @@
import Logo from "assets/bb-emblem.svg"
import { TestimonialPage } from "@budibase/frontend-core/src/components"
import { onMount } from "svelte"
import PasswordRepeatInput from "../../../components/common/users/PasswordRepeatInput.svelte"
import PasswordRepeatInput from "@budibase/frontend-core/src/components/PasswordRepeatInput.svelte"
const resetCode = $params["?code"]
let form
@ -79,11 +79,7 @@
<Layout gap="S" noPadding>
<Heading size="M">Reset your password</Heading>
<Body size="M">Must contain at least 12 characters</Body>
<PasswordRepeatInput
bind:passwordForm={form}
bind:password
bind:error={passwordError}
/>
<PasswordRepeatInput bind:password bind:error={passwordError} />
<Button secondary cta on:click={reset}>
{#if loading}
<ProgressCircle overBackground={true} size="S" />

View File

@ -2,8 +2,8 @@
import { admin, auth } from "@/stores/portal"
import { ActionMenu, MenuItem, Icon, Modal } from "@budibase/bbui"
import { goto } from "@roxi/routify"
import ProfileModal from "@/components/settings/ProfileModal.svelte"
import ChangePasswordModal from "@/components/settings/ChangePasswordModal.svelte"
import ProfileModal from "@budibase/frontend-core/src/components/ProfileModal.svelte"
import ChangePasswordModal from "@budibase/frontend-core/src/components/ChangePasswordModal.svelte"
import ThemeModal from "@/components/settings/ThemeModal.svelte"
import APIKeyModal from "@/components/settings/APIKeyModal.svelte"
import { UserAvatar } from "@budibase/frontend-core"

View File

@ -1,7 +1,7 @@
<script>
import { Button, FancyForm, FancyInput } from "@budibase/bbui"
import PanelHeader from "./PanelHeader.svelte"
import { APP_URL_REGEX } from "@/constants"
import { Constants } from "@budibase/frontend-core"
export let disabled
export let name = ""
@ -28,7 +28,7 @@
return "URL must be provided"
}
if (!APP_URL_REGEX.test(url)) {
if (!Constants.APP_URL_REGEX.test(url)) {
return "Invalid URL"
}
}

View File

@ -10,8 +10,7 @@
Icon,
} from "@budibase/bbui"
import { groups, licensing } from "@/stores/portal"
import { Constants } from "@budibase/frontend-core"
import { emailValidator } from "@/helpers/validation"
import { Constants, emailValidator } from "@budibase/frontend-core"
import { capitalise } from "@/helpers"
export let showOnboardingTypeModal

View File

@ -8,8 +8,7 @@
Icon,
} from "@budibase/bbui"
import { groups, licensing, admin } from "@/stores/portal"
import { emailValidator } from "@/helpers/validation"
import { Constants } from "@budibase/frontend-core"
import { emailValidator, Constants } from "@budibase/frontend-core"
import { capitalise } from "@/helpers"
const BYTES_IN_MB = 1000000

View File

@ -1,21 +1,27 @@
<script>
<script lang="ts">
import { ModalContent, Body, notifications } from "@budibase/bbui"
import PasswordRepeatInput from "@/components/common/users/PasswordRepeatInput.svelte"
import { auth } from "@/stores/portal"
import PasswordRepeatInput from "./PasswordRepeatInput.svelte"
import type { APIClient } from "@budibase/frontend-core"
import { createEventDispatcher } from "svelte"
let password
let error
export let API: APIClient
const dispatch = createEventDispatcher()
let password: string = ""
let error: string = ""
const updatePassword = async () => {
try {
await auth.updateSelf({ password })
await API.updateSelf({ password })
dispatch("save")
notifications.success("Password changed successfully")
} catch (error) {
notifications.error("Failed to update password")
}
}
const handleKeydown = evt => {
const handleKeydown = (evt: KeyboardEvent) => {
if (evt.key === "Enter" && !error && password) {
updatePassword()
}
@ -27,7 +33,7 @@
title="Update password"
confirmText="Update password"
onConfirm={updatePassword}
disabled={error || !password}
disabled={!!error || !password}
>
<Body size="S">Enter your new password below.</Body>
<PasswordRepeatInput bind:password bind:error />

View File

@ -1,20 +1,14 @@
<script>
import { FancyForm, FancyInput } from "@budibase/bbui"
import {
createValidationStore,
requiredValidator,
} from "@/helpers/validation"
import { admin } from "@/stores/portal"
import { createValidationStore, requiredValidator } from "../utils/validation"
export let password
export let passwordForm
export let error
$: passwordMinLength = $admin.passwordMinLength ?? 12
export let minLength = 12
const validatePassword = value => {
if (!value || value.length < passwordMinLength) {
return `Please enter at least ${passwordMinLength} characters. We recommend using machine generated or random passwords.`
if (!value || value.length < minLength) {
return `Please enter at least ${minLength} characters. We recommend using machine generated or random passwords.`
}
return null
}
@ -41,7 +35,7 @@
firstPasswordError
</script>
<FancyForm bind:this={passwordForm}>
<FancyForm>
<FancyInput
label="Password"
type="password"

View File

@ -1,16 +1,26 @@
<script>
import { ModalContent, Body, Input, notifications } from "@budibase/bbui"
<script lang="ts">
import { writable } from "svelte/store"
import { auth } from "@/stores/portal"
import { ModalContent, Body, Input, notifications } from "@budibase/bbui"
import type { User, ContextUser } from "@budibase/types"
import type { APIClient } from "@budibase/frontend-core"
import { createEventDispatcher } from "svelte"
export let user: User | ContextUser | undefined = undefined
export let API: APIClient
$: console.log(user)
const dispatch = createEventDispatcher()
const values = writable({
firstName: $auth.user.firstName,
lastName: $auth.user.lastName,
firstName: user?.firstName,
lastName: user?.lastName,
})
const updateInfo = async () => {
try {
await auth.updateSelf($values)
await API.updateSelf($values)
dispatch("save")
notifications.success("Information updated successfully")
} catch (error) {
console.error(error)
@ -23,7 +33,7 @@
<Body size="S">
Personalise the platform by adding your first name and last name.
</Body>
<Input disabled bind:value={$auth.user.email} label="Email" />
<Input disabled value={user?.email || ""} label="Email" />
<Input bind:value={$values.firstName} label="First name" />
<Input bind:value={$values.lastName} label="Last name" />
</ModalContent>

View File

@ -9,3 +9,5 @@ export { Grid } from "./grid"
export { default as ClientAppSkeleton } from "./ClientAppSkeleton.svelte"
export { default as CoreFilterBuilder } from "./CoreFilterBuilder.svelte"
export { default as FilterUsers } from "./FilterUsers.svelte"
export { default as ChangePasswordModal } from "./ChangePasswordModal.svelte"
export { default as ProfileModal } from "./ProfileModal.svelte"

View File

@ -166,3 +166,9 @@ export const FieldPermissions = {
READONLY: "readonly",
HIDDEN: "hidden",
}
// one or more word characters and whitespace
export const APP_NAME_REGEX = /^[\w\s]+$/
// zero or more non-whitespace characters
export const APP_URL_REGEX = /^[0-9a-zA-Z-_]+$/

View File

@ -14,3 +14,4 @@ export * from "./settings"
export * from "./relatedColumns"
export * from "./table"
export * from "./components"
export * from "./validation"

View File

@ -1,5 +1,5 @@
import { string, mixed } from "yup"
import { APP_NAME_REGEX, APP_URL_REGEX } from "@/constants"
import { APP_NAME_REGEX, APP_URL_REGEX } from "../../../constants"
export const name = (validation, { apps, currentApp } = { apps: [] }) => {
validation.addValidator(

View File

@ -1,7 +1,6 @@
import { capitalise } from "@/helpers"
import { object, string, number } from "yup"
import { writable, get } from "svelte/store"
import { notifications } from "@budibase/bbui"
import { Helpers, notifications } from "@budibase/bbui"
export const createValidationStore = () => {
const DEFAULT = {
@ -77,7 +76,7 @@ export const createValidationStore = () => {
const [fieldError] = error.errors
if (fieldError) {
validation.update(store => {
store.errors[propertyName] = capitalise(fieldError)
store.errors[propertyName] = Helpers.capitalise(fieldError)
store.valid = false
return store
})
@ -120,7 +119,7 @@ export const createValidationStore = () => {
} else {
error.inner.forEach(err => {
validation.update(store => {
store.errors[err.path] = capitalise(err.message)
store.errors[err.path] = Helpers.capitalise(err.message)
return store
})
})