Updates to improve the view development experience.

This commit is contained in:
mike12345567 2022-09-20 19:12:48 +01:00
parent 4dc24b7559
commit 34771e1ef7
6 changed files with 63 additions and 127 deletions

View File

@ -20,6 +20,7 @@ export enum ViewName {
AUTOMATION_LOGS = "automation_logs",
ACCOUNT_BY_EMAIL = "account_by_email",
PLATFORM_USERS_LOWERCASE = "platform_users_lowercase",
USER_BY_GROUP = "by_group_user",
}
export const DeprecatedViews = {

View File

@ -3,7 +3,7 @@ import { DEFAULT_TENANT_ID, Configs } from "../constants"
import env from "../environment"
import { SEPARATOR, DocumentType, UNICODE_MAX, ViewName } from "./constants"
import { getTenantId, getGlobalDB } from "../context"
import { getGlobalDBName } from "../tenancy/utils"
import { getGlobalDBName } from "../tenancy"
import fetch from "node-fetch"
import { doWithDB, allDbs } from "./index"
import { getCouchInfo } from "./pouch"

View File

@ -36,154 +36,91 @@ async function removeDeprecated(db: PouchDB.Database, viewName: ViewName) {
}
}
export const createNewUserEmailView = async () => {
const db = getGlobalDB()
export async function createView(db: any, viewJs: string, viewName: string) {
let designDoc
try {
designDoc = await db.get(DESIGN_DB)
designDoc = (await db.get(DESIGN_DB)) as DesignDocument
} catch (err) {
// no design doc, make one
designDoc = DesignDoc()
}
const view = {
// if using variables in a map function need to inject them before use
map: `function(doc) {
if (doc._id.startsWith("${DocumentType.USER}${SEPARATOR}")) {
emit(doc.email.toLowerCase(), doc._id)
}
}`,
map: viewJs,
}
designDoc.views = {
...designDoc.views,
[ViewName.USER_BY_EMAIL]: view,
[viewName]: view,
}
await db.put(designDoc)
}
export const createAccountEmailView = async () => {
await doWithDB(
StaticDatabases.PLATFORM_INFO.name,
async (db: PouchDB.Database) => {
let designDoc
try {
designDoc = await db.get<DesignDocument>(DESIGN_DB)
} catch (err) {
// no design doc, make one
designDoc = DesignDoc()
export const createNewUserEmailView = async () => {
const db = getGlobalDB()
const viewJs = `function(doc) {
if (doc._id.startsWith("${DocumentType.USER}${SEPARATOR}")) {
emit(doc.email.toLowerCase(), doc._id)
}
const view = {
// if using variables in a map function need to inject them before use
map: `function(doc) {
}`
await createView(db, viewJs, ViewName.USER_BY_EMAIL)
}
export const createAccountEmailView = async () => {
const viewJs = `function(doc) {
if (doc._id.startsWith("${DocumentType.ACCOUNT_METADATA}${SEPARATOR}")) {
emit(doc.email.toLowerCase(), doc._id)
}
}`,
}
designDoc.views = {
...designDoc.views,
[ViewName.ACCOUNT_BY_EMAIL]: view,
}
await db.put(designDoc)
}`
await doWithDB(
StaticDatabases.PLATFORM_INFO.name,
async (db: PouchDB.Database) => {
await createView(db, viewJs, ViewName.ACCOUNT_BY_EMAIL)
}
)
}
export const createUserAppView = async () => {
const db = getGlobalDB() as PouchDB.Database
let designDoc
try {
designDoc = await db.get<DesignDocument>("_design/database")
} catch (err) {
// no design doc, make one
designDoc = DesignDoc()
}
const view = {
// if using variables in a map function need to inject them before use
map: `function(doc) {
const viewJs = `function(doc) {
if (doc._id.startsWith("${DocumentType.USER}${SEPARATOR}") && doc.roles) {
for (let prodAppId of Object.keys(doc.roles)) {
let emitted = prodAppId + "${SEPARATOR}" + doc._id
emit(emitted, null)
}
}
}`,
}
designDoc.views = {
...designDoc.views,
[ViewName.USER_BY_APP]: view,
}
await db.put(designDoc)
}`
await createView(db, viewJs, ViewName.USER_BY_APP)
}
export const createApiKeyView = async () => {
const db = getGlobalDB()
let designDoc
try {
designDoc = await db.get("_design/database")
} catch (err) {
designDoc = DesignDoc()
}
const view = {
map: `function(doc) {
const viewJs = `function(doc) {
if (doc._id.startsWith("${DocumentType.DEV_INFO}") && doc.apiKey) {
emit(doc.apiKey, doc.userId)
}
}`,
}
designDoc.views = {
...designDoc.views,
[ViewName.BY_API_KEY]: view,
}
await db.put(designDoc)
}`
await createView(db, viewJs, ViewName.BY_API_KEY)
}
export const createUserBuildersView = async () => {
const db = getGlobalDB()
let designDoc
try {
designDoc = await db.get("_design/database")
} catch (err) {
// no design doc, make one
designDoc = DesignDoc()
}
const view = {
map: `function(doc) {
const viewJs = `function(doc) {
if (doc.builder && doc.builder.global === true) {
emit(doc._id, doc._id)
}
}`,
}
designDoc.views = {
...designDoc.views,
[ViewName.USER_BY_BUILDERS]: view,
}
await db.put(designDoc)
}`
await createView(db, viewJs, ViewName.USER_BY_BUILDERS)
}
export const createPlatformUserView = async () => {
await doWithDB(
StaticDatabases.PLATFORM_INFO.name,
async (db: PouchDB.Database) => {
let designDoc
try {
designDoc = await db.get<DesignDocument>(DESIGN_DB)
} catch (err) {
// no design doc, make one
designDoc = DesignDoc()
}
const view = {
// if using variables in a map function need to inject them before use
map: `function(doc) {
const viewJs = `function(doc) {
if (doc.tenantId) {
emit(doc._id.toLowerCase(), doc._id)
}
}`,
}
designDoc.views = {
...designDoc.views,
[ViewName.PLATFORM_USERS_LOWERCASE]: view,
}
await db.put(designDoc)
}`
await doWithDB(
StaticDatabases.PLATFORM_INFO.name,
async (db: PouchDB.Database) => {
await createView(db, viewJs, ViewName.PLATFORM_USERS_LOWERCASE)
}
)
}
@ -196,7 +133,7 @@ export const queryView = async <T>(
viewName: ViewName,
params: PouchDB.Query.Options<T, T>,
db: PouchDB.Database,
CreateFuncByName: any,
createFunc: any,
opts?: QueryViewOptions
): Promise<T[] | T | undefined> => {
try {
@ -213,10 +150,9 @@ export const queryView = async <T>(
}
} catch (err: any) {
if (err != null && err.name === "not_found") {
const createFunc = CreateFuncByName[viewName]
await removeDeprecated(db, viewName)
await createFunc()
return queryView(viewName, params, db, CreateFuncByName, opts)
return queryView(viewName, params, db, createFunc, opts)
} else {
throw err
}
@ -228,7 +164,7 @@ export const queryPlatformView = async <T>(
params: PouchDB.Query.Options<T, T>,
opts?: QueryViewOptions
): Promise<T[] | T | undefined> => {
const CreateFuncByName = {
const CreateFuncByName: any = {
[ViewName.ACCOUNT_BY_EMAIL]: createAccountEmailView,
[ViewName.PLATFORM_USERS_LOWERCASE]: createPlatformUserView,
}
@ -236,7 +172,8 @@ export const queryPlatformView = async <T>(
return doWithDB(
StaticDatabases.PLATFORM_INFO.name,
async (db: PouchDB.Database) => {
return queryView(viewName, params, db, CreateFuncByName, opts)
const createFn = CreateFuncByName[viewName]
return queryView(viewName, params, db, createFn, opts)
}
)
}
@ -247,7 +184,7 @@ export const queryGlobalView = async <T>(
db?: PouchDB.Database,
opts?: QueryViewOptions
): Promise<T[] | T | undefined> => {
const CreateFuncByName = {
const CreateFuncByName: any = {
[ViewName.USER_BY_EMAIL]: createNewUserEmailView,
[ViewName.BY_API_KEY]: createApiKeyView,
[ViewName.USER_BY_BUILDERS]: createUserBuildersView,
@ -257,5 +194,6 @@ export const queryGlobalView = async <T>(
if (!db) {
db = getGlobalDB() as PouchDB.Database
}
return queryView(viewName, params, db, CreateFuncByName, opts)
const createFn = CreateFuncByName[viewName]
return queryView(viewName, params, db, createFn, opts)
}

View File

@ -1,15 +1,12 @@
import { auth } from "../stores/portal"
import { get } from "svelte/store"
export const FEATURE_FLAGS = {
export const TENANT_FEATURE_FLAGS = {
LICENSING: "LICENSING",
USER_GROUPS: "USER_GROUPS",
}
export const isEnabled = featureFlag => {
const user = get(auth).user
if (user?.featureFlags?.includes(featureFlag)) {
return true
}
return false
return !!user?.featureFlags?.includes(featureFlag)
}

View File

@ -19,7 +19,7 @@
import ChangePasswordModal from "components/settings/ChangePasswordModal.svelte"
import UpdateAPIKeyModal from "components/settings/UpdateAPIKeyModal.svelte"
import Logo from "assets/bb-emblem.svg"
import { isEnabled, FEATURE_FLAGS } from "../../../helpers/featureFlags"
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
let loaded = false
let userInfoModal
@ -44,7 +44,7 @@
href: "/builder/portal/manage/users",
heading: "Manage",
},
isEnabled(FEATURE_FLAGS.USER_GROUPS)
isEnabled(TENANT_FEATURE_FLAGS.USER_GROUPS)
? {
title: "User Groups",
href: "/builder/portal/manage/groups",
@ -103,7 +103,7 @@
])
}
if (isEnabled(FEATURE_FLAGS.LICENSING)) {
if (isEnabled(TENANT_FEATURE_FLAGS.LICENSING)) {
// always show usage in self-host or cloud if licensing enabled
menu = menu.concat([
{

View File

@ -2,7 +2,7 @@ import { derived, writable, get } from "svelte/store"
import { API } from "api"
import { admin } from "stores/portal"
import analytics from "analytics"
import { FEATURE_FLAGS } from "helpers/featureFlags"
import { TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
import { Constants } from "@budibase/frontend-core"
export function createAuthStore() {
@ -35,7 +35,7 @@ export function createAuthStore() {
isBuilder = !!user.builder?.global
groupsEnabled =
user?.license.features.includes(Constants.Features.USER_GROUPS) &&
user?.featureFlags.includes(FEATURE_FLAGS.USER_GROUPS)
user?.featureFlags.includes(TENANT_FEATURE_FLAGS.USER_GROUPS)
}
return {
user: $store.user,