Merge branch 'master' into BUDI-8986/validate-datasource-setting-on-components
This commit is contained in:
commit
d0516f807a
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
"version": "3.3.0",
|
"version": "3.3.1",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"concurrency": 20,
|
"concurrency": 20,
|
||||||
"command": {
|
"command": {
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
const processModals = () => {
|
const processModals = () => {
|
||||||
const defaultCacheFn = key => {
|
const defaultCacheFn = key => {
|
||||||
temporalStore.actions.setExpiring(key, {}, oneDayInSeconds)
|
temporalStore.setExpiring(key, {}, oneDayInSeconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
const dismissableModals = [
|
const dismissableModals = [
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
return dismissableModals.filter(modal => {
|
return dismissableModals.filter(modal => {
|
||||||
return !temporalStore.actions.getExpiring(modal.key) && modal.criteria()
|
return !temporalStore.getExpiring(modal.key) && modal.criteria()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { BANNER_TYPES } from "@budibase/bbui"
|
||||||
const oneDayInSeconds = 86400
|
const oneDayInSeconds = 86400
|
||||||
|
|
||||||
const defaultCacheFn = key => {
|
const defaultCacheFn = key => {
|
||||||
temporalStore.actions.setExpiring(key, {}, oneDayInSeconds)
|
temporalStore.setExpiring(key, {}, oneDayInSeconds)
|
||||||
}
|
}
|
||||||
|
|
||||||
const upgradeAction = key => {
|
const upgradeAction = key => {
|
||||||
|
@ -148,7 +148,7 @@ export const getBanners = () => {
|
||||||
buildUsersAboveLimitBanner(ExpiringKeys.LICENSING_USERS_ABOVE_LIMIT_BANNER),
|
buildUsersAboveLimitBanner(ExpiringKeys.LICENSING_USERS_ABOVE_LIMIT_BANNER),
|
||||||
].filter(licensingBanner => {
|
].filter(licensingBanner => {
|
||||||
return (
|
return (
|
||||||
!temporalStore.actions.getExpiring(licensingBanner.key) &&
|
!temporalStore.getExpiring(licensingBanner.key) &&
|
||||||
licensingBanner.criteria()
|
licensingBanner.criteria()
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const datasourceSelect = {
|
||||||
},
|
},
|
||||||
viewV2: (view, datasources) => {
|
viewV2: (view, datasources) => {
|
||||||
const datasource = datasources
|
const datasource = datasources
|
||||||
.filter(f => f.entities)
|
?.filter(f => f.entities)
|
||||||
.flatMap(d => d.entities)
|
.flatMap(d => d.entities)
|
||||||
.find(ds => ds._id === view.tableId)
|
.find(ds => ds._id === view.tableId)
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
$: useAccountPortal = cloud && !$admin.disableAccountPortal
|
$: useAccountPortal = cloud && !$admin.disableAccountPortal
|
||||||
|
|
||||||
navigation.actions.init($redirect)
|
navigation.init($redirect)
|
||||||
|
|
||||||
const validateTenantId = async () => {
|
const validateTenantId = async () => {
|
||||||
const host = window.location.host
|
const host = window.location.host
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { it, expect, describe, beforeEach, vi } from "vitest"
|
import { it, expect, describe, beforeEach, vi } from "vitest"
|
||||||
import { createAdminStore } from "./admin"
|
import { AdminStore } from "./admin"
|
||||||
import { writable, get } from "svelte/store"
|
import { writable, get } from "svelte/store"
|
||||||
import { API } from "@/api"
|
import { API } from "@/api"
|
||||||
import { auth } from "@/stores/portal"
|
import { auth } from "@/stores/portal"
|
||||||
|
@ -46,16 +46,7 @@ describe("admin store", () => {
|
||||||
ctx.writableReturn = { update: vi.fn(), subscribe: vi.fn() }
|
ctx.writableReturn = { update: vi.fn(), subscribe: vi.fn() }
|
||||||
writable.mockReturnValue(ctx.writableReturn)
|
writable.mockReturnValue(ctx.writableReturn)
|
||||||
|
|
||||||
ctx.returnedStore = createAdminStore()
|
ctx.returnedStore = new AdminStore()
|
||||||
})
|
|
||||||
|
|
||||||
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(),
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("init method", () => {
|
describe("init method", () => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { writable, get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { API } from "@/api"
|
import { API } from "@/api"
|
||||||
import { auth } from "@/stores/portal"
|
import { auth } from "@/stores/portal"
|
||||||
import { banner } from "@budibase/bbui"
|
import { banner } from "@budibase/bbui"
|
||||||
|
@ -7,42 +7,44 @@ import {
|
||||||
GetEnvironmentResponse,
|
GetEnvironmentResponse,
|
||||||
SystemStatusResponse,
|
SystemStatusResponse,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
|
import { BudiStore } from "../BudiStore"
|
||||||
|
|
||||||
interface PortalAdminStore extends GetEnvironmentResponse {
|
interface AdminState extends GetEnvironmentResponse {
|
||||||
loaded: boolean
|
loaded: boolean
|
||||||
checklist?: ConfigChecklistResponse
|
checklist?: ConfigChecklistResponse
|
||||||
status?: SystemStatusResponse
|
status?: SystemStatusResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createAdminStore() {
|
export class AdminStore extends BudiStore<AdminState> {
|
||||||
const admin = writable<PortalAdminStore>({
|
constructor() {
|
||||||
loaded: false,
|
super({
|
||||||
multiTenancy: false,
|
loaded: false,
|
||||||
cloud: false,
|
multiTenancy: false,
|
||||||
isDev: false,
|
cloud: false,
|
||||||
disableAccountPortal: false,
|
isDev: false,
|
||||||
offlineMode: false,
|
disableAccountPortal: false,
|
||||||
maintenance: [],
|
offlineMode: false,
|
||||||
})
|
maintenance: [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function init() {
|
async init() {
|
||||||
await getChecklist()
|
await this.getChecklist()
|
||||||
await getEnvironment()
|
await this.getEnvironment()
|
||||||
// enable system status checks in the cloud
|
// enable system status checks in the cloud
|
||||||
if (get(admin).cloud) {
|
if (get(this.store).cloud) {
|
||||||
await getSystemStatus()
|
await this.getSystemStatus()
|
||||||
checkStatus()
|
this.checkStatus()
|
||||||
}
|
}
|
||||||
|
this.update(store => {
|
||||||
admin.update(store => {
|
|
||||||
store.loaded = true
|
store.loaded = true
|
||||||
return store
|
return store
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getEnvironment() {
|
async getEnvironment() {
|
||||||
const environment = await API.getEnvironment()
|
const environment = await API.getEnvironment()
|
||||||
admin.update(store => {
|
this.update(store => {
|
||||||
store.multiTenancy = environment.multiTenancy
|
store.multiTenancy = environment.multiTenancy
|
||||||
store.cloud = environment.cloud
|
store.cloud = environment.cloud
|
||||||
store.disableAccountPortal = environment.disableAccountPortal
|
store.disableAccountPortal = environment.disableAccountPortal
|
||||||
|
@ -56,43 +58,36 @@ export function createAdminStore() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkStatus = async () => {
|
async checkStatus() {
|
||||||
const health = get(admin)?.status?.health
|
const health = get(this.store).status?.health
|
||||||
if (!health?.passing) {
|
if (!health?.passing) {
|
||||||
await banner.showStatus()
|
await banner.showStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSystemStatus() {
|
async getSystemStatus() {
|
||||||
const status = await API.getSystemStatus()
|
const status = await API.getSystemStatus()
|
||||||
admin.update(store => {
|
this.update(store => {
|
||||||
store.status = status
|
store.status = status
|
||||||
return store
|
return store
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getChecklist() {
|
async getChecklist() {
|
||||||
const tenantId = get(auth).tenantId
|
const tenantId = get(auth).tenantId
|
||||||
const checklist = await API.getChecklist(tenantId)
|
const checklist = await API.getChecklist(tenantId)
|
||||||
admin.update(store => {
|
this.update(store => {
|
||||||
store.checklist = checklist
|
store.checklist = checklist
|
||||||
return store
|
return store
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function unload() {
|
unload() {
|
||||||
admin.update(store => {
|
this.update(store => {
|
||||||
store.loaded = false
|
store.loaded = false
|
||||||
return store
|
return store
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
subscribe: admin.subscribe,
|
|
||||||
init,
|
|
||||||
unload,
|
|
||||||
getChecklist,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const admin = createAdminStore()
|
export const admin = new AdminStore()
|
||||||
|
|
|
@ -13,7 +13,7 @@ interface PortalAuditLogsStore {
|
||||||
logs?: SearchAuditLogsResponse
|
logs?: SearchAuditLogsResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AuditLogsStore extends BudiStore<PortalAuditLogsStore> {
|
class AuditLogsStore extends BudiStore<PortalAuditLogsStore> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({})
|
super({})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,31 @@
|
||||||
import { writable } from "svelte/store"
|
import { BudiStore } from "../BudiStore"
|
||||||
|
|
||||||
type GotoFuncType = (path: string) => void
|
type GotoFuncType = (path: string) => void
|
||||||
|
|
||||||
interface PortalNavigationStore {
|
interface NavigationState {
|
||||||
initialisated: boolean
|
initialisated: boolean
|
||||||
goto: GotoFuncType
|
goto: GotoFuncType
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createNavigationStore() {
|
class NavigationStore extends BudiStore<NavigationState> {
|
||||||
const store = writable<PortalNavigationStore>({
|
constructor() {
|
||||||
initialisated: false,
|
super({
|
||||||
goto: undefined as any,
|
initialisated: false,
|
||||||
})
|
goto: undefined as any,
|
||||||
const { set, subscribe } = store
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const init = (gotoFunc: GotoFuncType) => {
|
init(gotoFunc: GotoFuncType) {
|
||||||
if (typeof gotoFunc !== "function") {
|
if (typeof gotoFunc !== "function") {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`gotoFunc must be a function, found a "${typeof gotoFunc}" instead`
|
`gotoFunc must be a function, found a "${typeof gotoFunc}" instead`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
this.set({
|
||||||
set({
|
|
||||||
initialisated: true,
|
initialisated: true,
|
||||||
goto: gotoFunc,
|
goto: gotoFunc,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
subscribe,
|
|
||||||
actions: {
|
|
||||||
init,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const navigation = createNavigationStore()
|
export const navigation = new NavigationStore()
|
||||||
|
|
|
@ -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()
|
|
|
@ -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()
|
|
@ -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()
|
|
|
@ -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()
|
|
@ -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()
|
|
|
@ -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()
|
Loading…
Reference in New Issue