mirror of https://github.com/Budibase/budibase.git
39 changed files with 40 additions and 672 deletions
@ -1,231 +0,0 @@ |
|||
<script> |
|||
import { tick } from "svelte" |
|||
import Textbox from "components/common/Textbox.svelte" |
|||
import Button from "components/common/Button.svelte" |
|||
import Select from "components/common/Select.svelte" |
|||
import ActionButton from "components/common/ActionButton.svelte" |
|||
import getIcon from "components/common/icon" |
|||
import FieldView from "../../FieldView.svelte" |
|||
import { |
|||
get, |
|||
compose, |
|||
map, |
|||
join, |
|||
filter, |
|||
some, |
|||
find, |
|||
keys, |
|||
isDate, |
|||
} from "lodash/fp" |
|||
import { store, backendUiStore } from "builderStore" |
|||
import { common, hierarchy } from "../../../../../../core/src/" |
|||
import { getNode } from "components/common/core" |
|||
import { templateApi, pipe, validate } from "components/common/core" |
|||
import ErrorsBox from "components/common/ErrorsBox.svelte" |
|||
|
|||
let model |
|||
let editingField = false |
|||
let fieldToEdit |
|||
let isNewField = false |
|||
let newField |
|||
let editField |
|||
let deleteField |
|||
let onFinishedFieldEdit |
|||
let editIndex |
|||
|
|||
$: parent = model && model.parent() |
|||
$: isChildModel = parent && parent.name !== "root" |
|||
$: modelExistsInHierarchy = |
|||
$store.currentNode && getNode($store.hierarchy, $store.currentNode.nodeId) |
|||
|
|||
store.subscribe($store => { |
|||
model = $store.currentNode |
|||
const flattened = hierarchy.getFlattenedHierarchy($store.hierarchy) |
|||
|
|||
newField = () => { |
|||
isNewField = true |
|||
fieldToEdit = templateApi($store.hierarchy).getNewField("string") |
|||
editingField = true |
|||
} |
|||
|
|||
onFinishedFieldEdit = field => { |
|||
if (field) { |
|||
store.saveField(field) |
|||
} |
|||
editingField = false |
|||
} |
|||
|
|||
editField = field => { |
|||
isNewField = false |
|||
fieldToEdit = field |
|||
editingField = true |
|||
} |
|||
|
|||
deleteField = field => { |
|||
store.deleteField(field) |
|||
} |
|||
|
|||
editIndex = index => { |
|||
store.selectExistingNode(index.nodeId) |
|||
} |
|||
}) |
|||
|
|||
let getTypeOptionsValueText = value => { |
|||
if ( |
|||
value === Number.MAX_SAFE_INTEGER || |
|||
value === Number.MIN_SAFE_INTEGER || |
|||
new Date(value).getTime() === new Date(8640000000000000).getTime() || |
|||
new Date(value).getTime() === new Date(-8640000000000000).getTime() |
|||
) |
|||
return "(any)" |
|||
|
|||
if (value === null) return "(not set)" |
|||
return value |
|||
} |
|||
|
|||
const nameChanged = ev => { |
|||
const pluralName = n => `${n}s` |
|||
if (model.collectionName === "") { |
|||
model.collectionName = pluralName(ev.target.value) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<heading> |
|||
{#if !editingField} |
|||
<i class="ri-list-settings-line button--toggled" /> |
|||
<h3 class="budibase__title--3">Create / Edit Model</h3> |
|||
{:else} |
|||
<i class="ri-file-list-line button--toggled" /> |
|||
<h3 class="budibase__title--3">Create / Edit Field</h3> |
|||
{/if} |
|||
</heading> |
|||
{#if !editingField} |
|||
<div class="padding"> |
|||
<h4 class="budibase__label--big">Settings</h4> |
|||
|
|||
{#if $store.errors && $store.errors.length > 0} |
|||
<ErrorsBox errors={$store.errors} /> |
|||
{/if} |
|||
|
|||
<form on:submit|preventDefault class="uk-form-stacked"> |
|||
|
|||
<Textbox label="Name" bind:text={model.name} on:change={nameChanged} /> |
|||
{#if isChildModel} |
|||
<div> |
|||
<label class="uk-form-label">Parent</label> |
|||
<div class="uk-form-controls parent-name">{parent.name}</div> |
|||
</div> |
|||
{/if} |
|||
</form> |
|||
|
|||
<div class="table-controls"> |
|||
<span class="budibase__label--big">Fields</span> |
|||
<h4 class="hoverable new-field" on:click={newField}>Add new field</h4> |
|||
</div> |
|||
|
|||
<table class="uk-table fields-table budibase__table"> |
|||
<thead> |
|||
<tr> |
|||
<th>Edit</th> |
|||
<th>Name</th> |
|||
<th>Type</th> |
|||
<th>Values</th> |
|||
<th /> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{#each model ? model.fields : [] as field} |
|||
<tr> |
|||
<td> |
|||
<i class="ri-more-line" on:click={() => editField(field)} /> |
|||
</td> |
|||
<td> |
|||
<div>{field.name}</div> |
|||
</td> |
|||
<td>{field.type}</td> |
|||
<td>{field.typeOptions.values || ''}</td> |
|||
<td> |
|||
<i |
|||
class="ri-delete-bin-6-line hoverable" |
|||
on:click={() => deleteField(field)} /> |
|||
</td> |
|||
</tr> |
|||
{/each} |
|||
</tbody> |
|||
</table> |
|||
<div class="uk-margin"> |
|||
<ActionButton color="secondary" on:click={store.saveCurrentNode}> |
|||
Save |
|||
</ActionButton> |
|||
{#if modelExistsInHierarchy} |
|||
<ActionButton color="primary" on:click={store.newChildModel}> |
|||
Create Child Model on {model.name} |
|||
</ActionButton> |
|||
<ActionButton |
|||
color="primary" |
|||
on:click={async () => { |
|||
backendUiStore.actions.modals.show('VIEW') |
|||
await tick() |
|||
store.newChildIndex() |
|||
}}> |
|||
Create Child View on {model.name} |
|||
</ActionButton> |
|||
<ActionButton alert on:click={store.deleteCurrentNode}> |
|||
Delete |
|||
</ActionButton> |
|||
{/if} |
|||
</div> |
|||
</div> |
|||
{:else} |
|||
<FieldView |
|||
field={fieldToEdit} |
|||
onFinished={onFinishedFieldEdit} |
|||
allFields={model.fields} |
|||
store={$store} /> |
|||
{/if} |
|||
|
|||
<style> |
|||
.padding { |
|||
padding: 20px; |
|||
} |
|||
|
|||
.new-field { |
|||
font-size: 16px; |
|||
font-weight: bold; |
|||
color: var(--button-text); |
|||
} |
|||
|
|||
.fields-table { |
|||
margin: 1rem 1rem 0rem 0rem; |
|||
border-collapse: collapse; |
|||
} |
|||
|
|||
tbody > tr:hover { |
|||
background-color: var(--primary10); |
|||
} |
|||
|
|||
.table-controls { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
} |
|||
|
|||
.ri-more-line:hover { |
|||
cursor: pointer; |
|||
} |
|||
|
|||
heading { |
|||
padding: 20px 20px 0 20px; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
|
|||
h3 { |
|||
margin: 0 0 0 10px; |
|||
} |
|||
|
|||
.parent-name { |
|||
font-weight: bold; |
|||
} |
|||
</style> |
|||
@ -1,86 +0,0 @@ |
|||
const { readdir, stat, copyFile } = require("fs-extra") |
|||
const { constants } = require("fs") |
|||
const { join, basename } = require("path") |
|||
const serverConfig = require("../../../server/config")() |
|||
|
|||
const packagesFolder = ".." |
|||
|
|||
const jsFile = dir => join(dir, "index.js") |
|||
const jsMapFile = dir => join(dir, "index.js.map") |
|||
const sourceJs = jsFile("dist") |
|||
const sourceJsMap = jsMapFile("dist") |
|||
const componentsFile = "components.json" |
|||
|
|||
const appPackages = join( |
|||
packagesFolder, |
|||
"server", |
|||
serverConfig.latestPackagesFolder |
|||
) |
|||
|
|||
const publicMain = appName => |
|||
join( |
|||
appPackages, |
|||
appName, |
|||
"public", |
|||
"main", |
|||
"lib", |
|||
"node_modules", |
|||
"@budibase", |
|||
"standard-components" |
|||
) |
|||
const publicUnauth = appName => |
|||
join( |
|||
appPackages, |
|||
appName, |
|||
"public", |
|||
"unauthenticated", |
|||
"lib", |
|||
"node_modules", |
|||
"@budibase", |
|||
"standard-components" |
|||
) |
|||
const nodeModulesDist = appName => |
|||
join( |
|||
appPackages, |
|||
appName, |
|||
"node_modules", |
|||
"@budibase", |
|||
"standard-components", |
|||
"dist" |
|||
) |
|||
const nodeModules = appName => |
|||
join(appPackages, appName, "node_modules", "@budibase", "standard-components") |
|||
|
|||
;(async () => { |
|||
const apps = await readdir(appPackages) |
|||
|
|||
const copySource = file => async toDir => { |
|||
const dest = join(toDir, basename(file)) |
|||
try { |
|||
await copyFile(file, dest, constants.COPYFILE_FICLONE) |
|||
console.log(`COPIED ${file} to ${dest}`) |
|||
} catch (e) { |
|||
console.log(`COPY FAILED ${file} to ${dest}: ${e}`) |
|||
} |
|||
} |
|||
|
|||
const copySourceJs = copySource(sourceJs) |
|||
const copySourceJsMap = copySource(sourceJsMap) |
|||
const copyComponentsJson = copySource(componentsFile) |
|||
|
|||
for (let app of apps) { |
|||
if (app === ".data") continue |
|||
if (!(await stat(join(appPackages, app))).isDirectory()) continue |
|||
|
|||
await copySourceJs(nodeModulesDist(app)) |
|||
await copySourceJsMap(nodeModulesDist(app)) |
|||
|
|||
await copyComponentsJson(nodeModules(app)) |
|||
|
|||
await copySourceJs(join(publicMain(app), "dist")) |
|||
await copySourceJsMap(join(publicMain(app), "dist")) |
|||
|
|||
await copySourceJs(join(publicUnauth(app), "dist")) |
|||
await copySourceJsMap(join(publicUnauth(app), "dist")) |
|||
} |
|||
})() |
|||
@ -1,11 +0,0 @@ |
|||
const getMasterAppInternal = require("../utilities/masterAppInternal") |
|||
|
|||
module.exports = async (config, masterIsCreated) => { |
|||
const context = { config } |
|||
|
|||
if (!masterIsCreated) return context |
|||
|
|||
const master = await getMasterAppInternal(context) |
|||
context.master = master |
|||
return context |
|||
} |
|||
@ -1,12 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
const { getRecordKey } = require("./helpers") |
|||
|
|||
module.exports = async ctx => { |
|||
const indexkey = getRecordKey(ctx.params.appname, ctx.request.path) |
|||
ctx.body = await ctx.instance.indexApi.aggregates(indexkey, { |
|||
rangeStartParams: ctx.request.body.rangeStartParams, |
|||
rangeEndParams: ctx.request.body.rangeEndParams, |
|||
searchPhrase: ctx.request.body.searchPhrase, |
|||
}) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,21 +0,0 @@ |
|||
const { getAppRelativePath } = require("./helpers") |
|||
|
|||
const send = require("koa-send") |
|||
|
|||
module.exports = async (ctx, next) => { |
|||
const path = getAppRelativePath(ctx.params.appname, ctx.path) |
|||
|
|||
if (path.startsWith("/api/")) { |
|||
await next() |
|||
} else if (path.startsWith("/_shared/")) { |
|||
await send(ctx, path.replace(`/_shared/`, ""), { root: ctx.sharedPath }) |
|||
} else if ( |
|||
path.endsWith(".js") || |
|||
path.endsWith(".map") || |
|||
path.endsWith(".css") |
|||
) { |
|||
await send(ctx, path, { root: ctx.publicPath }) |
|||
} else { |
|||
await send(ctx, "/index.html", { root: ctx.publicPath }) |
|||
} |
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
const user = await ctx.master.authenticate( |
|||
ctx.sessionId, |
|||
ctx.params.appname, |
|||
ctx.request.body.username, |
|||
ctx.request.body.password |
|||
) |
|||
if (!user) { |
|||
ctx.throw(StatusCodes.UNAUTHORIZED, "invalid username or password") |
|||
} |
|||
ctx.body = user.user_json |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
await ctx.instance.authApi.changeMyPassword( |
|||
ctx.request.body.currentPassword, |
|||
ctx.request.body.newPassword |
|||
) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
const instanceApi = await ctx.master.getFullAccessInstanceApiForUsername( |
|||
ctx.params.appname, |
|||
ctx.request.body.username |
|||
) |
|||
|
|||
if (!instanceApi) { |
|||
ctx.request.status = StatusCodes.OK |
|||
return |
|||
} |
|||
|
|||
await instanceApi.authApi.createTemporaryAccess(ctx.request.body.username) |
|||
|
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,10 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
await ctx.instance.authApi.createUser( |
|||
ctx.request.body.user, |
|||
ctx.request.body.password |
|||
) |
|||
|
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
const { getRecordKey } = require("./helpers") |
|||
|
|||
module.exports = async ctx => { |
|||
await ctx.instance.recordApi.delete( |
|||
getRecordKey(ctx.params.appname, ctx.request.path) |
|||
) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
await ctx.instance.authApi.disableUser(ctx.request.body.username) |
|||
|
|||
await ctx.master.removeSessionsForUser( |
|||
ctx.params.appname, |
|||
ctx.request.body.username |
|||
) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
await ctx.instance.authApi.enableUser(ctx.request.body.username) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,9 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
ctx.body = await ctx.instance.actionApi.execute( |
|||
ctx.request.body.actionname, |
|||
ctx.request.body.parameters |
|||
) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
ctx.body = await ctx.instance.authApi.getAccessLevels() |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
const { getRecordKey } = require("./helpers") |
|||
|
|||
module.exports = async ctx => { |
|||
try { |
|||
ctx.body = await ctx.instance.recordApi.load( |
|||
getRecordKey(ctx.params.appname, ctx.request.path) |
|||
) |
|||
ctx.response.status = StatusCodes.OK |
|||
} catch (e) { |
|||
// need to be catching for 404s here
|
|||
ctx.response.status = StatusCodes.INTERAL_ERROR |
|||
ctx.response.body = e.message |
|||
} |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
ctx.body = await ctx.instance.authApi.getUsers() |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,15 +0,0 @@ |
|||
exports.getRecordKey = (appname, wholePath) => |
|||
this.getAppRelativePath(appname, wholePath) |
|||
.replace(`/api/files/`, "/") |
|||
.replace(`/api/lookup_field/`, "/") |
|||
.replace(`/api/record/`, "/") |
|||
.replace(`/api/listRecords/`, "/") |
|||
.replace(`/api/aggregates/`, "/") |
|||
|
|||
exports.getAppRelativePath = (appname, wholePath) => { |
|||
const builderInstanceRegex = new RegExp( |
|||
`\\/_builder\\/instance\\/[^\\/]*\\/[^\\/]*\\/` |
|||
) |
|||
|
|||
return wholePath.replace(builderInstanceRegex, "/").replace(`/${appname}`, "") |
|||
} |
|||
@ -1,45 +0,0 @@ |
|||
const authenticate = require("./authenticate") |
|||
const setPasswordFromTemporaryCode = require("./setPasswordFromTemporaryCode") |
|||
const createTemporaryAccess = require("./createTemporaryAccess") |
|||
const appDefault = require("./appDefault") |
|||
const changeMyPassword = require("./changeMyPassword") |
|||
const executeAction = require("./executeAction") |
|||
const createUser = require("./createUser") |
|||
const enableUser = require("./enableUser") |
|||
const disableUser = require("./disableUser") |
|||
const getUsers = require("./getUsers") |
|||
const getAccessLevels = require("./getAccessLevels") |
|||
const listRecordsGet = require("./listRecordsGet") |
|||
const listRecordsPost = require("./listRecordsPost") |
|||
const aggregatesPost = require("./aggregatesPost") |
|||
const postFiles = require("./postFiles") |
|||
const saveRecord = require("./saveRecord") |
|||
const lookupField = require("./lookupField") |
|||
const getRecord = require("./getRecord") |
|||
const deleteRecord = require("./deleteRecord") |
|||
const saveAppHierarchy = require("./saveAppHierarchy") |
|||
const upgradeData = require("./upgradeData") |
|||
|
|||
module.exports = { |
|||
authenticate, |
|||
setPasswordFromTemporaryCode, |
|||
createTemporaryAccess, |
|||
appDefault, |
|||
changeMyPassword, |
|||
executeAction, |
|||
createUser, |
|||
enableUser, |
|||
disableUser, |
|||
getUsers, |
|||
getAccessLevels, |
|||
listRecordsGet, |
|||
listRecordsPost, |
|||
aggregatesPost, |
|||
postFiles, |
|||
saveRecord, |
|||
lookupField, |
|||
getRecord, |
|||
deleteRecord, |
|||
saveAppHierarchy, |
|||
upgradeData, |
|||
} |
|||
@ -1,8 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
const { getRecordKey } = require("./helpers") |
|||
|
|||
module.exports = async ctx => { |
|||
const indexkey = getRecordKey(ctx.params.appname, ctx.request.path) |
|||
ctx.body = await ctx.instance.indexApi.listItems(indexkey) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,12 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
const { getRecordKey } = require("./helpers") |
|||
|
|||
module.exports = async ctx => { |
|||
const indexkey = getRecordKey(ctx.params.appname, ctx.request.path) |
|||
ctx.body = await ctx.instance.indexApi.listItems(indexkey, { |
|||
rangeStartParams: ctx.request.body.rangeStartParams, |
|||
rangeEndParams: ctx.request.body.rangeEndParams, |
|||
searchPhrase: ctx.request.body.searchPhrase, |
|||
}) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
const { getRecordKey } = require("./helpers") |
|||
|
|||
module.exports = async ctx => { |
|||
const recordKey = getRecordKey(ctx.params.appname, ctx.request.path) |
|||
const fields = ctx.query.fields.split(",") |
|||
const recordContext = await ctx.instance.recordApi.getContext(recordKey) |
|||
const allContext = [] |
|||
for (let field of fields) { |
|||
allContext.push(await recordContext.referenceOptions(field)) |
|||
} |
|||
ctx.body = allContext |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,13 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
const { getRecordKey } = require("./helpers") |
|||
const fs = require("fs") |
|||
|
|||
module.exports = async ctx => { |
|||
const file = ctx.request.files.file |
|||
ctx.body = await ctx.instance.recordApi.uploadFile( |
|||
getRecordKey(ctx.params.appname, ctx.request.path), |
|||
fs.createReadStream(file.path), |
|||
file.name |
|||
) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
ctx.body = await ctx.instance.templateApi.saveApplicationHierarchy(ctx.body) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,6 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
ctx.body = await ctx.instance.recordApi.save(ctx.request.body) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,20 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
const instanceApi = await ctx.master.getFullAccessInstanceApiForUsername( |
|||
ctx.params.appname, |
|||
ctx.request.body.username |
|||
) |
|||
|
|||
if (!instanceApi) { |
|||
ctx.request.status = StatusCodes.OK |
|||
return |
|||
} |
|||
|
|||
await instanceApi.authApi.setPasswordFromTemporaryCode( |
|||
ctx.request.body.tempCode, |
|||
ctx.request.body.newPassword |
|||
) |
|||
|
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
const StatusCodes = require("../../utilities/statusCodes") |
|||
|
|||
module.exports = async ctx => { |
|||
const existingAccessLevels = await ctx.instance.authApi.loadAccessLevels() |
|||
const accessLevels = ctx.request.body.accessLevels |
|||
accessLevels.version = existingAccessLevels.version |
|||
await ctx.instance.authApi.saveAccessLevels(accessLevels) |
|||
await ctx.instance.templateApi.upgradeData(ctx.request.body.newHierarchy) |
|||
await ctx.master.clearAllSessions(ctx.params.appname) |
|||
ctx.response.status = StatusCodes.OK |
|||
} |
|||
Loading…
Reference in new issue