From 84a1ccfc4c8776685da057540b3f77c96d21a9c1 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Mon, 24 Feb 2025 14:59:04 +0000 Subject: [PATCH 01/21] Fixing an issue with scrollbar always appearing on end user portal. --- packages/bbui/src/Layout/Page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bbui/src/Layout/Page.svelte b/packages/bbui/src/Layout/Page.svelte index e469927e60..e8dad8bc38 100644 --- a/packages/bbui/src/Layout/Page.svelte +++ b/packages/bbui/src/Layout/Page.svelte @@ -47,7 +47,7 @@ overflow-x: hidden; } .main { - overflow-y: scroll; + overflow-y: auto; } .content { display: flex; From f5a7e5bf4951c5c1cc62adfb88f2d51b291fdfb4 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Mon, 24 Feb 2025 15:34:30 +0000 Subject: [PATCH 02/21] Fixing app count in user page. --- .../src/pages/builder/portal/users/users/index.svelte | 2 +- packages/shared-core/src/sdk/documents/users.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/portal/users/users/index.svelte b/packages/builder/src/pages/builder/portal/users/users/index.svelte index c77e40c964..6a1facfd01 100644 --- a/packages/builder/src/pages/builder/portal/users/users/index.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/index.svelte @@ -128,7 +128,7 @@ $auth.user?.email === user.email ? false : true, - apps: [...new Set(Object.keys(user.roles))], + apps: sdk.users.userAppAccessList(user, $groups), access: role.sortOrder, } }) diff --git a/packages/shared-core/src/sdk/documents/users.ts b/packages/shared-core/src/sdk/documents/users.ts index 17aa8a1e58..c4f1a16025 100644 --- a/packages/shared-core/src/sdk/documents/users.ts +++ b/packages/shared-core/src/sdk/documents/users.ts @@ -4,6 +4,7 @@ import { SEPARATOR, User, InternalTable, + UserGroup, } from "@budibase/types" import { getProdAppID } from "./applications" import * as _ from "lodash/fp" @@ -129,3 +130,13 @@ export function containsUserID(value: string | undefined): boolean { } return value.includes(`${DocumentType.USER}${SEPARATOR}`) } + +export function userAppAccessList(user: User, groups?: UserGroup[]) { + const userGroups = + groups?.filter(group => group.users?.find(u => u._id === user._id)) || [] + const userGroupApps = userGroups.flatMap(userGroup => + Object.keys(userGroup.roles || {}) + ) + const fullList = [...Object.keys(user.roles), ...userGroupApps] + return [...new Set(fullList)] +} From a1589b0dc05af57d65aa9ac6dda7dd81d3ea814f Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Mon, 24 Feb 2025 18:07:01 +0000 Subject: [PATCH 03/21] Adding group badges to users. --- packages/bbui/src/Badge/Badge.svelte | 2 ++ .../[application]/_components/BuilderSidePanel.svelte | 5 +++++ packages/shared-core/src/sdk/documents/users.ts | 9 +++++++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/bbui/src/Badge/Badge.svelte b/packages/bbui/src/Badge/Badge.svelte index e4ec7d4f33..03aa544dfe 100644 --- a/packages/bbui/src/Badge/Badge.svelte +++ b/packages/bbui/src/Badge/Badge.svelte @@ -11,6 +11,7 @@ export let active = false export let inactive = false export let hoverable = false + export let customColor = null </script> <!-- svelte-ignore a11y-no-static-element-interactions --> @@ -29,6 +30,7 @@ class:spectrum-Label--seafoam={seafoam} class:spectrum-Label--active={active} class:spectrum-Label--inactive={inactive} + style={customColor ? `background-color: ${customColor};` : ""} > <slot /> </span> diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 2260892913..5b1bf852aa 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -13,6 +13,7 @@ FancyInput, Button, FancySelect, + Badge, } from "@budibase/bbui" import { builderStore, appStore, roles, appPublished } from "@/stores/builder" import { @@ -741,11 +742,15 @@ <div class="auth-entity-access-title">Access</div> </div> {#each allUsers as user} + {@const userGroups = sdk.users.getUserGroups(user, $groups)} <div class="auth-entity"> <div class="details"> <div class="user-email" title={user.email}> {user.email} </div> + {#each userGroups as group} + <Badge size="S" customColor={group.color}>{group.name}</Badge> + {/each} </div> <div class="auth-entity-access" class:muted={user.group}> <RoleSelect diff --git a/packages/shared-core/src/sdk/documents/users.ts b/packages/shared-core/src/sdk/documents/users.ts index c4f1a16025..8b5abfd822 100644 --- a/packages/shared-core/src/sdk/documents/users.ts +++ b/packages/shared-core/src/sdk/documents/users.ts @@ -131,9 +131,14 @@ export function containsUserID(value: string | undefined): boolean { return value.includes(`${DocumentType.USER}${SEPARATOR}`) } -export function userAppAccessList(user: User, groups?: UserGroup[]) { - const userGroups = +export function getUserGroups(user: User, groups?: UserGroup[]) { + return ( groups?.filter(group => group.users?.find(u => u._id === user._id)) || [] + ) +} + +export function userAppAccessList(user: User, groups?: UserGroup[]) { + const userGroups = getUserGroups(user, groups) const userGroupApps = userGroups.flatMap(userGroup => Object.keys(userGroup.roles || {}) ) From f7d216c188562cf793673e04d3a17e5face33264 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Mon, 24 Feb 2025 18:08:20 +0000 Subject: [PATCH 04/21] Setting override placeholder. --- .../app/[application]/_components/BuilderSidePanel.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 5b1bf852aa..a9d3bb70ba 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -755,7 +755,7 @@ <div class="auth-entity-access" class:muted={user.group}> <RoleSelect footer={getRoleFooter(user)} - placeholder={false} + placeholder={userGroups?.length ? "Override" : false} value={parseRole(user)} allowRemove={user.role && !user.group} allowPublic={false} From b7f34b5f57408c111f2165301e21486fe3d34492 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Tue, 25 Feb 2025 10:45:50 +0000 Subject: [PATCH 05/21] Changing how badges are displayed. --- .../_components/BuilderSidePanel.svelte | 27 ++++++++++++++----- .../shared-core/src/sdk/documents/users.ts | 12 +++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index a9d3bb70ba..8136dd256c 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -742,15 +742,19 @@ <div class="auth-entity-access-title">Access</div> </div> {#each allUsers as user} - {@const userGroups = sdk.users.getUserGroups(user, $groups)} + {@const userGroups = sdk.users.getUserAppGroups($appStore.appId, user, $groups)} <div class="auth-entity"> <div class="details"> - <div class="user-email" title={user.email}> - {user.email} + <div class="user-groups"> + <div class="user-email" title={user.email}> + {user.email} + </div> + <div class="group-badges"> + {#each userGroups as group} + <Badge size="S" customColor={group.color}>{group.name}</Badge> + {/each} + </div> </div> - {#each userGroups as group} - <Badge size="S" customColor={group.color}>{group.name}</Badge> - {/each} </div> <div class="auth-entity-access" class:muted={user.group}> <RoleSelect @@ -1053,4 +1057,15 @@ .alert { padding: 0 var(--spacing-xl); } + + .user-groups { + display: flex; + flex-direction: column; + } + .group-badges { + padding-top: var(--spacing-s); + display: flex; + gap: var(--spacing-s); + flex-wrap: wrap; + } </style> diff --git a/packages/shared-core/src/sdk/documents/users.ts b/packages/shared-core/src/sdk/documents/users.ts index 8b5abfd822..d2ee2dec00 100644 --- a/packages/shared-core/src/sdk/documents/users.ts +++ b/packages/shared-core/src/sdk/documents/users.ts @@ -137,6 +137,18 @@ export function getUserGroups(user: User, groups?: UserGroup[]) { ) } +export function getUserAppGroups( + appId: string, + user: User, + groups?: UserGroup[] +) { + const prodAppId = getProdAppID(appId) + const userGroups = getUserGroups(user, groups) + return userGroups.filter(group => + Object.keys(group.roles || {}).find(app => app === prodAppId) + ) +} + export function userAppAccessList(user: User, groups?: UserGroup[]) { const userGroups = getUserGroups(user, groups) const userGroupApps = userGroups.flatMap(userGroup => From df102e7b6b6e9e518bfec8907eba79782f06b551 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Tue, 25 Feb 2025 17:18:27 +0000 Subject: [PATCH 06/21] Opacity of group badges. --- packages/bbui/src/Badge/Badge.svelte | 2 +- .../app/[application]/_components/BuilderSidePanel.svelte | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/bbui/src/Badge/Badge.svelte b/packages/bbui/src/Badge/Badge.svelte index 03aa544dfe..15bb6c62c2 100644 --- a/packages/bbui/src/Badge/Badge.svelte +++ b/packages/bbui/src/Badge/Badge.svelte @@ -30,7 +30,7 @@ class:spectrum-Label--seafoam={seafoam} class:spectrum-Label--active={active} class:spectrum-Label--inactive={inactive} - style={customColor ? `background-color: ${customColor};` : ""} + style={customColor ? `background-color: ${customColor}` : ""} > <slot /> </span> diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 8136dd256c..ff4b872153 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -742,7 +742,7 @@ <div class="auth-entity-access-title">Access</div> </div> {#each allUsers as user} - {@const userGroups = sdk.users.getUserAppGroups($appStore.appId, user, $groups)} + {@const userGroups = sdk.users.getUserAppGroups($appStore.appId, user, $groups).slice(0, 3)} <div class="auth-entity"> <div class="details"> <div class="user-groups"> @@ -751,7 +751,7 @@ </div> <div class="group-badges"> {#each userGroups as group} - <Badge size="S" customColor={group.color}>{group.name}</Badge> + <Badge size="S" customColor={`color-mix(in srgb, ${group.color} 30%, transparent)`}>{group.name}</Badge> {/each} </div> </div> @@ -949,6 +949,8 @@ grid-template-columns: 1fr 220px; align-items: center; gap: var(--spacing-xl); + border-bottom: var(--border-light); + padding-bottom: var(--spacing-s); } .auth-entity .details { From c3de44a6a9270fba6b8184ed379fa4b304ba4efe Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Tue, 25 Feb 2025 18:17:41 +0000 Subject: [PATCH 07/21] Adding a way to limit the groups shown and then display a popover. --- packages/bbui/src/Icon/Icon.svelte | 3 ++ .../_components/BuilderGroupPopover.svelte | 49 +++++++++++++++++++ .../_components/BuilderSidePanel.svelte | 15 ++++-- .../_components/GroupBadge.svelte | 10 ++++ 4 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/_components/GroupBadge.svelte diff --git a/packages/bbui/src/Icon/Icon.svelte b/packages/bbui/src/Icon/Icon.svelte index 2f12935f53..46b3140be8 100644 --- a/packages/bbui/src/Icon/Icon.svelte +++ b/packages/bbui/src/Icon/Icon.svelte @@ -28,6 +28,9 @@ <svg on:contextmenu on:click + on:mouseover + on:mouseleave + on:focus class:hoverable class:disabled class="spectrum-Icon spectrum-Icon--size{size}" diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte new file mode 100644 index 0000000000..47811cbcb9 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte @@ -0,0 +1,49 @@ +<script> + import { Icon, Popover } from "@budibase/bbui" + import GroupBadge from "./GroupBadge.svelte" + + export let groups = [] + + let anchor, popover + + function show() { + popover.show() + } + + function hide() { + popover.hide() + } +</script> + +<div class="icon" bind:this={anchor}> + <Icon name="More" size="S" hoverable on:mouseover={show} on:mouseleave={hide} /> +</div> + +<Popover + customZIndex={1002} + bind:this={popover} + align="center" + {anchor} + showPopover={true} + minWidth={0} +> + <div class="badges"> + {#each groups as group} + <GroupBadge color={group.color} name={group.name} /> + {/each} + </div> +</Popover> + +<style> + .icon { + height: auto; + display: flex; + justify-content: center; + } + .badges { + display: flex; + flex-wrap: wrap; + gap: var(--spacing-s); + padding: var(--spacing-m); + } +</style> diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index ff4b872153..11a36706cf 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -38,6 +38,8 @@ 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" + import GroupBadge from "./GroupBadge.svelte" let query = null let loaded = false @@ -742,7 +744,11 @@ <div class="auth-entity-access-title">Access</div> </div> {#each allUsers as user} - {@const userGroups = sdk.users.getUserAppGroups($appStore.appId, user, $groups).slice(0, 3)} + {@const userGroups = sdk.users.getUserAppGroups( + $appStore.appId, + user, + $groups + )} <div class="auth-entity"> <div class="details"> <div class="user-groups"> @@ -750,9 +756,12 @@ {user.email} </div> <div class="group-badges"> - {#each userGroups as group} - <Badge size="S" customColor={`color-mix(in srgb, ${group.color} 30%, transparent)`}>{group.name}</Badge> + {#each userGroups.slice(0, 3) as group} + <GroupBadge color={group.color} name={group.name} /> {/each} + {#if userGroups.length > 3} + <BuilderGroupPopover groups={userGroups.slice(3)} /> + {/if} </div> </div> </div> diff --git a/packages/builder/src/pages/builder/app/[application]/_components/GroupBadge.svelte b/packages/builder/src/pages/builder/app/[application]/_components/GroupBadge.svelte new file mode 100644 index 0000000000..f10e2aa220 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/_components/GroupBadge.svelte @@ -0,0 +1,10 @@ +<script> + import { Badge } from "@budibase/bbui" + + export let color + export let name +</script> + +<Badge size="S" customColor={`color-mix(in srgb, ${color} 30%, transparent)`} + >{name}</Badge +> From 336bc72de27860e8941e3a984929d2b83062de01 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Wed, 26 Feb 2025 12:53:18 +0000 Subject: [PATCH 08/21] Design after discussion with Cheeks and Joe. --- packages/bbui/src/Badge/Badge.svelte | 4 +- .../_components/BuilderGroupPopover.svelte | 41 +++------------- .../_components/BuilderSidePanel.svelte | 48 ++++++++++--------- .../_components/GroupBadge.svelte | 10 ---- packages/shared-core/src/helpers/index.ts | 1 + packages/shared-core/src/helpers/lists.ts | 7 +++ 6 files changed, 43 insertions(+), 68 deletions(-) delete mode 100644 packages/builder/src/pages/builder/app/[application]/_components/GroupBadge.svelte create mode 100644 packages/shared-core/src/helpers/lists.ts diff --git a/packages/bbui/src/Badge/Badge.svelte b/packages/bbui/src/Badge/Badge.svelte index 15bb6c62c2..dadbaa3317 100644 --- a/packages/bbui/src/Badge/Badge.svelte +++ b/packages/bbui/src/Badge/Badge.svelte @@ -11,7 +11,7 @@ export let active = false export let inactive = false export let hoverable = false - export let customColor = null + export let outlineColor = null </script> <!-- svelte-ignore a11y-no-static-element-interactions --> @@ -30,7 +30,7 @@ class:spectrum-Label--seafoam={seafoam} class:spectrum-Label--active={active} class:spectrum-Label--inactive={inactive} - style={customColor ? `background-color: ${customColor}` : ""} + style={outlineColor ? `border: 2px solid ${outlineColor}` : ""} > <slot /> </span> diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte index 47811cbcb9..43c662a6d2 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte @@ -1,49 +1,22 @@ <script> - import { Icon, Popover } from "@budibase/bbui" - import GroupBadge from "./GroupBadge.svelte" + import { Icon } from "@budibase/bbui" + import { helpers } from "@budibase/shared-core" export let groups = [] - - let anchor, popover - - function show() { - popover.show() - } - - function hide() { - popover.hide() + function tooltip(groups) { + const sortedNames = groups.sort((a, b) => a.name.localeCompare(b.name)).map(group => group.name) + return `Member of ${helpers.lists.punctuateList(sortedNames)}` } </script> -<div class="icon" bind:this={anchor}> - <Icon name="More" size="S" hoverable on:mouseover={show} on:mouseleave={hide} /> +<div class="icon"> + <Icon name="Info" size="XS" color="grey" hoverable tooltip={tooltip(groups)} tooltipPosition="top" /> </div> -<Popover - customZIndex={1002} - bind:this={popover} - align="center" - {anchor} - showPopover={true} - minWidth={0} -> - <div class="badges"> - {#each groups as group} - <GroupBadge color={group.color} name={group.name} /> - {/each} - </div> -</Popover> - <style> .icon { height: auto; display: flex; justify-content: center; } - .badges { - display: flex; - flex-wrap: wrap; - gap: var(--spacing-s); - padding: var(--spacing-m); - } </style> diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 11a36706cf..0bf32e4b76 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -13,7 +13,6 @@ FancyInput, Button, FancySelect, - Badge, } from "@budibase/bbui" import { builderStore, appStore, roles, appPublished } from "@/stores/builder" import { @@ -39,7 +38,6 @@ import { fly } from "svelte/transition" import InfoDisplay from "../design/[screenId]/[componentId]/_components/Component/InfoDisplay.svelte" import BuilderGroupPopover from "./BuilderGroupPopover.svelte" - import GroupBadge from "./GroupBadge.svelte" let query = null let loaded = false @@ -542,6 +540,12 @@ creationAccessType = Constants.Roles.CREATOR } } + + const itemCountText = (word, count) => { + return `${count} ${word}${ + count !== 1 ? "s" : "" + }` + } </script> <svelte:window on:keydown={handleKeyDown} /> @@ -708,9 +712,7 @@ {group.name} </div> <div class="auth-entity-meta"> - {`${group.users?.length} user${ - group.users?.length != 1 ? "s" : "" - }`} + {itemCountText("user", group.users?.length)} </div> </div> <div class="auth-entity-access"> @@ -755,20 +757,20 @@ <div class="user-email" title={user.email}> {user.email} </div> - <div class="group-badges"> - {#each userGroups.slice(0, 3) as group} - <GroupBadge color={group.color} name={group.name} /> - {/each} - {#if userGroups.length > 3} - <BuilderGroupPopover groups={userGroups.slice(3)} /> - {/if} - </div> + {#if userGroups.length} + <div class="group-info"> + <div class="auth-entity-meta"> + {itemCountText("group", userGroups.length)} + </div> + <BuilderGroupPopover groups={userGroups} /> + </div> + {/if} </div> </div> <div class="auth-entity-access" class:muted={user.group}> <RoleSelect footer={getRoleFooter(user)} - placeholder={userGroups?.length ? "Override" : false} + placeholder={userGroups?.length ? "Controlled by group" : false} value={parseRole(user)} allowRemove={user.role && !user.group} allowPublic={false} @@ -949,7 +951,7 @@ .auth-entity, .auth-entity-header { - padding: 0px var(--spacing-xl); + padding: 0 var(--spacing-xl); } .auth-entity, @@ -958,8 +960,6 @@ grid-template-columns: 1fr 220px; align-items: center; gap: var(--spacing-xl); - border-bottom: var(--border-light); - padding-bottom: var(--spacing-s); } .auth-entity .details { @@ -1071,12 +1071,16 @@ .user-groups { display: flex; - flex-direction: column; + flex-direction: row; + justify-content: center; + align-items: center; + gap: var(--spacing-m); } - .group-badges { - padding-top: var(--spacing-s); + + .group-info { display: flex; - gap: var(--spacing-s); - flex-wrap: wrap; + flex-direction: row; + gap: var(--spacing-xs); + justify-content: center; } </style> diff --git a/packages/builder/src/pages/builder/app/[application]/_components/GroupBadge.svelte b/packages/builder/src/pages/builder/app/[application]/_components/GroupBadge.svelte deleted file mode 100644 index f10e2aa220..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/_components/GroupBadge.svelte +++ /dev/null @@ -1,10 +0,0 @@ -<script> - import { Badge } from "@budibase/bbui" - - export let color - export let name -</script> - -<Badge size="S" customColor={`color-mix(in srgb, ${color} 30%, transparent)`} - >{name}</Badge -> diff --git a/packages/shared-core/src/helpers/index.ts b/packages/shared-core/src/helpers/index.ts index 0aa378b46a..b924617a0f 100644 --- a/packages/shared-core/src/helpers/index.ts +++ b/packages/shared-core/src/helpers/index.ts @@ -6,3 +6,4 @@ export * as cron from "./cron" export * as schema from "./schema" export * as views from "./views" export * as roles from "./roles" +export * as lists from "./lists" diff --git a/packages/shared-core/src/helpers/lists.ts b/packages/shared-core/src/helpers/lists.ts new file mode 100644 index 0000000000..64b906fef8 --- /dev/null +++ b/packages/shared-core/src/helpers/lists.ts @@ -0,0 +1,7 @@ +export function punctuateList(list: string[]) { + if (list.length === 0) return "" + if (list.length === 1) return list[0] + if (list.length === 2) return list.join(" and ") + // For more than 2 elements: join all but the last with commas, then add "and" before the last element. + return list.slice(0, -1).join(", ") + " and " + list[list.length - 1] +} From c2841b824d5ad83a12fe777f356ae0ef55548152 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Wed, 26 Feb 2025 13:25:58 +0000 Subject: [PATCH 09/21] Linting. --- .../_components/BuilderGroupPopover.svelte | 13 +++++++++++-- .../_components/BuilderSidePanel.svelte | 8 ++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte index 43c662a6d2..367d84e029 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderGroupPopover.svelte @@ -4,13 +4,22 @@ export let groups = [] function tooltip(groups) { - const sortedNames = groups.sort((a, b) => a.name.localeCompare(b.name)).map(group => group.name) + const sortedNames = groups + .sort((a, b) => a.name.localeCompare(b.name)) + .map(group => group.name) return `Member of ${helpers.lists.punctuateList(sortedNames)}` } </script> <div class="icon"> - <Icon name="Info" size="XS" color="grey" hoverable tooltip={tooltip(groups)} tooltipPosition="top" /> + <Icon + name="Info" + size="XS" + color="grey" + hoverable + tooltip={tooltip(groups)} + tooltipPosition="top" + /> </div> <style> diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 0bf32e4b76..7a9b6ba7a0 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -542,9 +542,7 @@ } const itemCountText = (word, count) => { - return `${count} ${word}${ - count !== 1 ? "s" : "" - }` + return `${count} ${word}${count !== 1 ? "s" : ""}` } </script> @@ -770,7 +768,9 @@ <div class="auth-entity-access" class:muted={user.group}> <RoleSelect footer={getRoleFooter(user)} - placeholder={userGroups?.length ? "Controlled by group" : false} + placeholder={userGroups?.length + ? "Controlled by group" + : false} value={parseRole(user)} allowRemove={user.role && !user.group} allowPublic={false} From 1d35f2a029b2fcc0e37564bf8ee563bf94629c04 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Wed, 26 Feb 2025 13:41:45 +0000 Subject: [PATCH 10/21] Remove comment --- packages/shared-core/src/helpers/lists.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/shared-core/src/helpers/lists.ts b/packages/shared-core/src/helpers/lists.ts index 64b906fef8..3a2cf743a3 100644 --- a/packages/shared-core/src/helpers/lists.ts +++ b/packages/shared-core/src/helpers/lists.ts @@ -2,6 +2,5 @@ export function punctuateList(list: string[]) { if (list.length === 0) return "" if (list.length === 1) return list[0] if (list.length === 2) return list.join(" and ") - // For more than 2 elements: join all but the last with commas, then add "and" before the last element. return list.slice(0, -1).join(", ") + " and " + list[list.length - 1] } From 2022aa1c742bb8ce695d762a15fff80bc9778158 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Wed, 26 Feb 2025 15:18:43 +0000 Subject: [PATCH 11/21] Attempting to remove elasticsearch --- .github/workflows/budibase_ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 6a9aa3e8d0..5e769fc8dc 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -164,7 +164,6 @@ jobs: mariadb, oracle, sqs, - elasticsearch, none, ] steps: From 04324e6220a7c8783bcab1ed72fb84f17e397fa5 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Wed, 26 Feb 2025 15:31:17 +0000 Subject: [PATCH 12/21] Undo. --- .github/workflows/budibase_ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index 5e769fc8dc..6a9aa3e8d0 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -164,6 +164,7 @@ jobs: mariadb, oracle, sqs, + elasticsearch, none, ] steps: From 5c20b496b720f58e768ce36b4397f528e53a240c Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Thu, 27 Feb 2025 12:08:00 +0000 Subject: [PATCH 13/21] Handling long email addresses. --- .../_components/BuilderSidePanel.svelte | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 7a9b6ba7a0..16af731e02 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -966,15 +966,16 @@ display: flex; align-items: center; gap: var(--spacing-m); - color: var(--spectrum-global-color-gray-900); overflow: hidden; + width: 100%; } .auth-entity .user-email { - text-overflow: ellipsis; - white-space: nowrap; + flex: 1 1 0; + min-width: 0; overflow: hidden; - color: var(--spectrum-global-color-gray-900); + white-space: nowrap; + text-overflow: ellipsis; } #builder-side-panel-container { @@ -1072,15 +1073,19 @@ .user-groups { display: flex; flex-direction: row; - justify-content: center; + justify-content: flex-start; /* or space-between */ align-items: center; gap: var(--spacing-m); + width: 100%; + min-width: 0; } .group-info { display: flex; flex-direction: row; gap: var(--spacing-xs); - justify-content: center; + justify-content: end; + width: 60px; + flex: 0 0 auto; } </style> From 33b8751d7817b0f385cd0e9f081aad8177cd7a39 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Thu, 27 Feb 2025 12:36:42 +0000 Subject: [PATCH 14/21] Fixing users meta info for groups. --- .../app/[application]/_components/BuilderSidePanel.svelte | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 16af731e02..4a7af9342e 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -706,7 +706,7 @@ > <div class="details"> <GroupIcon {group} size="S" /> - <div> + <div class="group-name"> {group.name} </div> <div class="auth-entity-meta"> @@ -935,6 +935,7 @@ color: var(--spectrum-global-color-gray-600); font-size: 12px; white-space: nowrap; + text-align: end; } .auth-entity-access { @@ -970,7 +971,7 @@ width: 100%; } - .auth-entity .user-email { + .auth-entity .user-email, .group-name { flex: 1 1 0; min-width: 0; overflow: hidden; @@ -1073,7 +1074,7 @@ .user-groups { display: flex; flex-direction: row; - justify-content: flex-start; /* or space-between */ + justify-content: flex-start; align-items: center; gap: var(--spacing-m); width: 100%; From 4f697b7731a3e3eca298a69196383bd4f256e987 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Thu, 27 Feb 2025 17:12:20 +0000 Subject: [PATCH 15/21] Adding groups to user app list. --- .../_components/BuilderSidePanel.svelte | 3 +- .../portal/users/users/[userId].svelte | 40 ++++++++++++------- .../_components/AppRoleTableRenderer.svelte | 4 +- packages/frontend-core/src/constants.ts | 1 + 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 4a7af9342e..59d14770ae 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -971,7 +971,8 @@ width: 100%; } - .auth-entity .user-email, .group-name { + .auth-entity .user-email, + .group-name { flex: 1 1 0; min-width: 0; overflow: hidden; diff --git a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte index 6c480d9ef8..f02c2fe058 100644 --- a/packages/builder/src/pages/builder/portal/users/users/[userId].svelte +++ b/packages/builder/src/pages/builder/portal/users/users/[userId].svelte @@ -98,7 +98,9 @@ $: privileged = sdk.users.isAdminOrGlobalBuilder(user) $: nameLabel = getNameLabel(user) $: filteredGroups = getFilteredGroups(internalGroups, searchTerm) - $: availableApps = getAvailableApps($appsStore.apps, privileged, user?.roles) + $: availableApps = user + ? getApps(user, sdk.users.userAppAccessList(user, $groups || [])) + : [] $: userGroups = $groups.filter(x => { return x.users?.find(y => { return y._id === userId @@ -107,23 +109,19 @@ $: globalRole = users.getUserRole(user) $: isTenantOwner = tenantOwner?.email && tenantOwner.email === user?.email - const getAvailableApps = (appList, privileged, roles) => { - let availableApps = appList.slice() - if (!privileged) { - availableApps = availableApps.filter(x => { - let roleKeys = Object.keys(roles || {}) - return roleKeys.concat(user?.builder?.apps).find(y => { - return x.appId === appsStore.extractAppId(y) - }) - }) - } + const getApps = (user, appIds) => { + let availableApps = $appsStore.apps + .slice() + .filter(app => + appIds.find(id => id === appsStore.getProdAppID(app.devId)) + ) return availableApps.map(app => { const prodAppId = appsStore.getProdAppID(app.devId) return { name: app.name, devId: app.devId, icon: app.icon, - role: getRole(prodAppId, roles), + role: getRole(prodAppId, user), } }) } @@ -136,7 +134,7 @@ return groups.filter(group => group.name?.toLowerCase().includes(search)) } - const getRole = (prodAppId, roles) => { + const getRole = (prodAppId, user) => { if (privileged) { return Constants.Roles.ADMIN } @@ -145,7 +143,21 @@ return Constants.Roles.CREATOR } - return roles[prodAppId] + if (user?.roles[prodAppId]) { + return user.roles[prodAppId] + } + + // check if access via group for creator + const foundGroup = $groups?.find( + group => group.roles[prodAppId] || group.builder?.apps[prodAppId] + ) + if (foundGroup.builder?.apps[prodAppId]) { + return Constants.Roles.CREATOR + } + // can't tell how groups will control role + if (foundGroup.roles[prodAppId]) { + return Constants.Roles.GROUP + } } const getNameLabel = user => { diff --git a/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte b/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte index 9429cfbc23..5adc38ebc6 100644 --- a/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte +++ b/packages/builder/src/pages/builder/portal/users/users/_components/AppRoleTableRenderer.svelte @@ -15,7 +15,9 @@ } </script> -{#if value === Constants.Roles.CREATOR} +{#if value === Constants.Roles.GROUP} + Controlled by group +{:else if value === Constants.Roles.CREATOR} Can edit {:else} <StatusLight diff --git a/packages/frontend-core/src/constants.ts b/packages/frontend-core/src/constants.ts index 3e51719bfd..fdf4a8c36f 100644 --- a/packages/frontend-core/src/constants.ts +++ b/packages/frontend-core/src/constants.ts @@ -106,6 +106,7 @@ export const Roles = { PUBLIC: "PUBLIC", BUILDER: "BUILDER", CREATOR: "CREATOR", + GROUP: "GROUP", } export const EventPublishType = { From 5cd5a201772b18863176d53d558ee44452be482d Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Fri, 28 Feb 2025 15:01:34 +0000 Subject: [PATCH 16/21] Fixing an issue switching back to controlled by group. --- .../_components/BuilderSidePanel.svelte | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte index 59d14770ae..737edd69f7 100644 --- a/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_components/BuilderSidePanel.svelte @@ -198,12 +198,19 @@ return } const update = await users.get(user._id) + const newRoles = { + ...update.roles, + [prodAppId]: role, + } + // make sure no undefined/null roles (during removal) + for (let [appId, role] of Object.entries(newRoles)) { + if (!role) { + delete newRoles[appId] + } + } await users.save({ ...update, - roles: { - ...update.roles, - [prodAppId]: role, - }, + roles: newRoles, }) await searchUsers(query, $builderStore.builderSidePanel, loaded) } From 67d31b971a69e3d664606c36672c2758f51df7ab Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Fri, 28 Feb 2025 16:56:31 +0000 Subject: [PATCH 17/21] Updating master reference. --- packages/pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/pro b/packages/pro index e3843dd4ea..b28dbd5492 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit e3843dd4eaced68ae063355b77df200dbc789c98 +Subproject commit b28dbd549284cf450be7f25ad85aadf614d08f0b From ebfd8eb6c8a75e682ead8fd94d1079e11bd27c1f Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Fri, 28 Feb 2025 17:14:19 +0000 Subject: [PATCH 18/21] Fixing readme action. --- .github/workflows/readme-openapi.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/readme-openapi.yml b/.github/workflows/readme-openapi.yml index 9f42f6141b..e6224156b6 100644 --- a/.github/workflows/readme-openapi.yml +++ b/.github/workflows/readme-openapi.yml @@ -20,7 +20,7 @@ jobs: - run: yarn --frozen-lockfile - name: Install OpenAPI pkg - run: yarn global add openapi + run: yarn global add rdme openapi - name: update specs - run: cd packages/server && yarn specs && openapi specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=6728a74f5918b50036c61841 + run: cd packages/server && yarn specs && rdme openapi specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=6728a74f5918b50036c61841 From 415570b802b3eea7aa9e4d2b5a5d0b135d70eb17 Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Fri, 28 Feb 2025 17:21:57 +0000 Subject: [PATCH 19/21] Another readme action fix. --- .github/workflows/readme-openapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/readme-openapi.yml b/.github/workflows/readme-openapi.yml index e6224156b6..f7a563fc45 100644 --- a/.github/workflows/readme-openapi.yml +++ b/.github/workflows/readme-openapi.yml @@ -23,4 +23,4 @@ jobs: run: yarn global add rdme openapi - name: update specs - run: cd packages/server && yarn specs && rdme openapi specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=6728a74f5918b50036c61841 + run: cd packages/server && yarn specs && rdme openapi upload specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=6728a74f5918b50036c61841 From 4077a6df35c319bfdab9962ea7c2101388e7702c Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Fri, 28 Feb 2025 17:48:23 +0000 Subject: [PATCH 20/21] Final fix for rdme. --- .github/workflows/readme-openapi.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/readme-openapi.yml b/.github/workflows/readme-openapi.yml index f7a563fc45..ec04e4001c 100644 --- a/.github/workflows/readme-openapi.yml +++ b/.github/workflows/readme-openapi.yml @@ -20,7 +20,7 @@ jobs: - run: yarn --frozen-lockfile - name: Install OpenAPI pkg - run: yarn global add rdme openapi + run: yarn global add rdme - name: update specs - run: cd packages/server && yarn specs && rdme openapi upload specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=6728a74f5918b50036c61841 + run: cd packages/server && yarn specs && rdme openapi specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=67c16880add6da002352069a From b4ad744261a9cb47fcadf8e25af57909311900ee Mon Sep 17 00:00:00 2001 From: mike12345567 <me@michaeldrury.co.uk> Date: Fri, 28 Feb 2025 17:52:18 +0000 Subject: [PATCH 21/21] Set rdme cli version (hardcoded). --- .github/workflows/readme-openapi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/readme-openapi.yml b/.github/workflows/readme-openapi.yml index ec04e4001c..27a68e69cf 100644 --- a/.github/workflows/readme-openapi.yml +++ b/.github/workflows/readme-openapi.yml @@ -20,7 +20,7 @@ jobs: - run: yarn --frozen-lockfile - name: Install OpenAPI pkg - run: yarn global add rdme + run: yarn global add rdme@8.6.6 - name: update specs run: cd packages/server && yarn specs && rdme openapi specs/openapi.yaml --key=${{ secrets.README_API_KEY }} --id=67c16880add6da002352069a