Merge branch 'master' of github.com:Budibase/budibase into fix/budi-7433-google-sheets-validation-wont-let-you-import-any-sheets-if
This commit is contained in:
commit
a3cb9d7567
19 changed files with 55 additions and 459 deletions
14
.github/workflows/release-singleimage.yml
vendored
14
.github/workflows/release-singleimage.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
||||||
- name: Maximize build space
|
- name: Maximize build space
|
||||||
uses: easimon/maximize-build-space@master
|
uses: easimon/maximize-build-space@master
|
||||||
with:
|
with:
|
||||||
root-reserve-mb: 35000
|
root-reserve-mb: 30000
|
||||||
swap-size-mb: 1024
|
swap-size-mb: 1024
|
||||||
remove-android: 'true'
|
remove-android: 'true'
|
||||||
remove-dotnet: 'true'
|
remove-dotnet: 'true'
|
||||||
|
@ -33,14 +33,6 @@ jobs:
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Fail if tag is not in master
|
|
||||||
run: |
|
|
||||||
if ! git merge-base --is-ancestor ${{ github.sha }} origin/master; then
|
|
||||||
echo "Tag is not in master. This pipeline can only execute tags that are present on the master branch"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
|
@ -55,10 +47,6 @@ jobs:
|
||||||
run: yarn
|
run: yarn
|
||||||
- name: Update versions
|
- name: Update versions
|
||||||
run: ./scripts/updateVersions.sh
|
run: ./scripts/updateVersions.sh
|
||||||
- name: Runt Yarn Lint
|
|
||||||
run: yarn lint
|
|
||||||
- name: Update versions
|
|
||||||
run: ./scripts/updateVersions.sh
|
|
||||||
- name: Run Yarn Build
|
- name: Run Yarn Build
|
||||||
run: yarn build:docker:pre
|
run: yarn build:docker:pre
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
|
|
|
@ -12,14 +12,14 @@ RUN chmod +x /cleanup.sh
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ADD packages/server .
|
ADD packages/server .
|
||||||
COPY yarn.lock .
|
COPY yarn.lock .
|
||||||
RUN yarn install --production=true
|
RUN yarn install --production=true --network-timeout 100000
|
||||||
RUN /cleanup.sh
|
RUN /cleanup.sh
|
||||||
|
|
||||||
# build worker
|
# build worker
|
||||||
WORKDIR /worker
|
WORKDIR /worker
|
||||||
ADD packages/worker .
|
ADD packages/worker .
|
||||||
COPY yarn.lock .
|
COPY yarn.lock .
|
||||||
RUN yarn install --production=true
|
RUN yarn install --production=true --network-timeout 100000
|
||||||
RUN /cleanup.sh
|
RUN /cleanup.sh
|
||||||
|
|
||||||
FROM budibase/couchdb
|
FROM budibase/couchdb
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": "2.11.24",
|
"version": "2.11.31",
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"packages": [
|
"packages": [
|
||||||
"packages/*"
|
"packages/*"
|
||||||
|
|
|
@ -74,7 +74,6 @@
|
||||||
"build:docker:dependencies": "docker build -f hosting/dependencies/Dockerfile -t budibase/dependencies:latest ./hosting",
|
"build:docker:dependencies": "docker build -f hosting/dependencies/Dockerfile -t budibase/dependencies:latest ./hosting",
|
||||||
"publish:docker:couch": "docker buildx build --platform linux/arm64,linux/amd64 -f hosting/couchdb/Dockerfile -t budibase/couchdb:latest -t budibase/couchdb:v3.2.1 --push ./hosting/couchdb",
|
"publish:docker:couch": "docker buildx build --platform linux/arm64,linux/amd64 -f hosting/couchdb/Dockerfile -t budibase/couchdb:latest -t budibase/couchdb:v3.2.1 --push ./hosting/couchdb",
|
||||||
"publish:docker:dependencies": "docker buildx build --platform linux/arm64,linux/amd64 -f hosting/dependencies/Dockerfile -t budibase/dependencies:latest -t budibase/dependencies:v3.2.1 --push ./hosting",
|
"publish:docker:dependencies": "docker buildx build --platform linux/arm64,linux/amd64 -f hosting/dependencies/Dockerfile -t budibase/dependencies:latest -t budibase/dependencies:v3.2.1 --push ./hosting",
|
||||||
"build:docs": "lerna run --stream build:docs",
|
|
||||||
"release:helm": "node scripts/releaseHelmChart",
|
"release:helm": "node scripts/releaseHelmChart",
|
||||||
"env:multi:enable": "lerna run --stream env:multi:enable",
|
"env:multi:enable": "lerna run --stream env:multi:enable",
|
||||||
"env:multi:disable": "lerna run --stream env:multi:disable",
|
"env:multi:disable": "lerna run --stream env:multi:disable",
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="text" title={showTooltip ? text : null}>
|
<div class="text" title={showTooltip ? text : null}>
|
||||||
{text}
|
<span title={text}>{text}</span>
|
||||||
{#if selectedBy}
|
{#if selectedBy}
|
||||||
<UserAvatars size="XS" users={selectedBy} />
|
<UserAvatars size="XS" users={selectedBy} />
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -227,9 +227,6 @@
|
||||||
.text {
|
.text {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
color: var(--spectrum-global-color-gray-900);
|
color: var(--spectrum-global-color-gray-900);
|
||||||
order: 2;
|
order: 2;
|
||||||
|
@ -238,6 +235,11 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
.text span {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
.scrollable .text {
|
.scrollable .text {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
max-width: 160px;
|
max-width: 160px;
|
||||||
|
|
|
@ -3419,6 +3419,17 @@
|
||||||
"value": "custom"
|
"value": "custom"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "event",
|
||||||
|
"label": "On change",
|
||||||
|
"key": "onChange",
|
||||||
|
"context": [
|
||||||
|
{
|
||||||
|
"label": "Field Value",
|
||||||
|
"key": "value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "validation/string",
|
"type": "validation/string",
|
||||||
"label": "Validation",
|
"label": "Validation",
|
||||||
|
|
|
@ -128,6 +128,7 @@
|
||||||
<div class="manual-input">
|
<div class="manual-input">
|
||||||
<Input
|
<Input
|
||||||
bind:value
|
bind:value
|
||||||
|
updateOnChange={false}
|
||||||
on:change={() => {
|
on:change={() => {
|
||||||
dispatch("change", value)
|
dispatch("change", value)
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
"test:watch": "jest --watch",
|
"test:watch": "jest --watch",
|
||||||
"predocker": "copyfiles -f ../client/dist/budibase-client.js ../client/manifest.json client && yarn build && cp ../../yarn.lock ./dist/",
|
"predocker": "copyfiles -f ../client/dist/budibase-client.js ../client/manifest.json client && yarn build && cp ../../yarn.lock ./dist/",
|
||||||
"build:docker": "yarn predocker && docker build . -t app-service --label version=$BUDIBASE_RELEASE_VERSION",
|
"build:docker": "yarn predocker && docker build . -t app-service --label version=$BUDIBASE_RELEASE_VERSION",
|
||||||
"build:docs": "node ./scripts/docs/generate.js open",
|
|
||||||
"run:docker": "node dist/index.js",
|
"run:docker": "node dist/index.js",
|
||||||
"run:docker:cluster": "pm2-runtime start pm2.config.js",
|
"run:docker:cluster": "pm2-runtime start pm2.config.js",
|
||||||
"dev:stack:up": "node scripts/dev/manage.js up",
|
"dev:stack:up": "node scripts/dev/manage.js up",
|
||||||
|
@ -112,7 +111,7 @@
|
||||||
"to-json-schema": "0.2.5",
|
"to-json-schema": "0.2.5",
|
||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
"validate.js": "0.13.1",
|
"validate.js": "0.13.1",
|
||||||
"vm2": "3.9.17",
|
"vm2": "^3.9.19",
|
||||||
"worker-farm": "1.7.0",
|
"worker-farm": "1.7.0",
|
||||||
"xml2js": "0.5.0",
|
"xml2js": "0.5.0",
|
||||||
"yargs": "13.2.4"
|
"yargs": "13.2.4"
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
### Documentation
|
|
||||||
|
|
||||||
This directory contains the scripts required to generate the APIDoc based documentation.
|
|
||||||
You can find the docs about comment structure at the [APIDocs page](https://apidocjs.com/).
|
|
||||||
|
|
||||||
In general most API endpoints will look like:
|
|
||||||
```js
|
|
||||||
/**
|
|
||||||
* @api {post} /api/:param/url Give it a name
|
|
||||||
* @apiName Give it a name
|
|
||||||
* @apiGroup group
|
|
||||||
* @apiPermission permission
|
|
||||||
* @apiDescription Describe what the endpoint does, any special cases the user
|
|
||||||
* should be aware of.
|
|
||||||
*
|
|
||||||
* @apiParam {string} param describe a URL parameter.
|
|
||||||
*
|
|
||||||
* @apiParam (Body) input describe a field on the body.
|
|
||||||
*
|
|
||||||
* @apiSuccess {object} output describe the output.
|
|
||||||
*/
|
|
||||||
```
|
|
||||||
|
|
||||||
There are a few key points to note when writing API docs:
|
|
||||||
1. Don't use `@apiBody` - this isn't currently supported by our swagger converter.
|
|
||||||
2. Make sure to always have an `@api` definition at the start, which must always have the
|
|
||||||
HTTP verb, the endpoint URL and the name.
|
|
||||||
3. There are three ways you can specify parameters used as inputs for your endpoint,
|
|
||||||
`@apiParam` for a URL param, `@apiParam (Body)` for a field on the request body and `@apiParam (Query)`
|
|
||||||
for query string parameters.
|
|
||||||
4. The `@apiGroup` should be the same for all API Doc comments in a route file.
|
|
|
@ -1,74 +0,0 @@
|
||||||
const fs = require("fs")
|
|
||||||
const { join } = require("path")
|
|
||||||
const { createDoc } = require("apidoc")
|
|
||||||
const packageJson = require("../../package.json")
|
|
||||||
const toSwagger = require("./toSwagger")
|
|
||||||
const open = require("open")
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
name: "Budibase API",
|
|
||||||
version: packageJson.version,
|
|
||||||
description: "Documenting the Budibase backend API",
|
|
||||||
title: "Budibase app service API",
|
|
||||||
}
|
|
||||||
|
|
||||||
const shouldOpen = process.argv[2]
|
|
||||||
const disallowed = []
|
|
||||||
|
|
||||||
function filter(parsedRouteFiles) {
|
|
||||||
const tagToSearch = "url"
|
|
||||||
for (let routeFile of parsedRouteFiles) {
|
|
||||||
for (let route of routeFile) {
|
|
||||||
let routeInfo = route["local"]
|
|
||||||
if (disallowed.includes(routeInfo[tagToSearch])) {
|
|
||||||
const idx = routeFile.indexOf(route)
|
|
||||||
routeFile.splice(idx, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function generate() {
|
|
||||||
// start by writing a config file
|
|
||||||
const configPath = join(__dirname, "config.json")
|
|
||||||
fs.writeFileSync(configPath, JSON.stringify(config))
|
|
||||||
const mainPath = join(__dirname, "..", "..")
|
|
||||||
const srcPath = join(mainPath, "src", "api", "routes")
|
|
||||||
const assetsPath = join(mainPath, "builder", "assets", "docs")
|
|
||||||
if (!fs.existsSync(assetsPath)) {
|
|
||||||
fs.mkdirSync(assetsPath, { recursive: true })
|
|
||||||
}
|
|
||||||
const options = {
|
|
||||||
src: [srcPath],
|
|
||||||
dest: assetsPath,
|
|
||||||
filters: {
|
|
||||||
main: {
|
|
||||||
postFilter: filter,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
config: configPath,
|
|
||||||
}
|
|
||||||
const doc = createDoc(options)
|
|
||||||
if (typeof doc !== "boolean") {
|
|
||||||
const swagger = toSwagger(JSON.parse(doc.data), JSON.parse(doc.project))
|
|
||||||
fs.writeFileSync(join(assetsPath, "swagger.json"), JSON.stringify(swagger))
|
|
||||||
fs.writeFileSync(join(assetsPath, "apidoc.json"), doc.data)
|
|
||||||
fs.writeFileSync(join(assetsPath, "project.json"), doc.project)
|
|
||||||
console.log(
|
|
||||||
`Docs generated successfully, find in ${assetsPath}, swagger.json, apidoc.json and project.json`
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
throw "Unable to generate docs."
|
|
||||||
}
|
|
||||||
// delete the temporary config file
|
|
||||||
fs.unlinkSync(configPath)
|
|
||||||
setTimeout(async () => {
|
|
||||||
if (shouldOpen === "open") {
|
|
||||||
await open(join(assetsPath, "index.html"), { wait: false })
|
|
||||||
}
|
|
||||||
}, 2000)
|
|
||||||
}
|
|
||||||
|
|
||||||
generate().catch(err => {
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
|
@ -1,320 +0,0 @@
|
||||||
let _ = require("lodash")
|
|
||||||
let { pathToRegexp } = require("path-to-regexp")
|
|
||||||
|
|
||||||
/********************************************************
|
|
||||||
* Based on: https://github.com/fsbahman/apidoc-swagger *
|
|
||||||
********************************************************/
|
|
||||||
|
|
||||||
let swagger = {
|
|
||||||
swagger: "2.0",
|
|
||||||
info: {},
|
|
||||||
paths: {},
|
|
||||||
definitions: {},
|
|
||||||
}
|
|
||||||
|
|
||||||
function toSwagger(apidocJson, projectJson) {
|
|
||||||
swagger.info = addInfo(projectJson)
|
|
||||||
swagger.paths = extractPaths(apidocJson)
|
|
||||||
return swagger
|
|
||||||
}
|
|
||||||
|
|
||||||
let tagsRegex = /(<([^>]+)>)/gi
|
|
||||||
// Removes <p> </p> tags from text
|
|
||||||
function removeTags(text) {
|
|
||||||
return text ? text.replace(tagsRegex, "") : text
|
|
||||||
}
|
|
||||||
|
|
||||||
function addInfo(projectJson) {
|
|
||||||
let info = {}
|
|
||||||
info["title"] = projectJson.title || projectJson.name
|
|
||||||
info["version"] = projectJson.version
|
|
||||||
info["description"] = projectJson.description
|
|
||||||
return info
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts paths provided in json format
|
|
||||||
* post, patch, put request parameters are extracted in body
|
|
||||||
* get and delete are extracted to path parameters
|
|
||||||
* @param apidocJson
|
|
||||||
* @returns {{}}
|
|
||||||
*/
|
|
||||||
function extractPaths(apidocJson) {
|
|
||||||
let apiPaths = groupByUrl(apidocJson)
|
|
||||||
let paths = {}
|
|
||||||
for (let i = 0; i < apiPaths.length; i++) {
|
|
||||||
let verbs = apiPaths[i].verbs
|
|
||||||
let url = verbs[0].url
|
|
||||||
let pattern = pathToRegexp(url, null)
|
|
||||||
let matches = pattern.exec(url)
|
|
||||||
|
|
||||||
// Surrounds URL parameters with curly brackets -> :email with {email}
|
|
||||||
let pathKeys = []
|
|
||||||
for (let j = 1; j < matches.length; j++) {
|
|
||||||
let key = matches[j].slice(1)
|
|
||||||
url = url.replace(matches[j], "{" + key + "}")
|
|
||||||
pathKeys.push(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let j = 0; j < verbs.length; j++) {
|
|
||||||
let verb = verbs[j]
|
|
||||||
let type = verb.type
|
|
||||||
|
|
||||||
let obj = (paths[url] = paths[url] || {})
|
|
||||||
|
|
||||||
if (type === "post" || type === "patch" || type === "put") {
|
|
||||||
_.extend(
|
|
||||||
obj,
|
|
||||||
createPostPushPutOutput(verb, swagger.definitions, pathKeys)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
_.extend(obj, createGetDeleteOutput(verb, swagger.definitions))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return paths
|
|
||||||
}
|
|
||||||
|
|
||||||
function createPostPushPutOutput(verbs, definitions, pathKeys) {
|
|
||||||
let pathItemObject = {}
|
|
||||||
let verbDefinitionResult = createVerbDefinitions(verbs, definitions)
|
|
||||||
|
|
||||||
let params = []
|
|
||||||
let pathParams = createPathParameters(verbs, pathKeys)
|
|
||||||
pathParams = _.filter(pathParams, function (param) {
|
|
||||||
let hasKey = pathKeys.indexOf(param.name) !== -1
|
|
||||||
return !(param.in === "path" && !hasKey)
|
|
||||||
})
|
|
||||||
|
|
||||||
params = params.concat(pathParams)
|
|
||||||
let required =
|
|
||||||
verbs.parameter &&
|
|
||||||
verbs.parameter.fields &&
|
|
||||||
verbs.parameter.fields.Parameter &&
|
|
||||||
verbs.parameter.fields.Parameter.length > 0
|
|
||||||
|
|
||||||
params.push({
|
|
||||||
in: "body",
|
|
||||||
name: "body",
|
|
||||||
description: removeTags(verbs.description),
|
|
||||||
required: required,
|
|
||||||
schema: {
|
|
||||||
$ref: "#/definitions/" + verbDefinitionResult.topLevelParametersRef,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
pathItemObject[verbs.type] = {
|
|
||||||
tags: [verbs.group],
|
|
||||||
summary: removeTags(verbs.description),
|
|
||||||
consumes: ["application/json"],
|
|
||||||
produces: ["application/json"],
|
|
||||||
parameters: params,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbDefinitionResult.topLevelSuccessRef) {
|
|
||||||
pathItemObject[verbs.type].responses = {
|
|
||||||
200: {
|
|
||||||
description: "successful operation",
|
|
||||||
schema: {
|
|
||||||
type: verbDefinitionResult.topLevelSuccessRefType,
|
|
||||||
items: {
|
|
||||||
$ref: "#/definitions/" + verbDefinitionResult.topLevelSuccessRef,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pathItemObject
|
|
||||||
}
|
|
||||||
|
|
||||||
function createVerbDefinitions(verbs, definitions) {
|
|
||||||
let result = {
|
|
||||||
topLevelParametersRef: null,
|
|
||||||
topLevelSuccessRef: null,
|
|
||||||
topLevelSuccessRefType: null,
|
|
||||||
}
|
|
||||||
let defaultObjectName = verbs.name
|
|
||||||
|
|
||||||
let fieldArrayResult = {}
|
|
||||||
if (verbs && verbs.parameter && verbs.parameter.fields) {
|
|
||||||
fieldArrayResult = createFieldArrayDefinitions(
|
|
||||||
verbs.parameter.fields.Parameter,
|
|
||||||
definitions,
|
|
||||||
verbs.name,
|
|
||||||
defaultObjectName
|
|
||||||
)
|
|
||||||
result.topLevelParametersRef = fieldArrayResult.topLevelRef
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbs && verbs.success && verbs.success.fields) {
|
|
||||||
fieldArrayResult = createFieldArrayDefinitions(
|
|
||||||
verbs.success.fields["Success 200"],
|
|
||||||
definitions,
|
|
||||||
verbs.name,
|
|
||||||
defaultObjectName
|
|
||||||
)
|
|
||||||
result.topLevelSuccessRef = fieldArrayResult.topLevelRef
|
|
||||||
result.topLevelSuccessRefType = fieldArrayResult.topLevelRefType
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFieldArrayDefinitions(
|
|
||||||
fieldArray,
|
|
||||||
definitions,
|
|
||||||
topLevelRef,
|
|
||||||
defaultObjectName
|
|
||||||
) {
|
|
||||||
let result = {
|
|
||||||
topLevelRef: topLevelRef,
|
|
||||||
topLevelRefType: null,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fieldArray) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < fieldArray.length; i++) {
|
|
||||||
let parameter = fieldArray[i]
|
|
||||||
|
|
||||||
let nestedName = createNestedName(parameter.field)
|
|
||||||
let objectName = nestedName.objectName
|
|
||||||
if (!objectName) {
|
|
||||||
objectName = defaultObjectName
|
|
||||||
}
|
|
||||||
let type = parameter.type
|
|
||||||
if (i === 0) {
|
|
||||||
result.topLevelRefType = type
|
|
||||||
if (parameter.type === "Object") {
|
|
||||||
objectName = nestedName.propertyName
|
|
||||||
nestedName.propertyName = null
|
|
||||||
} else if (parameter.type === "Array") {
|
|
||||||
objectName = nestedName.propertyName
|
|
||||||
nestedName.propertyName = null
|
|
||||||
result.topLevelRefType = "array"
|
|
||||||
}
|
|
||||||
result.topLevelRef = objectName
|
|
||||||
}
|
|
||||||
|
|
||||||
definitions[objectName] = definitions[objectName] || {
|
|
||||||
properties: {},
|
|
||||||
required: [],
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nestedName.propertyName) {
|
|
||||||
let prop = {
|
|
||||||
type: (parameter.type || "").toLowerCase(),
|
|
||||||
description: removeTags(parameter.description),
|
|
||||||
}
|
|
||||||
if (parameter.type === "Object") {
|
|
||||||
prop.$ref = "#/definitions/" + parameter.field
|
|
||||||
}
|
|
||||||
|
|
||||||
let typeIndex = type.indexOf("[]")
|
|
||||||
if (typeIndex !== -1 && typeIndex === type.length - 2) {
|
|
||||||
prop.type = "array"
|
|
||||||
prop.items = {
|
|
||||||
type: type.slice(0, type.length - 2),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
definitions[objectName]["properties"][nestedName.propertyName] = prop
|
|
||||||
if (!parameter.optional) {
|
|
||||||
let arr = definitions[objectName]["required"]
|
|
||||||
if (arr.indexOf(nestedName.propertyName) === -1) {
|
|
||||||
arr.push(nestedName.propertyName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
function createNestedName(field) {
|
|
||||||
let propertyName = field
|
|
||||||
let objectName
|
|
||||||
let propertyNames = field.split(".")
|
|
||||||
if (propertyNames && propertyNames.length > 1) {
|
|
||||||
propertyName = propertyNames[propertyNames.length - 1]
|
|
||||||
propertyNames.pop()
|
|
||||||
objectName = propertyNames.join(".")
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
propertyName: propertyName,
|
|
||||||
objectName: objectName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate get, delete method output
|
|
||||||
* @param verbs
|
|
||||||
* @param definitions
|
|
||||||
* @returns {{}}
|
|
||||||
*/
|
|
||||||
function createGetDeleteOutput(verbs, definitions) {
|
|
||||||
let pathItemObject = {}
|
|
||||||
verbs.type = verbs.type === "del" ? "delete" : verbs.type
|
|
||||||
|
|
||||||
let verbDefinitionResult = createVerbDefinitions(verbs, definitions)
|
|
||||||
pathItemObject[verbs.type] = {
|
|
||||||
tags: [verbs.group],
|
|
||||||
summary: removeTags(verbs.description),
|
|
||||||
consumes: ["application/json"],
|
|
||||||
produces: ["application/json"],
|
|
||||||
parameters: createPathParameters(verbs),
|
|
||||||
}
|
|
||||||
if (verbDefinitionResult.topLevelSuccessRef) {
|
|
||||||
pathItemObject[verbs.type].responses = {
|
|
||||||
200: {
|
|
||||||
description: "successful operation",
|
|
||||||
schema: {
|
|
||||||
type: verbDefinitionResult.topLevelSuccessRefType,
|
|
||||||
items: {
|
|
||||||
$ref: "#/definitions/" + verbDefinitionResult.topLevelSuccessRef,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pathItemObject
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate through all method parameters and create array of parameter objects which are stored as path parameters
|
|
||||||
* @param verbs
|
|
||||||
* @returns {Array}
|
|
||||||
*/
|
|
||||||
function createPathParameters(verbs) {
|
|
||||||
let pathItemObject = []
|
|
||||||
if (verbs.parameter && verbs.parameter.fields.Parameter) {
|
|
||||||
for (let i = 0; i < verbs.parameter.fields.Parameter.length; i++) {
|
|
||||||
let param = verbs.parameter.fields.Parameter[i]
|
|
||||||
let field = param.field
|
|
||||||
let type = param.type
|
|
||||||
pathItemObject.push({
|
|
||||||
name: field,
|
|
||||||
in: type === "file" ? "formData" : "path",
|
|
||||||
required: !param.optional,
|
|
||||||
type: param.type.toLowerCase(),
|
|
||||||
description: removeTags(param.description),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pathItemObject
|
|
||||||
}
|
|
||||||
|
|
||||||
function groupByUrl(apidocJson) {
|
|
||||||
return _.chain(apidocJson)
|
|
||||||
.groupBy("url")
|
|
||||||
.toPairs()
|
|
||||||
.map(function (element) {
|
|
||||||
return _.zipObject(["url", "verbs"], element)
|
|
||||||
})
|
|
||||||
.value()
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = toSwagger
|
|
|
@ -859,7 +859,8 @@
|
||||||
"json",
|
"json",
|
||||||
"internal",
|
"internal",
|
||||||
"barcodeqr",
|
"barcodeqr",
|
||||||
"bigint"
|
"bigint",
|
||||||
|
"bb_reference"
|
||||||
],
|
],
|
||||||
"description": "Defines the type of the column, most explain themselves, a link column is a relationship."
|
"description": "Defines the type of the column, most explain themselves, a link column is a relationship."
|
||||||
},
|
},
|
||||||
|
@ -1064,7 +1065,8 @@
|
||||||
"json",
|
"json",
|
||||||
"internal",
|
"internal",
|
||||||
"barcodeqr",
|
"barcodeqr",
|
||||||
"bigint"
|
"bigint",
|
||||||
|
"bb_reference"
|
||||||
],
|
],
|
||||||
"description": "Defines the type of the column, most explain themselves, a link column is a relationship."
|
"description": "Defines the type of the column, most explain themselves, a link column is a relationship."
|
||||||
},
|
},
|
||||||
|
@ -1280,7 +1282,8 @@
|
||||||
"json",
|
"json",
|
||||||
"internal",
|
"internal",
|
||||||
"barcodeqr",
|
"barcodeqr",
|
||||||
"bigint"
|
"bigint",
|
||||||
|
"bb_reference"
|
||||||
],
|
],
|
||||||
"description": "Defines the type of the column, most explain themselves, a link column is a relationship."
|
"description": "Defines the type of the column, most explain themselves, a link column is a relationship."
|
||||||
},
|
},
|
||||||
|
|
|
@ -782,6 +782,7 @@ components:
|
||||||
- internal
|
- internal
|
||||||
- barcodeqr
|
- barcodeqr
|
||||||
- bigint
|
- bigint
|
||||||
|
- bb_reference
|
||||||
description: Defines the type of the column, most explain themselves, a link
|
description: Defines the type of the column, most explain themselves, a link
|
||||||
column is a relationship.
|
column is a relationship.
|
||||||
constraints:
|
constraints:
|
||||||
|
@ -946,6 +947,7 @@ components:
|
||||||
- internal
|
- internal
|
||||||
- barcodeqr
|
- barcodeqr
|
||||||
- bigint
|
- bigint
|
||||||
|
- bb_reference
|
||||||
description: Defines the type of the column, most explain themselves, a link
|
description: Defines the type of the column, most explain themselves, a link
|
||||||
column is a relationship.
|
column is a relationship.
|
||||||
constraints:
|
constraints:
|
||||||
|
@ -1117,6 +1119,7 @@ components:
|
||||||
- internal
|
- internal
|
||||||
- barcodeqr
|
- barcodeqr
|
||||||
- bigint
|
- bigint
|
||||||
|
- bb_reference
|
||||||
description: Defines the type of the column, most explain themselves, a link
|
description: Defines the type of the column, most explain themselves, a link
|
||||||
column is a relationship.
|
column is a relationship.
|
||||||
constraints:
|
constraints:
|
||||||
|
|
|
@ -1580,6 +1580,9 @@ describe.each([
|
||||||
(row: Row) => ({
|
(row: Row) => ({
|
||||||
_id: row._id,
|
_id: row._id,
|
||||||
primaryDisplay: row.email,
|
primaryDisplay: row.email,
|
||||||
|
email: row.email,
|
||||||
|
firstName: row.firstName,
|
||||||
|
lastName: row.lastName,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
])("links - %s", (__, relSchema, dataGenerator, resultMapper) => {
|
])("links - %s", (__, relSchema, dataGenerator, resultMapper) => {
|
||||||
|
|
|
@ -279,7 +279,8 @@ export interface components {
|
||||||
| "json"
|
| "json"
|
||||||
| "internal"
|
| "internal"
|
||||||
| "barcodeqr"
|
| "barcodeqr"
|
||||||
| "bigint";
|
| "bigint"
|
||||||
|
| "bb_reference";
|
||||||
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
||||||
constraints?: {
|
constraints?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -386,7 +387,8 @@ export interface components {
|
||||||
| "json"
|
| "json"
|
||||||
| "internal"
|
| "internal"
|
||||||
| "barcodeqr"
|
| "barcodeqr"
|
||||||
| "bigint";
|
| "bigint"
|
||||||
|
| "bb_reference";
|
||||||
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
||||||
constraints?: {
|
constraints?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
@ -495,7 +497,8 @@ export interface components {
|
||||||
| "json"
|
| "json"
|
||||||
| "internal"
|
| "internal"
|
||||||
| "barcodeqr"
|
| "barcodeqr"
|
||||||
| "bigint";
|
| "bigint"
|
||||||
|
| "bb_reference";
|
||||||
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
/** @description A constraint can be applied to the column which will be validated against when a row is saved. */
|
||||||
constraints?: {
|
constraints?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
|
|
|
@ -82,6 +82,9 @@ export async function processOutputBBReferences(
|
||||||
return users.map(u => ({
|
return users.map(u => ({
|
||||||
_id: u._id,
|
_id: u._id,
|
||||||
primaryDisplay: u.email,
|
primaryDisplay: u.email,
|
||||||
|
email: u.email,
|
||||||
|
firstName: u.firstName,
|
||||||
|
lastName: u.lastName,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -180,6 +180,9 @@ describe("bbReferenceProcessor", () => {
|
||||||
{
|
{
|
||||||
_id: user._id,
|
_id: user._id,
|
||||||
primaryDisplay: user.email,
|
primaryDisplay: user.email,
|
||||||
|
email: user.email,
|
||||||
|
firstName: user.firstName,
|
||||||
|
lastName: user.lastName,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
expect(cacheGetUsersSpy).toBeCalledTimes(1)
|
expect(cacheGetUsersSpy).toBeCalledTimes(1)
|
||||||
|
@ -204,6 +207,9 @@ describe("bbReferenceProcessor", () => {
|
||||||
[user1, user2].map(u => ({
|
[user1, user2].map(u => ({
|
||||||
_id: u._id,
|
_id: u._id,
|
||||||
primaryDisplay: u.email,
|
primaryDisplay: u.email,
|
||||||
|
email: u.email,
|
||||||
|
firstName: u.firstName,
|
||||||
|
lastName: u.lastName,
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
"dayjs": "^1.10.8",
|
"dayjs": "^1.10.8",
|
||||||
"handlebars": "^4.7.6",
|
"handlebars": "^4.7.6",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"vm2": "^3.9.15"
|
"vm2": "^3.9.19"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^17.1.0",
|
"@rollup/plugin-commonjs": "^17.1.0",
|
||||||
|
|
|
@ -21750,10 +21750,10 @@ vlq@^0.2.2:
|
||||||
resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
|
resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
|
||||||
integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
|
integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
|
||||||
|
|
||||||
vm2@3.9.17, vm2@^3.9.15, vm2@^3.9.8:
|
vm2@^3.9.19:
|
||||||
version "3.9.17"
|
version "3.9.19"
|
||||||
resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.17.tgz#251b165ff8a0e034942b5181057305e39570aeab"
|
resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.19.tgz#be1e1d7a106122c6c492b4d51c2e8b93d3ed6a4a"
|
||||||
integrity sha512-AqwtCnZ/ERcX+AVj9vUsphY56YANXxRuqMb7GsDtAr0m0PcQX3u0Aj3KWiXM0YAHy7i6JEeHrwOnwXbGYgRpAw==
|
integrity sha512-J637XF0DHDMV57R6JyVsTak7nIL8gy5KH4r1HiwWLf/4GBbb5MKL5y7LpmF4A8E2nR6XmzpmMFQ7V7ppPTmUQg==
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn "^8.7.0"
|
acorn "^8.7.0"
|
||||||
acorn-walk "^8.2.0"
|
acorn-walk "^8.2.0"
|
||||||
|
|
Loading…
Reference in a new issue