From e3603a81d5098f2a4ca07becb4005301c1002537 Mon Sep 17 00:00:00 2001 From: Dean Date: Wed, 6 Mar 2024 09:33:17 +0000 Subject: [PATCH 1/7] App favouriting --- packages/bbui/src/Icon/Icon.svelte | 83 +++++----- packages/bbui/src/Tooltip/AbsTooltip.svelte | 5 + packages/bbui/src/index.js | 2 +- .../src/components/common/NavHeader.svelte | 4 +- .../src/components/common/NavItem.svelte | 7 +- .../src/components/deploy/AppActions.svelte | 8 +- .../src/components/deploy/DeleteModal.svelte | 4 +- .../src/components/start/AppRow.svelte | 58 ++++++- .../src/components/start/AppRowContext.svelte | 94 +++++++---- .../components/start/ChooseIconModal.svelte | 4 +- .../components/start/CreateAppModal.svelte | 4 +- .../components/start/DuplicateAppModal.svelte | 6 +- .../components/start/UpdateAppModal.svelte | 6 +- .../_components/BuilderSidePanel.svelte | 11 +- .../builder/app/[application]/_layout.svelte | 4 +- .../settings/automations/index.svelte | 6 +- .../app/[application]/settings/embed.svelte | 4 +- .../settings/exportImport.svelte | 4 +- .../settings/name-and-url.svelte | 4 +- .../src/pages/builder/apps/index.svelte | 19 ++- .../src/pages/builder/portal/_layout.svelte | 7 +- .../portal/account/auditLogs/index.svelte | 4 +- .../portal/apps/FavouriteAppButton.svelte | 29 ++++ .../portal/apps/[appId]/_layout.svelte | 4 +- .../builder/portal/apps/[appId]/index.svelte | 103 ++++++++---- .../apps/_components/PortalSideBar.svelte | 96 ++++++----- .../pages/builder/portal/apps/_layout.svelte | 11 +- .../pages/builder/portal/apps/create.svelte | 4 +- .../pages/builder/portal/apps/index.svelte | 96 +++++------ .../portal/users/groups/[groupId].svelte | 12 +- .../groups/_components/AppAddModal.svelte | 6 +- .../portal/users/users/[userId].svelte | 15 +- .../_components/AppsTableRenderer.svelte | 4 +- .../src/stores/{builder => }/BudiStore.js | 0 packages/builder/src/stores/builder/app.js | 2 +- .../builder/src/stores/builder/builder.js | 2 +- .../builder/src/stores/builder/components.js | 2 +- packages/builder/src/stores/builder/hover.js | 2 +- .../builder/src/stores/builder/layouts.js | 2 +- .../builder/src/stores/builder/navigation.js | 2 +- .../builder/src/stores/builder/screens.js | 2 +- .../builder/src/stores/builder/websocket.js | 4 +- packages/builder/src/stores/portal/apps.js | 153 ++++++++++++------ packages/builder/src/stores/portal/index.js | 2 +- packages/frontend-core/src/themes/nord.css | 2 + packages/types/src/api/web/auth.ts | 1 + packages/types/src/documents/global/user.ts | 1 + .../worker/src/api/controllers/global/self.ts | 85 +++++++++- .../worker/src/api/routes/validation/users.ts | 1 + 49 files changed, 658 insertions(+), 333 deletions(-) create mode 100644 packages/builder/src/pages/builder/portal/apps/FavouriteAppButton.svelte rename packages/builder/src/stores/{builder => }/BudiStore.js (100%) diff --git a/packages/bbui/src/Icon/Icon.svelte b/packages/bbui/src/Icon/Icon.svelte index 275c339bf4..c7261ea74d 100644 --- a/packages/bbui/src/Icon/Icon.svelte +++ b/packages/bbui/src/Icon/Icon.svelte @@ -1,58 +1,53 @@ - - - - -
(showTooltip = true)} - on:focus={() => (showTooltip = true)} - on:mouseleave={() => (showTooltip = false)} - on:click={() => (showTooltip = false)} + - - - - {#if tooltip && showTooltip} -
- -
- {/if} -
+
+ + + +
+ diff --git a/packages/builder/src/pages/builder/portal/apps/_layout.svelte b/packages/builder/src/pages/builder/portal/apps/_layout.svelte index 8810edca9c..00719dc6d5 100644 --- a/packages/builder/src/pages/builder/portal/apps/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/apps/_layout.svelte @@ -2,7 +2,7 @@ import { notifications } from "@budibase/bbui" import { admin, - apps, + appsStore, templates, licensing, groups, @@ -14,7 +14,7 @@ import PortalSideBar from "./_components/PortalSideBar.svelte" // Don't block loading if we've already hydrated state - let loaded = !!$apps?.length + let loaded = !!$appsStore.apps?.length onMount(async () => { try { @@ -34,7 +34,10 @@ } // Go to new app page if no apps exists - if (!$apps.length && sdk.users.hasBuilderPermissions($auth.user)) { + if ( + !$appsStore.apps.length && + sdk.users.hasBuilderPermissions($auth.user) + ) { $redirect("./onboarding") } } catch (error) { @@ -46,7 +49,7 @@ {#if loaded}
- {#if $apps.length > 0} + {#if $appsStore.apps.length > 0} {/if} diff --git a/packages/builder/src/pages/builder/portal/apps/create.svelte b/packages/builder/src/pages/builder/portal/apps/create.svelte index 1f2c579071..1248c41cf8 100644 --- a/packages/builder/src/pages/builder/portal/apps/create.svelte +++ b/packages/builder/src/pages/builder/portal/apps/create.svelte @@ -5,7 +5,7 @@ import CreateAppModal from "components/start/CreateAppModal.svelte" import TemplateDisplay from "components/common/TemplateDisplay.svelte" import AppLimitModal from "components/portal/licensing/AppLimitModal.svelte" - import { apps, templates, licensing } from "stores/portal" + import { appsStore, templates, licensing } from "stores/portal" import { Breadcrumbs, Breadcrumb, Header } from "components/portal/page" let template @@ -35,7 +35,7 @@ } -{#if !$apps.length} +{#if !$appsStore.apps.length} {:else} diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index a1aa242a36..c087e3cc86 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -19,10 +19,16 @@ import { automationStore, initialise } from "stores/builder" import { API } from "api" import { onMount } from "svelte" - import { apps, auth, admin, licensing, environment } from "stores/portal" + import { + appsStore, + auth, + admin, + licensing, + environment, + enriched as enrichedApps, + } from "stores/portal" import { goto } from "@roxi/routify" import AppRow from "components/start/AppRow.svelte" - import { AppStatus } from "constants" import Logo from "assets/bb-space-man.svg" let sortBy = "name" @@ -33,56 +39,27 @@ let searchTerm = "" let creatingFromTemplate = false let automationErrors - let accessFilterList = null $: welcomeHeader = `Welcome ${$auth?.user?.firstName || "back"}` - $: enrichedApps = enrichApps($apps, $auth.user, sortBy) - $: filteredApps = enrichedApps.filter( - app => - (searchTerm - ? app?.name?.toLowerCase().includes(searchTerm.toLowerCase()) - : true) && - (accessFilterList !== null - ? accessFilterList?.includes( - `${app?.type}_${app?.tenantId}_${app?.appId}` - ) - : true) - ) - $: automationErrors = getAutomationErrors(enrichedApps) + $: filteredApps = filterApps($enrichedApps, searchTerm) + $: automationErrors = getAutomationErrors(filteredApps || []) $: isOwner = $auth.accountPortalAccess && $admin.cloud + const filterApps = (apps, searchTerm) => { + return apps?.filter(app => { + const query = searchTerm?.trim()?.replace(/\s/g, "") + if (query) { + return app?.name?.toLowerCase().includes(query.toLowerCase()) + } else { + return true + } + }) + } + const usersLimitLockAction = $licensing?.errUserLimit ? () => accountLockedModal.show() : null - const enrichApps = (apps, user, sortBy) => { - const enrichedApps = apps.map(app => ({ - ...app, - deployed: app.status === AppStatus.DEPLOYED, - lockedYou: app.lockedBy && app.lockedBy.email === user?.email, - lockedOther: app.lockedBy && app.lockedBy.email !== user?.email, - })) - - if (sortBy === "status") { - return enrichedApps.sort((a, b) => { - if (a.status === b.status) { - return a.name?.toLowerCase() < b.name?.toLowerCase() ? -1 : 1 - } - return a.status === AppStatus.DEPLOYED ? -1 : 1 - }) - } else if (sortBy === "updated") { - return enrichedApps.sort((a, b) => { - const aUpdated = a.updatedAt || "9999" - const bUpdated = b.updatedAt || "9999" - return aUpdated < bUpdated ? 1 : -1 - }) - } else { - return enrichedApps.sort((a, b) => { - return a.name?.toLowerCase() < b.name?.toLowerCase() ? -1 : 1 - }) - } - } - const getAutomationErrors = apps => { const automationErrors = {} for (let app of apps) { @@ -117,7 +94,7 @@ const initiateAppCreation = async () => { if ($licensing?.usageMetrics?.apps >= 100) { appLimitModal.show() - } else if ($apps?.length) { + } else if ($appsStore.apps?.length) { $goto("/builder/portal/apps/create") } else { template = null @@ -136,7 +113,7 @@ const templateKey = template.key.split("/")[1] let appName = templateKey.replace(/-/g, " ") - const appsWithSameName = $apps.filter(app => + const appsWithSameName = $appsStore.apps.filter(app => app.name?.startsWith(appName) ) appName = `${appName} ${appsWithSameName.length + 1}` @@ -217,7 +194,7 @@ : "View error"} on:dismiss={async () => { await automationStore.actions.clearLogErrors({ appId }) - await apps.load() + await appsStore.load() }} message={automationErrorMessage(appId)} /> @@ -233,7 +210,7 @@
- {#if enrichedApps.length} + {#if $appsStore.apps.length}
{#if $auth.user && sdk.users.canCreateApps($auth.user)} @@ -245,7 +222,7 @@ > Create new app - {#if $apps?.length > 0 && !$admin.offlineMode} + {#if $appsStore.apps?.length > 0 && !$admin.offlineMode}