Merge pull request #15174 from Budibase/ts-portal-apps-store
Convert portal apps store to typescript
This commit is contained in:
commit
e3d2041d73
|
@ -1,8 +1,17 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable, Writable } from "svelte/store"
|
||||||
|
|
||||||
export default class BudiStore {
|
interface BudiStoreOpts {
|
||||||
constructor(init, opts) {
|
debug?: boolean
|
||||||
const store = writable({ ...init })
|
}
|
||||||
|
|
||||||
|
export default class BudiStore<T> implements Writable<T> {
|
||||||
|
store: Writable<T>
|
||||||
|
subscribe: Writable<T>["subscribe"]
|
||||||
|
update: Writable<T>["update"]
|
||||||
|
set: Writable<T>["set"]
|
||||||
|
|
||||||
|
constructor(init: T, opts?: BudiStoreOpts) {
|
||||||
|
const store = writable<T>({ ...init })
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal Svelte store
|
* Internal Svelte store
|
|
@ -1,19 +1,39 @@
|
||||||
import { derived } from "svelte/store"
|
import { derived } from "svelte/store"
|
||||||
|
// @ts-ignore
|
||||||
import { AppStatus } from "constants"
|
import { AppStatus } from "constants"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import { auth } from "./auth"
|
import { auth } from "./auth"
|
||||||
import BudiStore from "../BudiStore" // move this
|
import BudiStore from "../BudiStore"
|
||||||
|
import { App, UpdateAppRequest, User } from "@budibase/types"
|
||||||
|
|
||||||
// properties that should always come from the dev app, not the deployed
|
interface AppIdentifierMetadata {
|
||||||
const DEV_PROPS = ["updatedBy", "updatedAt"]
|
devId?: string
|
||||||
|
devRev?: string
|
||||||
export const INITIAL_APPS_STATE = {
|
prodId?: string
|
||||||
apps: [],
|
prodRev?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AppsStore extends BudiStore {
|
interface AppUIMetadata {
|
||||||
|
deployed: boolean
|
||||||
|
lockedYou: boolean
|
||||||
|
lockedOther: boolean
|
||||||
|
favourite: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StoreApp extends App, AppIdentifierMetadata {}
|
||||||
|
|
||||||
|
interface EnrichedApp extends StoreApp, AppUIMetadata {}
|
||||||
|
|
||||||
|
interface PortalAppsStore {
|
||||||
|
apps: StoreApp[]
|
||||||
|
sortBy?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AppsStore extends BudiStore<PortalAppsStore> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super({ ...INITIAL_APPS_STATE })
|
super({
|
||||||
|
apps: [],
|
||||||
|
})
|
||||||
|
|
||||||
this.extractAppId = this.extractAppId.bind(this)
|
this.extractAppId = this.extractAppId.bind(this)
|
||||||
this.getProdAppID = this.getProdAppID.bind(this)
|
this.getProdAppID = this.getProdAppID.bind(this)
|
||||||
|
@ -22,12 +42,12 @@ export class AppsStore extends BudiStore {
|
||||||
this.save = this.save.bind(this)
|
this.save = this.save.bind(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
extractAppId(id) {
|
extractAppId(appId?: string) {
|
||||||
const split = id?.split("_") || []
|
const split = appId?.split("_") || []
|
||||||
return split.length ? split[split.length - 1] : null
|
return split.length ? split[split.length - 1] : null
|
||||||
}
|
}
|
||||||
|
|
||||||
getProdAppID(appId) {
|
getProdAppID(appId: string) {
|
||||||
if (!appId) {
|
if (!appId) {
|
||||||
return appId
|
return appId
|
||||||
}
|
}
|
||||||
|
@ -47,15 +67,15 @@ export class AppsStore extends BudiStore {
|
||||||
return `app${separator}${rest}`
|
return `app${separator}${rest}`
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSort(sortBy) {
|
async updateSort(sortBy: string) {
|
||||||
this.update(state => ({
|
this.update(state => ({
|
||||||
...state,
|
...state,
|
||||||
sortBy,
|
sortBy,
|
||||||
}))
|
}))
|
||||||
this.updateUserSort(sortBy)
|
await this.updateUserSort(sortBy)
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateUserSort(sortBy) {
|
async updateUserSort(sortBy: string) {
|
||||||
try {
|
try {
|
||||||
await auth.updateSelf({ appSort: sortBy })
|
await auth.updateSelf({ appSort: sortBy })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -64,16 +84,19 @@ export class AppsStore extends BudiStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
const json = await API.getApps()
|
const json = (await API.getApps()) as App[]
|
||||||
if (Array.isArray(json)) {
|
if (Array.isArray(json)) {
|
||||||
// Merge apps into one sensible list
|
// Merge apps into one sensible list
|
||||||
let appMap = {}
|
let appMap: Record<string, StoreApp> = {}
|
||||||
let devApps = json.filter(app => app.status === AppStatus.DEV)
|
let devApps = json.filter(app => app.status === AppStatus.DEV)
|
||||||
let deployedApps = json.filter(app => app.status === AppStatus.DEPLOYED)
|
let deployedApps = json.filter(app => app.status === AppStatus.DEPLOYED)
|
||||||
|
|
||||||
// First append all dev app version
|
// First append all dev app version
|
||||||
devApps.forEach(app => {
|
devApps.forEach(app => {
|
||||||
const id = this.extractAppId(app.appId)
|
const id = this.extractAppId(app.appId)
|
||||||
|
if (!id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
appMap[id] = {
|
appMap[id] = {
|
||||||
...app,
|
...app,
|
||||||
devId: app.appId,
|
devId: app.appId,
|
||||||
|
@ -84,20 +107,22 @@ export class AppsStore extends BudiStore {
|
||||||
// Then merge with all prod app versions
|
// Then merge with all prod app versions
|
||||||
deployedApps.forEach(app => {
|
deployedApps.forEach(app => {
|
||||||
const id = this.extractAppId(app.appId)
|
const id = this.extractAppId(app.appId)
|
||||||
|
if (!id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Skip any deployed apps which don't have a dev counterpart
|
// Skip any deployed apps which don't have a dev counterpart
|
||||||
if (!appMap[id]) {
|
if (!appMap[id]) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let devProps = {}
|
// Extract certain properties from the dev app to override the prod app
|
||||||
|
let devProps: Pick<App, "updatedBy" | "updatedAt"> = {}
|
||||||
if (appMap[id]) {
|
if (appMap[id]) {
|
||||||
const entries = Object.entries(appMap[id]).filter(
|
devProps = {
|
||||||
([key]) => DEV_PROPS.indexOf(key) !== -1
|
updatedBy: appMap[id].updatedBy,
|
||||||
)
|
updatedAt: appMap[id].updatedAt,
|
||||||
entries.forEach(entry => {
|
}
|
||||||
devProps[entry[0]] = entry[1]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
appMap[id] = {
|
appMap[id] = {
|
||||||
...appMap[id],
|
...appMap[id],
|
||||||
|
@ -111,7 +136,10 @@ export class AppsStore extends BudiStore {
|
||||||
// Transform into an array and clean up
|
// Transform into an array and clean up
|
||||||
const apps = Object.values(appMap)
|
const apps = Object.values(appMap)
|
||||||
apps.forEach(app => {
|
apps.forEach(app => {
|
||||||
app.appId = this.extractAppId(app.devId)
|
const appId = this.extractAppId(app.devId)
|
||||||
|
if (appId) {
|
||||||
|
app.appId = appId
|
||||||
|
}
|
||||||
delete app._id
|
delete app._id
|
||||||
delete app._rev
|
delete app._rev
|
||||||
})
|
})
|
||||||
|
@ -127,7 +155,7 @@ export class AppsStore extends BudiStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async save(appId, value) {
|
async save(appId: string, value: UpdateAppRequest) {
|
||||||
await API.saveAppMetadata(appId, value)
|
await API.saveAppMetadata(appId, value)
|
||||||
this.update(state => {
|
this.update(state => {
|
||||||
const updatedAppIndex = state.apps.findIndex(
|
const updatedAppIndex = state.apps.findIndex(
|
||||||
|
@ -146,22 +174,23 @@ export class AppsStore extends BudiStore {
|
||||||
export const appsStore = new AppsStore()
|
export const appsStore = new AppsStore()
|
||||||
|
|
||||||
export const sortBy = derived([appsStore, auth], ([$store, $auth]) => {
|
export const sortBy = derived([appsStore, auth], ([$store, $auth]) => {
|
||||||
return $store.sortBy || $auth.user?.appSort || "name"
|
return $store.sortBy || ($auth.user as User | null)?.appSort || "name"
|
||||||
})
|
})
|
||||||
|
|
||||||
// Centralise any logic that enriches the apps list
|
// Centralise any logic that enriches the apps list
|
||||||
export const enrichedApps = derived(
|
export const enrichedApps = derived(
|
||||||
[appsStore, auth, sortBy],
|
[appsStore, auth, sortBy],
|
||||||
([$store, $auth, $sortBy]) => {
|
([$store, $auth, $sortBy]) => {
|
||||||
const enrichedApps = $store.apps
|
const enrichedApps: EnrichedApp[] = $store.apps.map(app => {
|
||||||
? $store.apps.map(app => ({
|
const user = $auth.user as User | null
|
||||||
...app,
|
return {
|
||||||
deployed: app.status === AppStatus.DEPLOYED,
|
...app,
|
||||||
lockedYou: app.lockedBy && app.lockedBy.email === $auth.user?.email,
|
deployed: app.status === AppStatus.DEPLOYED,
|
||||||
lockedOther: app.lockedBy && app.lockedBy.email !== $auth.user?.email,
|
lockedYou: app.lockedBy != null && app.lockedBy.email === user?.email,
|
||||||
favourite: $auth.user?.appFavourites?.includes(app.appId),
|
lockedOther: app.lockedBy != null && app.lockedBy.email !== user?.email,
|
||||||
}))
|
favourite: !!user?.appFavourites?.includes(app.appId),
|
||||||
: []
|
}
|
||||||
|
})
|
||||||
|
|
||||||
if ($sortBy === "status") {
|
if ($sortBy === "status") {
|
||||||
return enrichedApps.sort((a, b) => {
|
return enrichedApps.sort((a, b) => {
|
Loading…
Reference in New Issue