Add fields for MongoDB SSL cert file paths (#8260)

* Added fields for tls certificate files

* lint

* Only include cert fields if SELF_HOSTED

* lint

* Refactor getSchema function

* Add datasource field group with accordion

* Handle no display column on fieldGroup field

* Override text transform accordian header

* Renamed from TLS to SSL in UI config

* readable flag

* Add accordion component

* Refactor
This commit is contained in:
melohagan 2023-01-23 16:46:02 +00:00 committed by GitHub
parent de83c32576
commit c72bce9e4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 442 additions and 285 deletions

View File

@ -38,6 +38,7 @@
], ],
"dependencies": { "dependencies": {
"@adobe/spectrum-css-workflow-icons": "1.2.1", "@adobe/spectrum-css-workflow-icons": "1.2.1",
"@spectrum-css/accordion": "3.0.24",
"@budibase/string-templates": "2.2.12-alpha.33", "@budibase/string-templates": "2.2.12-alpha.33",
"@spectrum-css/actionbutton": "1.0.1", "@spectrum-css/actionbutton": "1.0.1",
"@spectrum-css/actiongroup": "1.0.1", "@spectrum-css/actiongroup": "1.0.1",

View File

@ -0,0 +1,58 @@
<script>
import "@spectrum-css/accordion"
export let itemName
export let initialOpen
export let header
let isOpen
function getOpenClass(isOpen) {
if (isOpen === undefined) {
isOpen = initialOpen
}
return isOpen ? "is-open" : ""
}
</script>
<div class="spectrum-Accordion" role={itemName}>
<div class="spectrum-Accordion-item {getOpenClass(isOpen)}">
<h3 class="spectrum-Accordion-itemHeading">
<button
class="spectrum-Accordion-itemHeader"
type="button"
on:click={() => (isOpen = !isOpen)}
>
{header}
</button>
<svg
class="spectrum-Icon spectrum-UIIcon-ChevronRight100 spectrum-Accordion-itemIndicator"
focusable="false"
aria-hidden="true"
>
<use xlink:href="#spectrum-css-icon-Chevron100" />
</svg>
</h3>
<div class="spectrum-Accordion-itemContent" role={itemName}>
<slot />
</div>
</div>
</div>
<style>
.spectrum-Accordion {
margin-left: -20px;
}
.spectrum-Accordion-item {
border: none;
}
.spectrum-Accordion-itemContent {
width: 97%;
padding-left: 30px;
}
.spectrum-Accordion-itemHeader {
text-transform: none;
font-weight: bold;
font-size: 0.875rem;
}
</style>

View File

@ -75,6 +75,7 @@ export { default as ListItem } from "./List/ListItem.svelte"
export { default as IconSideNav } from "./IconSideNav/IconSideNav.svelte" export { default as IconSideNav } from "./IconSideNav/IconSideNav.svelte"
export { default as IconSideNavItem } from "./IconSideNav/IconSideNavItem.svelte" export { default as IconSideNavItem } from "./IconSideNav/IconSideNavItem.svelte"
export { default as Slider } from "./Form/Slider.svelte" export { default as Slider } from "./Form/Slider.svelte"
export { default as Accordion } from "./Accordion/Accordion.svelte"
// Renderers // Renderers
export { default as BoldRenderer } from "./Table/BoldRenderer.svelte" export { default as BoldRenderer } from "./Table/BoldRenderer.svelte"

View File

@ -109,10 +109,15 @@
estree-walker "^1.0.1" estree-walker "^1.0.1"
picomatch "^2.2.2" picomatch "^2.2.2"
"@spectrum-css/actionbutton@1.0.1": "@spectrum-css/accordion@3.0.24":
version "1.0.1" version "3.0.24"
resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.1.tgz#9c75da37ea6915919fb574c74bd60dacc03b6577" resolved "https://registry.yarnpkg.com/@spectrum-css/accordion/-/accordion-3.0.24.tgz#f89066c120c57b0cfc9aba66d60c39fc1cf69f74"
integrity sha512-AUqtyNabHF451Aj9i3xz82TxS5Z6k1dttA68/1hMeU9kbPCSS4P6Viw3vaRGs9CSspuR8xnnhDgrq+F+zMy2Hw== integrity sha512-jNOmUsxmiT3lRLButnN5KKHM94fd+87fjiF8L0c4uRNgJl6ZsBuxPXrM15lV4y1f8D2IACAw01/ZkGRAeaCOFA==
"@spectrum-css/actionbutton@^1.0.1":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.2.tgz#7753a94c64cebecfca6749ef20e37a5ea80c59be"
integrity sha512-laDWk7PCgy2I0AGsMjTmYKkiMVYVoF1B4tffJf4cIp66znTiqPHEbLDh5EDNU88JLTY2bWoCOY4cJxvXk5gERw==
"@spectrum-css/actiongroup@1.0.1": "@spectrum-css/actiongroup@1.0.1":
version "1.0.1" version "1.0.1"

View File

@ -78,6 +78,7 @@
"@sentry/browser": "5.19.1", "@sentry/browser": "5.19.1",
"@spectrum-css/page": "^3.0.1", "@spectrum-css/page": "^3.0.1",
"@spectrum-css/vars": "^3.0.1", "@spectrum-css/vars": "^3.0.1",
"@spectrum-css/accordion": "^3.0.24",
"codemirror": "^5.59.0", "codemirror": "^5.59.0",
"dayjs": "^1.11.2", "dayjs": "^1.11.2",
"downloadjs": "1.4.7", "downloadjs": "1.4.7",

View File

@ -6,6 +6,7 @@
Toggle, Toggle,
Button, Button,
TextArea, TextArea,
Accordion,
} from "@budibase/bbui" } from "@budibase/bbui"
import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte" import KeyValueBuilder from "components/integration/KeyValueBuilder.svelte"
import { capitalise } from "helpers" import { capitalise } from "helpers"
@ -51,15 +52,24 @@
let addButton let addButton
function getDisplayName(key) { function getDisplayName(key, fieldKey) {
let name let name
if (schema[key]?.display) { if (fieldKey && schema[key]["fields"][fieldKey]?.display) {
name = schema[key]["fields"][fieldKey].display
} else if (fieldKey) {
name = fieldKey
} else if (schema[key]?.display) {
name = schema[key].display name = schema[key].display
} else { } else {
name = key name = key
} }
return capitalise(name) return capitalise(name)
} }
function getFieldGroupKeys(fieldGroup) {
return Object.entries(schema[fieldGroup].fields || {})
.filter(el => filter(el))
.map(([key]) => key)
}
</script> </script>
<form> <form>
@ -100,6 +110,27 @@
error={$validation.errors[configKey]} error={$validation.errors[configKey]}
/> />
</div> </div>
{:else if schema[configKey].type === "fieldGroup"}
<Accordion
itemName={configKey}
initialOpen={getFieldGroupKeys(configKey).some(
fieldKey => !!config[fieldKey]
)}
header={getDisplayName(configKey)}
>
<Layout gap="S">
{#each getFieldGroupKeys(configKey) as fieldKey}
<div class="form-row">
<Label>{getDisplayName(configKey, fieldKey)}</Label>
<Input
type={schema[configKey]["fields"][fieldKey]?.type}
on:change
bind:value={config[fieldKey]}
/>
</div>
{/each}
</Layout>
</Accordion>
{:else} {:else}
<div class="form-row"> <div class="form-row">
<Label>{getDisplayName(configKey)}</Label> <Label>{getDisplayName(configKey)}</Label>

View File

@ -1356,6 +1356,11 @@
dependencies: dependencies:
"@sinonjs/commons" "^1.7.0" "@sinonjs/commons" "^1.7.0"
"@spectrum-css/accordion@^3.0.24":
version "3.0.24"
resolved "https://registry.yarnpkg.com/@spectrum-css/accordion/-/accordion-3.0.24.tgz#f89066c120c57b0cfc9aba66d60c39fc1cf69f74"
integrity sha512-jNOmUsxmiT3lRLButnN5KKHM94fd+87fjiF8L0c4uRNgJl6ZsBuxPXrM15lV4y1f8D2IACAw01/ZkGRAeaCOFA==
"@spectrum-css/page@^3.0.1": "@spectrum-css/page@^3.0.1":
version "3.0.8" version "3.0.8"
resolved "https://registry.yarnpkg.com/@spectrum-css/page/-/page-3.0.8.tgz#001efa9e4c10095df9b2b37cf7d7d6eb60140190" resolved "https://registry.yarnpkg.com/@spectrum-css/page/-/page-3.0.8.tgz#001efa9e4c10095df9b2b37cf7d7d6eb60140190"

View File

@ -12,11 +12,16 @@ import {
FindOneAndUpdateOptions, FindOneAndUpdateOptions,
UpdateOptions, UpdateOptions,
OperationOptions, OperationOptions,
MongoClientOptions,
} from "mongodb" } from "mongodb"
import environment from "../environment"
interface MongoDBConfig { interface MongoDBConfig {
connectionString: string connectionString: string
db: string db: string
tlsCertificateFile: string
tlsCertificateKeyFile: string
tlsCAFile: string
} }
interface MongoDBQuery { interface MongoDBQuery {
@ -26,7 +31,8 @@ interface MongoDBQuery {
} }
} }
const SCHEMA: Integration = { const getSchema = () => {
let schema = {
docs: "https://github.com/mongodb/node-mongodb-native", docs: "https://github.com/mongodb/node-mongodb-native",
friendlyName: "MongoDB", friendlyName: "MongoDB",
type: "Non-relational", type: "Non-relational",
@ -37,10 +43,12 @@ const SCHEMA: Integration = {
type: DatasourceFieldType.STRING, type: DatasourceFieldType.STRING,
required: true, required: true,
default: "mongodb://localhost:27017", default: "mongodb://localhost:27017",
display: "Connection string",
}, },
db: { db: {
type: DatasourceFieldType.STRING, type: DatasourceFieldType.STRING,
required: true, required: true,
display: "DB",
}, },
}, },
query: { query: {
@ -71,7 +79,7 @@ const SCHEMA: Integration = {
"boundaries": [], "boundaries": [],
"default": "", "default": "",
"output": {} "output": {}
}`, }`,
}, },
{ {
key: "$bucketAuto", key: "$bucketAuto",
@ -80,7 +88,7 @@ const SCHEMA: Integration = {
"buckets": 1, "buckets": 1,
"output": {}, "output": {},
"granularity": "R5" "granularity": "R5"
}`, }`,
}, },
{ {
key: "$changeStream", key: "$changeStream",
@ -92,7 +100,7 @@ const SCHEMA: Integration = {
"showExpandedEvents": true, "showExpandedEvents": true,
"startAfter": {}, "startAfter": {},
"startAtOperationTime": "" "startAtOperationTime": ""
}`, }`,
}, },
{ {
key: "$collStats", key: "$collStats",
@ -101,7 +109,7 @@ const SCHEMA: Integration = {
"storageStats": { "scale": 1 } }, "storageStats": { "scale": 1 } },
"count": {}, "count": {},
"queryExecStats": {} "queryExecStats": {}
}`, }`,
}, },
{ {
key: "$count", key: "$count",
@ -117,7 +125,7 @@ const SCHEMA: Integration = {
"unit": 1, "unit": 1,
"bounds": "full" "bounds": "full"
} }
}`, }`,
}, },
{ {
key: "$documents", key: "$documents",
@ -134,7 +142,7 @@ const SCHEMA: Integration = {
"partitionByFields": [], "partitionByFields": [],
"sortBy": {}, "sortBy": {},
"output": {} "output": {}
}`, }`,
}, },
{ {
key: "$geoNear", key: "$geoNear",
@ -148,7 +156,7 @@ const SCHEMA: Integration = {
"key": "location", "key": "location",
"distanceField": "dist.calculated", "distanceField": "dist.calculated",
"query": { "category": "Parks" } "query": { "category": "Parks" }
}`, }`,
}, },
{ {
key: "$graphLookup", key: "$graphLookup",
@ -161,13 +169,13 @@ const SCHEMA: Integration = {
"maxDepth": 1, "maxDepth": 1,
"depthField": "", "depthField": "",
"restrictSearchWithMatch": {} "restrictSearchWithMatch": {}
}`, }`,
}, },
{ {
key: "$group", key: "$group",
template: `{ template: `{
"_id": "" "_id": ""
}`, }`,
}, },
{ {
key: "$indexStats", key: "$indexStats",
@ -192,7 +200,7 @@ const SCHEMA: Integration = {
"localField": "", "localField": "",
"foreignField": "", "foreignField": "",
"as": "" "as": ""
}`, }`,
}, },
{ {
key: "$match", key: "$match",
@ -205,14 +213,14 @@ const SCHEMA: Integration = {
"on": "_id", "on": "_id",
"whenMatched": "replace", "whenMatched": "replace",
"whenNotMatched": "insert" "whenNotMatched": "insert"
}`, }`,
}, },
{ {
key: "$out", key: "$out",
template: `{ template: `{
"db": "", "db": "",
"coll": "" "coll": ""
}`, }`,
}, },
{ {
key: "$planCacheStats", key: "$planCacheStats",
@ -248,7 +256,7 @@ const SCHEMA: Integration = {
"partitionBy": "", "partitionBy": "",
"sortBy": {}, "sortBy": {},
"output": {} "output": {}
}`, }`,
}, },
{ {
key: "$skip", key: "$skip",
@ -267,7 +275,7 @@ const SCHEMA: Integration = {
template: `{ template: `{
"coll": "", "coll": "",
"pipeline": [] "pipeline": []
}`, }`,
}, },
{ {
key: "$unset", key: "$unset",
@ -279,7 +287,7 @@ const SCHEMA: Integration = {
"path": "", "path": "",
"includeArrayIndex": "", "includeArrayIndex": "",
"preserveNullAndEmptyArrays": true "preserveNullAndEmptyArrays": true
}`, }`,
}, },
], ],
}, },
@ -303,15 +311,51 @@ const SCHEMA: Integration = {
}, },
}, },
}, },
}
if (environment.SELF_HOSTED) {
schema.datasource = {
...schema.datasource,
//@ts-ignore
tls: {
type: DatasourceFieldType.FIELD_GROUP,
display: "Configure SSL",
fields: {
tlsCertificateFile: {
type: DatasourceFieldType.STRING,
required: false,
display: "Certificate file path",
},
tlsCertificateKeyFile: {
type: DatasourceFieldType.STRING,
required: false,
display: "Certificate Key file path",
},
tlsCAFile: {
type: DatasourceFieldType.STRING,
required: false,
display: "CA file path",
},
},
},
}
}
return schema
} }
const SCHEMA: Integration = getSchema()
class MongoIntegration implements IntegrationBase { class MongoIntegration implements IntegrationBase {
private config: MongoDBConfig private config: MongoDBConfig
private client: any private client: any
constructor(config: MongoDBConfig) { constructor(config: MongoDBConfig) {
this.config = config this.config = config
this.client = new MongoClient(config.connectionString) const options: MongoClientOptions = {
tlsCertificateFile: config.tlsCertificateFile || undefined,
tlsCertificateKeyFile: config.tlsCertificateKeyFile || undefined,
tlsCAFile: config.tlsCAFile || undefined,
}
this.client = new MongoClient(config.connectionString, options)
} }
async connect() { async connect() {

View File

@ -33,6 +33,7 @@ export enum DatasourceFieldType {
OBJECT = "object", OBJECT = "object",
JSON = "json", JSON = "json",
FILE = "file", FILE = "file",
FIELD_GROUP = "fieldGroup",
} }
export enum SourceName { export enum SourceName {
@ -95,6 +96,16 @@ export interface ExtraQueryConfig {
} }
} }
export interface DatasourceConfig {
[key: string]: {
type: string
display?: string
required?: boolean
default?: any
deprecated?: boolean
}
}
export interface Integration { export interface Integration {
docs: string docs: string
plus?: boolean plus?: boolean
@ -104,7 +115,7 @@ export interface Integration {
friendlyName: string friendlyName: string
type?: string type?: string
iconUrl?: string iconUrl?: string
datasource: {} datasource: DatasourceConfig
query: { query: {
[key: string]: QueryDefinition [key: string]: QueryDefinition
} }