Add initial user dropdown in nav, improve typing in auth store
This commit is contained in:
parent
b20ef58727
commit
d7fc0f1b4b
|
@ -5,10 +5,10 @@
|
|||
|
||||
export let disabled = false
|
||||
export let align = "left"
|
||||
export let portalTarget
|
||||
export let portalTarget = undefined
|
||||
export let openOnHover = false
|
||||
export let animate
|
||||
export let offset
|
||||
export let animate = true
|
||||
export let offset = undefined
|
||||
|
||||
const actionMenuContext = getContext("actionMenu")
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
export let url = ""
|
||||
export let disabled = false
|
||||
export let initials = "JD"
|
||||
export let color = null
|
||||
export let color = ""
|
||||
|
||||
const DefaultColor = "#3aab87"
|
||||
|
||||
|
|
|
@ -105,8 +105,8 @@
|
|||
<img class="logo" alt="logo" src={$organisation.logoUrl || Logo} />
|
||||
<ActionMenu align="right">
|
||||
<div slot="control" class="avatar">
|
||||
<UserAvatar user={$auth.user} showTooltip={false} />
|
||||
<Icon size="XL" name="ChevronDown" />
|
||||
<UserAvatar size="M" user={$auth.user} showTooltip={false} />
|
||||
<Icon size="L" name="ChevronDown" />
|
||||
</div>
|
||||
<MenuItem icon="UserEdit" on:click={() => userInfoModal.show()}>
|
||||
My profile
|
||||
|
@ -239,6 +239,7 @@
|
|||
grid-template-columns: auto auto;
|
||||
place-items: center;
|
||||
grid-gap: var(--spacing-xs);
|
||||
transition: filter 130ms ease-out;
|
||||
}
|
||||
.avatar:hover {
|
||||
cursor: pointer;
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
|
||||
<ActionMenu align="right">
|
||||
<div slot="control" class="user-dropdown">
|
||||
<UserAvatar user={$auth.user} showTooltip={false} />
|
||||
<Icon size="XL" name="ChevronDown" />
|
||||
<UserAvatar size="M" user={$auth.user} showTooltip={false} />
|
||||
<Icon size="L" name="ChevronDown" />
|
||||
</div>
|
||||
<MenuItem icon="UserEdit" on:click={() => profileModal.show()}>
|
||||
My profile
|
||||
|
@ -75,7 +75,8 @@
|
|||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
gap: var(--spacing-s);
|
||||
gap: var(--spacing-xs);
|
||||
transition: filter 130ms ease-out;
|
||||
}
|
||||
.user-dropdown:hover {
|
||||
cursor: pointer;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script>
|
||||
import { getContext, setContext } from "svelte"
|
||||
import { writable } from "svelte/store"
|
||||
import { Heading, Icon, clickOutside, TooltipPosition } from "@budibase/bbui"
|
||||
import { Heading, Icon, clickOutside } from "@budibase/bbui"
|
||||
import { Constants } from "@budibase/frontend-core"
|
||||
import NavItem from "./NavItem.svelte"
|
||||
import { UserAvatar } from "@budibase/frontend-core"
|
||||
import UserMenu from "./UserMenu.svelte"
|
||||
|
||||
const sdk = getContext("sdk")
|
||||
const {
|
||||
|
@ -14,7 +14,6 @@
|
|||
builderStore,
|
||||
sidePanelStore,
|
||||
modalStore,
|
||||
authStore,
|
||||
} = sdk
|
||||
const context = getContext("context")
|
||||
const navStateStore = writable({})
|
||||
|
@ -159,11 +158,6 @@
|
|||
return !url.startsWith("http") ? `http://${url}` : url
|
||||
}
|
||||
|
||||
const navigateToPortal = () => {
|
||||
if ($builderStore.inBuilder) return
|
||||
window.location.href = "/builder/apps"
|
||||
}
|
||||
|
||||
const getScreenXOffset = (navigation, mobile) => {
|
||||
if (navigation !== "Left") {
|
||||
return 0
|
||||
|
@ -276,14 +270,9 @@
|
|||
<Heading size="S" {textAlign}>{title}</Heading>
|
||||
{/if}
|
||||
</div>
|
||||
{#if !embedded && $authStore}
|
||||
{#if !embedded}
|
||||
<div class="user top">
|
||||
<UserAvatar
|
||||
user={$authStore}
|
||||
size="M"
|
||||
tooltipPosition={TooltipPosition.Left}
|
||||
/>
|
||||
<Icon name="ChevronDown" />
|
||||
<UserMenu compact />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -309,16 +298,9 @@
|
|||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{#if !embedded && $authStore}
|
||||
{#if !embedded}
|
||||
<div class="user left">
|
||||
<UserAvatar user={$authStore} size="M" showTooltip={false} />
|
||||
<div class="text">
|
||||
<div class="name">
|
||||
{$authStore.firstName}
|
||||
{$authStore.lastName}
|
||||
</div>
|
||||
</div>
|
||||
<Icon name="ChevronDown" />
|
||||
<UserMenu />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -560,34 +542,6 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
/* User avatar */
|
||||
.user {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 8px;
|
||||
transition: background 130ms ease-out;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.user .text {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
color: var(--navTextColor);
|
||||
display: none;
|
||||
}
|
||||
.user .name {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
.layout--left .user .text {
|
||||
display: flex;
|
||||
}
|
||||
.user:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Left overrides for both desktop and mobile */
|
||||
.nav--left {
|
||||
overflow-y: auto;
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
<script lang="ts">
|
||||
import { ActionMenu, Icon, MenuItem } from "@budibase/bbui"
|
||||
import { UserAvatar } from "@budibase/frontend-core"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
export let compact: boolean = false
|
||||
|
||||
const { authStore } = getContext("sdk")
|
||||
|
||||
const requestChangeDetails = () => {}
|
||||
|
||||
const requestChangePassword = () => {
|
||||
// if (isOwner) {
|
||||
// window.location.href = `${$admin.accountPortalUrl}/portal/account`
|
||||
// } else {
|
||||
// changePasswordModal.show()
|
||||
// }
|
||||
}
|
||||
|
||||
const goToPortal = () => {
|
||||
window.location.href = "/builder/apps"
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if $authStore}
|
||||
<ActionMenu align={compact ? "right" : "left"}>
|
||||
<svelte:fragment slot="control" let:open>
|
||||
<div class="container" class:open>
|
||||
<UserAvatar user={$authStore} size="M" showTooltip={false} />
|
||||
{#if !compact}
|
||||
<div class="text">
|
||||
<div class="name">
|
||||
{$authStore.firstName}
|
||||
{$authStore.lastName}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<Icon size="L" name="ChevronDown" />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<MenuItem icon="UserEdit" on:click={requestChangeDetails}>
|
||||
My profile
|
||||
</MenuItem>
|
||||
<MenuItem icon="LockClosed" on:click={requestChangePassword}>
|
||||
Update password
|
||||
</MenuItem>
|
||||
<MenuItem icon="Apps" on:click={goToPortal}>Go to portal</MenuItem>
|
||||
<MenuItem icon="LogOut" on:click={authStore.actions.logOut}>
|
||||
Log out
|
||||
</MenuItem>
|
||||
</ActionMenu>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: var(--spacing-xs);
|
||||
transition: filter 130ms ease-out;
|
||||
}
|
||||
.text {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
color: var(--navTextColor);
|
||||
display: flex;
|
||||
}
|
||||
.name {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
.container:hover {
|
||||
cursor: pointer;
|
||||
filter: brightness(110%);
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,7 @@
|
|||
import ClientApp from "./components/ClientApp.svelte"
|
||||
import UpdatingApp from "./components/UpdatingApp.svelte"
|
||||
import {
|
||||
authStore,
|
||||
builderStore,
|
||||
appStore,
|
||||
blockStore,
|
||||
|
@ -80,6 +81,7 @@ export interface SDK {
|
|||
ActionTypes: typeof ActionTypes
|
||||
fetchDatasourceSchema: any
|
||||
generateGoldenSample: any
|
||||
authStore: typeof authStore
|
||||
builderStore: Readable<{
|
||||
inBuilder: boolean
|
||||
}> & {
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
import { API } from "@/api"
|
||||
import { writable } from "svelte/store"
|
||||
import {
|
||||
AppSelfResponse,
|
||||
ContextUserMetadata,
|
||||
GetGlobalSelfResponse,
|
||||
} from "@budibase/types"
|
||||
|
||||
type AuthState = ContextUserMetadata | GetGlobalSelfResponse | null
|
||||
|
||||
const createAuthStore = () => {
|
||||
const store = writable<{
|
||||
csrfToken?: string
|
||||
} | null>(null)
|
||||
const store = writable<AuthState>(null)
|
||||
|
||||
const hasAppSelfUser = (
|
||||
user: AppSelfResponse | null
|
||||
): user is ContextUserMetadata => {
|
||||
return user != null && "_id" in user
|
||||
}
|
||||
|
||||
// Fetches the user object if someone is logged in and has reloaded the page
|
||||
const fetchUser = async () => {
|
||||
|
@ -21,7 +32,10 @@ const createAuthStore = () => {
|
|||
|
||||
// Then try and get the user for this app to provide via context
|
||||
try {
|
||||
appSelf = await API.fetchSelf()
|
||||
const res = await API.fetchSelf()
|
||||
if (hasAppSelfUser(res)) {
|
||||
appSelf = res
|
||||
}
|
||||
} catch (error) {
|
||||
// Swallow
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue