Merge branch 'master' into BUDI-8986/validate-datasource-setting-on-components

This commit is contained in:
Adria Navarro 2025-01-23 11:31:55 +01:00 committed by GitHub
commit d0516f807a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 169 additions and 174 deletions

View File

@ -1,6 +1,6 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "3.3.0",
"version": "3.3.1",
"npmClient": "yarn",
"concurrency": 20,
"command": {

View File

@ -20,7 +20,7 @@
const processModals = () => {
const defaultCacheFn = key => {
temporalStore.actions.setExpiring(key, {}, oneDayInSeconds)
temporalStore.setExpiring(key, {}, oneDayInSeconds)
}
const dismissableModals = [
@ -50,7 +50,7 @@
},
]
return dismissableModals.filter(modal => {
return !temporalStore.actions.getExpiring(modal.key) && modal.criteria()
return !temporalStore.getExpiring(modal.key) && modal.criteria()
})
}

View File

@ -6,7 +6,7 @@ import { BANNER_TYPES } from "@budibase/bbui"
const oneDayInSeconds = 86400
const defaultCacheFn = key => {
temporalStore.actions.setExpiring(key, {}, oneDayInSeconds)
temporalStore.setExpiring(key, {}, oneDayInSeconds)
}
const upgradeAction = key => {
@ -148,7 +148,7 @@ export const getBanners = () => {
buildUsersAboveLimitBanner(ExpiringKeys.LICENSING_USERS_ABOVE_LIMIT_BANNER),
].filter(licensingBanner => {
return (
!temporalStore.actions.getExpiring(licensingBanner.key) &&
!temporalStore.getExpiring(licensingBanner.key) &&
licensingBanner.criteria()
)
})

View File

@ -11,7 +11,7 @@ export const datasourceSelect = {
},
viewV2: (view, datasources) => {
const datasource = datasources
.filter(f => f.entities)
?.filter(f => f.entities)
.flatMap(d => d.entities)
.find(ds => ds._id === view.tableId)
return {

View File

@ -18,7 +18,7 @@
$: useAccountPortal = cloud && !$admin.disableAccountPortal
navigation.actions.init($redirect)
navigation.init($redirect)
const validateTenantId = async () => {
const host = window.location.host

View File

@ -1,5 +1,5 @@
import { it, expect, describe, beforeEach, vi } from "vitest"
import { createAdminStore } from "./admin"
import { AdminStore } from "./admin"
import { writable, get } from "svelte/store"
import { API } from "@/api"
import { auth } from "@/stores/portal"
@ -46,16 +46,7 @@ describe("admin store", () => {
ctx.writableReturn = { update: vi.fn(), subscribe: vi.fn() }
writable.mockReturnValue(ctx.writableReturn)
ctx.returnedStore = createAdminStore()
})
it("returns the created store", ctx => {
expect(ctx.returnedStore).toEqual({
subscribe: expect.toBe(ctx.writableReturn.subscribe),
init: expect.toBeFunc(),
unload: expect.toBeFunc(),
getChecklist: expect.toBeFunc(),
})
ctx.returnedStore = new AdminStore()
})
describe("init method", () => {

View File

@ -1,4 +1,4 @@
import { writable, get } from "svelte/store"
import { get } from "svelte/store"
import { API } from "@/api"
import { auth } from "@/stores/portal"
import { banner } from "@budibase/bbui"
@ -7,42 +7,44 @@ import {
GetEnvironmentResponse,
SystemStatusResponse,
} from "@budibase/types"
import { BudiStore } from "../BudiStore"
interface PortalAdminStore extends GetEnvironmentResponse {
interface AdminState extends GetEnvironmentResponse {
loaded: boolean
checklist?: ConfigChecklistResponse
status?: SystemStatusResponse
}
export function createAdminStore() {
const admin = writable<PortalAdminStore>({
loaded: false,
multiTenancy: false,
cloud: false,
isDev: false,
disableAccountPortal: false,
offlineMode: false,
maintenance: [],
})
export class AdminStore extends BudiStore<AdminState> {
constructor() {
super({
loaded: false,
multiTenancy: false,
cloud: false,
isDev: false,
disableAccountPortal: false,
offlineMode: false,
maintenance: [],
})
}
async function init() {
await getChecklist()
await getEnvironment()
async init() {
await this.getChecklist()
await this.getEnvironment()
// enable system status checks in the cloud
if (get(admin).cloud) {
await getSystemStatus()
checkStatus()
if (get(this.store).cloud) {
await this.getSystemStatus()
this.checkStatus()
}
admin.update(store => {
this.update(store => {
store.loaded = true
return store
})
}
async function getEnvironment() {
async getEnvironment() {
const environment = await API.getEnvironment()
admin.update(store => {
this.update(store => {
store.multiTenancy = environment.multiTenancy
store.cloud = environment.cloud
store.disableAccountPortal = environment.disableAccountPortal
@ -56,43 +58,36 @@ export function createAdminStore() {
})
}
const checkStatus = async () => {
const health = get(admin)?.status?.health
async checkStatus() {
const health = get(this.store).status?.health
if (!health?.passing) {
await banner.showStatus()
}
}
async function getSystemStatus() {
async getSystemStatus() {
const status = await API.getSystemStatus()
admin.update(store => {
this.update(store => {
store.status = status
return store
})
}
async function getChecklist() {
async getChecklist() {
const tenantId = get(auth).tenantId
const checklist = await API.getChecklist(tenantId)
admin.update(store => {
this.update(store => {
store.checklist = checklist
return store
})
}
function unload() {
admin.update(store => {
unload() {
this.update(store => {
store.loaded = false
return store
})
}
return {
subscribe: admin.subscribe,
init,
unload,
getChecklist,
}
}
export const admin = createAdminStore()
export const admin = new AdminStore()

View File

@ -13,7 +13,7 @@ interface PortalAuditLogsStore {
logs?: SearchAuditLogsResponse
}
export class AuditLogsStore extends BudiStore<PortalAuditLogsStore> {
class AuditLogsStore extends BudiStore<PortalAuditLogsStore> {
constructor() {
super({})
}

View File

@ -1,38 +1,31 @@
import { writable } from "svelte/store"
import { BudiStore } from "../BudiStore"
type GotoFuncType = (path: string) => void
interface PortalNavigationStore {
interface NavigationState {
initialisated: boolean
goto: GotoFuncType
}
export function createNavigationStore() {
const store = writable<PortalNavigationStore>({
initialisated: false,
goto: undefined as any,
})
const { set, subscribe } = store
class NavigationStore extends BudiStore<NavigationState> {
constructor() {
super({
initialisated: false,
goto: undefined as any,
})
}
const init = (gotoFunc: GotoFuncType) => {
init(gotoFunc: GotoFuncType) {
if (typeof gotoFunc !== "function") {
throw new Error(
`gotoFunc must be a function, found a "${typeof gotoFunc}" instead`
)
}
set({
this.set({
initialisated: true,
goto: gotoFunc,
})
}
return {
subscribe,
actions: {
init,
},
}
}
export const navigation = createNavigationStore()
export const navigation = new NavigationStore()

View File

@ -1,16 +0,0 @@
import { writable } from "svelte/store"
import { API } from "@/api"
export function templatesStore() {
const { subscribe, set } = writable([])
return {
subscribe,
load: async () => {
const templates = await API.getAppTemplates()
set(templates)
},
}
}
export const templates = templatesStore()

View File

@ -0,0 +1,16 @@
import { API } from "@/api"
import { BudiStore } from "../BudiStore"
import { TemplateMetadata } from "@budibase/types"
class TemplateStore extends BudiStore<TemplateMetadata[]> {
constructor() {
super([])
}
async load() {
const templates = await API.getAppTemplates()
this.set(templates)
}
}
export const templates = new TemplateStore()

View File

@ -1,45 +0,0 @@
import { createLocalStorageStore } from "@budibase/frontend-core"
import { get } from "svelte/store"
export const createTemporalStore = () => {
const initialValue = {}
const localStorageKey = `bb-temporal`
const store = createLocalStorageStore(localStorageKey, initialValue)
const setExpiring = (key, data, duration) => {
const updated = {
...data,
expiry: Date.now() + duration * 1000,
}
store.update(state => ({
...state,
[key]: updated,
}))
}
const getExpiring = key => {
const entry = get(store)[key]
if (!entry) {
return
}
const currentExpiry = entry.expiry
if (currentExpiry < Date.now()) {
store.update(state => {
delete state[key]
return state
})
return null
} else {
return entry
}
}
return {
subscribe: store.subscribe,
actions: { setExpiring, getExpiring },
}
}
export const temporalStore = createTemporalStore()

View File

@ -0,0 +1,53 @@
import { get } from "svelte/store"
import { BudiStore, PersistenceType } from "../BudiStore"
type TemporalItem = Record<string, any> & { expiry: number }
type TemporalState = Record<string, TemporalItem>
class TemporalStore extends BudiStore<TemporalState> {
constructor() {
super(
{},
{
persistence: {
key: "bb-temporal",
type: PersistenceType.LOCAL,
},
}
)
}
setExpiring = (
key: string,
data: Record<string, any>,
durationSeconds: number
) => {
const updated: TemporalItem = {
...data,
expiry: Date.now() + durationSeconds * 1000,
}
this.update(state => ({
...state,
[key]: updated,
}))
}
getExpiring(key: string) {
const entry = get(this.store)[key]
if (!entry) {
return null
}
const currentExpiry = entry.expiry
if (currentExpiry < Date.now()) {
this.update(state => {
delete state[key]
return state
})
return null
} else {
return entry
}
}
}
export const temporalStore = new TemporalStore()

View File

@ -1,37 +0,0 @@
import { createLocalStorageStore } from "@budibase/frontend-core"
import { derived } from "svelte/store"
import {
DefaultBuilderTheme,
ensureValidTheme,
getThemeClassNames,
ThemeOptions,
ThemeClassPrefix,
} from "@budibase/shared-core"
export const getThemeStore = () => {
const themeElement = document.documentElement
const initialValue = {
theme: DefaultBuilderTheme,
}
const store = createLocalStorageStore("bb-theme", initialValue)
const derivedStore = derived(store, $store => ({
...$store,
theme: ensureValidTheme($store.theme, DefaultBuilderTheme),
}))
// Update theme class when store changes
derivedStore.subscribe(({ theme }) => {
const classNames = getThemeClassNames(theme).split(" ")
ThemeOptions.forEach(option => {
const className = `${ThemeClassPrefix}${option.id}`
themeElement.classList.toggle(className, classNames.includes(className))
})
})
return {
...store,
subscribe: derivedStore.subscribe,
}
}
export const themeStore = getThemeStore()

View File

@ -0,0 +1,45 @@
import { derived, Writable } from "svelte/store"
import {
DefaultBuilderTheme,
ensureValidTheme,
getThemeClassNames,
ThemeOptions,
ThemeClassPrefix,
} from "@budibase/shared-core"
import { Theme } from "@budibase/types"
import { DerivedBudiStore, PersistenceType } from "../BudiStore"
interface ThemeState {
theme: Theme
}
class ThemeStore extends DerivedBudiStore<ThemeState, ThemeState> {
constructor() {
const makeDerivedStore = (store: Writable<ThemeState>) => {
return derived(store, $store => ({
...$store,
theme: ensureValidTheme($store.theme, DefaultBuilderTheme),
}))
}
super({ theme: DefaultBuilderTheme }, makeDerivedStore, {
persistence: {
key: "bb-theme",
type: PersistenceType.LOCAL,
},
})
// Update theme class when store changes
this.subscribe(({ theme }) => {
const classNames = getThemeClassNames(theme).split(" ")
ThemeOptions.forEach(option => {
const className = `${ThemeClassPrefix}${option.id}`
document.documentElement.classList.toggle(
className,
classNames.includes(className)
)
})
})
}
}
export const themeStore = new ThemeStore()