diff --git a/src/components/ingress-routing/IngressRoutingModal.jsx b/src/components/ingress-routing/IngressRoutingModal.jsx index db0e5c7b..810fd54f 100644 --- a/src/components/ingress-routing/IngressRoutingModal.jsx +++ b/src/components/ingress-routing/IngressRoutingModal.jsx @@ -88,6 +88,7 @@ const IngressRoutingModal = props => { form.validateFields().then(values => { values = Object.assign({}, formInitialValues, values) try { + values.url = values.url.trim() if (!values.allowSpecificHosts) values.allowedHosts = ["*"] if (!values.allowSpecificMethods) values.allowedMethods = ["*"] if (!values.performRewrite) values.rewrite = undefined diff --git a/src/components/security-rules/configure-rule/ConfigureRule.jsx b/src/components/security-rules/configure-rule/ConfigureRule.jsx index a2974b73..641c95cf 100644 --- a/src/components/security-rules/configure-rule/ConfigureRule.jsx +++ b/src/components/security-rules/configure-rule/ConfigureRule.jsx @@ -144,18 +144,11 @@ const parseNumber = (value) => { return !isNaN(value) ? Number(value) : value } -const parseArray = (value, type) => { - if (!value.includes(",")) { - return value - } - return value.split(",").map(value => value.trim()).map(value => parseValue(value, type)) -} - const isTypeOfFieldsString = (fields) => { return typeof fields === "string" } -const rules = ['allow', 'deny', 'authenticated', 'match', 'and', 'or', 'query', 'webhook', 'force', 'remove', 'encrypt', 'decrypt', 'hash']; +const rules = ['allow', 'deny', 'authenticated', 'match', 'and', 'or', 'query', 'webhook', 'force', 'remove', 'encrypt', 'decrypt', 'hash', 'graphql', 'transform']; const ConfigureRule = (props) => { // form @@ -165,7 +158,8 @@ const ConfigureRule = (props) => { const [col, setCol] = useState(''); // Derived properties - const { rule, type, f1, f2, error, fields, field, value, url, store, outputFormat, claims, requestTemplate, db, cache } = props.selectedRule; + const { rule, type, f1, f2, error, field, value, url, store, outputFormat, claims, requestTemplate, db, cache, graphqlQuery, graphqlVariables } = props.selectedRule; + let { fields } = props.selectedRule; const dbConfigs = useSelector(state => getDbConfigs(state)) const dbList = Object.keys(dbConfigs) const [selectedDb, setSelectedDb] = useState(db); @@ -181,7 +175,10 @@ const ConfigureRule = (props) => { switch (values.rule) { case "match": if (values.eval === 'in' || values.eval === 'notIn') { - values.f2 = parseArray(values.f2, values.type) + values.f2 = values.loadVar ? values.singleInputFields : values.multipleInputFields + delete values["loadVar"] + delete values["singleInputFields"] + delete values["multipleInputFields"] } else { values.f1 = parseValue(values.f1, values.type) values.f2 = parseValue(values.f2, values.type) @@ -215,6 +212,20 @@ const ConfigureRule = (props) => { delete values["applyTransformations"] break; + case "graphql": + try { + if (values.graphqlVariables) { + values.graphqlVariables = JSON.parse(values.graphqlVariables); + } + delete values["generateToken"] + } catch (ex) { + notify("error", "Error", ex.toString()) + return; + } + break; + case "transform": + values.template = "go" + break; } delete values.errorMsg; @@ -223,7 +234,7 @@ const ConfigureRule = (props) => { if (!props.selectedRule.clauses) values.clauses = []; else values.clauses = props.selectedRule.clauses } - if (values.rule === "query" || values.rule === "webhook" || values.rule === "force" || values.rule === "remove" || values.rule === "encrypt" || values.rule === "decrypt" || values.rule === "hash") { + if (values.rule === "query" || values.rule === "webhook" || values.rule === "force" || values.rule === "remove" || values.rule === "encrypt" || values.rule === "decrypt" || values.rule === "hash" || values.rule === "transform") { values.clause = props.selectedRule.clause values.fields = values.loadVar ? values.singleInputFields : values.multipleInputFields delete values["loadVar"] @@ -287,6 +298,7 @@ const ConfigureRule = (props) => { } const inheritedDataType = getTypeFromValue(value) + fields = rule === "match" ? f2 : fields const formInitialValues = { rule, type: (rule === "force") ? inheritedDataType : type, @@ -312,7 +324,9 @@ const ConfigureRule = (props) => { error, cacheResponse: cache ? true : false, cacheTTL: cache && cache.ttl !== undefined && cache.ttl !== null ? cache.ttl : undefined, - cacheInstantInvalidate: cache && cache.instantInvalidate !== undefined && cache.instantInvalidate !== null ? cache.instantInvalidate : undefined + cacheInstantInvalidate: cache && cache.instantInvalidate !== undefined && cache.instantInvalidate !== null ? cache.instantInvalidate : undefined, + graphqlQuery, + graphqlVariables : JSON.stringify(graphqlVariables, null, 2) } if (formInitialValues.type === "object") { @@ -393,9 +407,80 @@ const ConfigureRule = (props) => { () => { const type = form.getFieldValue("type") return ( - - - + <> + form.getFieldValue('eval') !== 'in' && form.getFieldValue('eval') !== 'notIn'} + > + + + + + form.getFieldValue('eval') === 'in' || form.getFieldValue('eval') === 'notIn'} + > + + + Load fields from a variable + + + form.getFieldValue('loadVar')}> + + + + + + + + + !form.getFieldValue('loadVar')}> + + {(fields, { add, remove }) => { + return ( + <> + {fields.map((field, index) => ( + + + + + + + + { + remove(field.name); + }} + /> + + + ))} + + + + + ); + }} + + + + ) } } @@ -685,6 +770,69 @@ const ConfigureRule = (props) => { + form.getFieldValue('rule') === 'graphql'} + > + + + + + + + + + + + + + + + Generate token + + + form.getFieldValue('generateToken') === true} + > + + + + + + + form.getFieldValue('rule') === "transform"} > + + + + + } + type='info' + showIcon + style={{ marginBottom: 21 }} + /> + + + + + + + + + diff --git a/src/components/security-rules/graph-editor/GraphEditor.jsx b/src/components/security-rules/graph-editor/GraphEditor.jsx index f0bc2e0d..5cc93073 100644 --- a/src/components/security-rules/graph-editor/GraphEditor.jsx +++ b/src/components/security-rules/graph-editor/GraphEditor.jsx @@ -152,7 +152,7 @@ function GraphEditor({ rule, setRule, ruleName, ruleMetaData, isCachingEnabled } } return } - if (selectedRuleObj.rule === "query" || selectedRuleObj.rule === "force" || selectedRuleObj.rule === "remove" || selectedRuleObj.rule === "encrypt" || selectedRuleObj.rule === "decrypt" || selectedRuleObj.rule === "hash") { + if (selectedRuleObj.rule === "query" || selectedRuleObj.rule === "force" || selectedRuleObj.rule === "remove" || selectedRuleObj.rule === "encrypt" || selectedRuleObj.rule === "decrypt" || selectedRuleObj.rule === "hash" || selectedRuleObj.rule === "transform") { if (strippedKey === "root") { setRule(dotProp.set(rule, "clause", copiedRule)) } else { diff --git a/src/components/security-rules/graph-editor/generateGraph.js b/src/components/security-rules/graph-editor/generateGraph.js index a48772a9..f9c14977 100644 --- a/src/components/security-rules/graph-editor/generateGraph.js +++ b/src/components/security-rules/graph-editor/generateGraph.js @@ -33,7 +33,7 @@ const convertRuleToGraph = (rule, id, parentId) => { graph.nodes.push({ id: `${id}.clauses.${len}`, label: "+ Add clause", group: "add_rule" }) graph.edges.push({ from: id, to: `${id}.clauses.${len}` }) } - if (rule.rule === "query" || rule.rule === "force" || rule.rule === "remove" || rule.rule === "encrypt" || rule.rule === "decrypt" || rule.rule === "hash") { + if (rule.rule === "query" || rule.rule === "force" || rule.rule === "remove" || rule.rule === "encrypt" || rule.rule === "decrypt" || rule.rule === "hash" || rule.rule === "transform") { if (rule.clause && rule.clause.rule) { graph = mergeGraph(graph, convertRuleToGraph(rule.clause, `${id}.clause`, id)) } else { diff --git a/src/graphql.js b/src/graphql.js index 43cc36ab..60f16227 100644 --- a/src/graphql.js +++ b/src/graphql.js @@ -7,7 +7,7 @@ import dotprop from "dot-prop-immutable"; const lorem = new LoremIpsum(); -const primitiveTypes = ["ID", "String", "Float", "Integer", "Boolean", "Date", "Time", "DateTime", "JSON", "SmallInteger", "BigInteger", "Decimal", "Char", "Varchar", "DateTimeWithZone"] +const primitiveTypes = ["ID", "String", "Float", "Integer", "Boolean", "Date", "Time", "DateTime", "JSON"] const getDefType = (type, isArray, required) => { isArray = isArray ? true : type.kind === "ListType"; required = required ? true : type.kind === "NonNullType"; @@ -183,18 +183,6 @@ const generateRandomValue = (type) => { return "2017-11-13T03:15:45.108Z" case "JSON": return { foo: "bar" } - case "SmallInteger": - return 12 - case "BigInteger": - return 4323 - case "Decimal": - return 23.84 - case "Char": - return "F919mV2W1ifQy9wlNyYnoOoqUM1" - case "Varchar": - return "7mr8VjGnCCerZUyzC9YDCn8Oxku" - case "DateTimeWithZone": - return "2021-11-22T03:15:45.108" default: return type } @@ -218,18 +206,6 @@ const generateRandomValue = (type) => { return new Date().toISOString() case "JSON": return { foo: "bar" } - case "SmallInteger": - return Math.ceil(Math.random() * 100) - case "BigInteger": - return Math.ceil(Math.random() * 10000) - case "Decimal": - return Number((Math.random() * 100).toFixed(2)) - case "Char": - return generateId(6) - case "Varchar": - return generateId(6) - case "DateTimeWithZone": - return new Date().toISOString() default: return type } diff --git a/src/graphql.test.js b/src/graphql.test.js index 4dd0f4e8..849be911 100644 --- a/src/graphql.test.js +++ b/src/graphql.test.js @@ -25,12 +25,6 @@ describe("generateSchemaAST method", () => { f19: String @link(table: mytype4, from: id, to: somefield, field: goodfield) f20: mytype5 @link(table: mytype5, from: id, to: nicefield) f21: [mytype6]! @link(table: mytype6, from: id, to: goodfield) - f22: SmallInteger - f23: BigInteger - f24: Decimal - f25: Char - f26: Varchar - f27: DateTimeWithZone } ` const expectedSchemaAST = { @@ -330,84 +324,6 @@ describe("generateSchemaAST method", () => { hasCreatedAtDirective: false, hasUpdatedAtDirective: false, hasNestedFields: true - }, - { - name: "f22", - type: "SmallInteger", - isRequired: false, - isPrimary: false, - hasUniqueConstraint: false, - hasForeignConstraint: false, - isLink: false, - isArray: false, - hasCreatedAtDirective: false, - hasUpdatedAtDirective: false, - hasNestedFields: false - }, - { - name: "f23", - type: "BigInteger", - isRequired: false, - isPrimary: false, - hasUniqueConstraint: false, - hasForeignConstraint: false, - isLink: false, - isArray: false, - hasCreatedAtDirective: false, - hasUpdatedAtDirective: false, - hasNestedFields: false - }, - { - name: "f24", - type: "Decimal", - isRequired: false, - isPrimary: false, - hasUniqueConstraint: false, - hasForeignConstraint: false, - isLink: false, - isArray: false, - hasCreatedAtDirective: false, - hasUpdatedAtDirective: false, - hasNestedFields: false - }, - { - name: "f25", - type: "Char", - isRequired: false, - isPrimary: false, - hasUniqueConstraint: false, - hasForeignConstraint: false, - isLink: false, - isArray: false, - hasCreatedAtDirective: false, - hasUpdatedAtDirective: false, - hasNestedFields: false - }, - { - name: "f26", - type: "Varchar", - isRequired: false, - isPrimary: false, - hasUniqueConstraint: false, - hasForeignConstraint: false, - isLink: false, - isArray: false, - hasCreatedAtDirective: false, - hasUpdatedAtDirective: false, - hasNestedFields: false - }, - { - name: "f27", - type: "DateTimeWithZone", - isRequired: false, - isPrimary: false, - hasUniqueConstraint: false, - hasForeignConstraint: false, - isLink: false, - isArray: false, - hasCreatedAtDirective: false, - hasUpdatedAtDirective: false, - hasNestedFields: false } ] } @@ -549,30 +465,6 @@ describe("generateRandomFieldValues method", () => { { name: "k9", type: "JSON" - }, - { - name: "k10", - type: "SmallInteger" - }, - { - name: "k11", - type: "BigInteger" - }, - { - name: "k12", - type: "Decimal" - }, - { - name: "k13", - type: "Char" - }, - { - name: "k14", - type: "Varchar" - }, - { - name: "k15", - type: "DateTimeWithZone" } ] const result = { @@ -586,13 +478,7 @@ describe("generateRandomFieldValues method", () => { k8: "2017-11-13T03:15:45.108Z", k9: { foo: "bar" - }, - k10: 12, - k11: 4323, - k12: 23.84, - k13: "F919mV2W1ifQy9wlNyYnoOoqUM1", - k14: "7mr8VjGnCCerZUyzC9YDCn8Oxku", - k15: "2021-11-22T03:15:45.108" + } } expect(generateRandomFieldValues(fields)).toEqual(result) }) diff --git a/src/pages/database/browse/DBBrowse.jsx b/src/pages/database/browse/DBBrowse.jsx index 97cfc414..005cc2cc 100644 --- a/src/pages/database/browse/DBBrowse.jsx +++ b/src/pages/database/browse/DBBrowse.jsx @@ -14,7 +14,7 @@ import InfiniteScrollingTable from "../../../components/utils/infinite-scrolling import { notify, incrementPendingRequests, decrementPendingRequests } from '../../../utils'; import { generateSchemaAST } from "../../../graphql"; import { Button, Select, Popconfirm } from "antd"; -import { FilterOutlined, PlusOutlined } from "@ant-design/icons"; +import { FilterOutlined, PlusOutlined, ReloadOutlined } from "@ant-design/icons"; import { API, cond } from "space-api"; import { spaceCloudClusterOrigin, projectModules } from "../../../constants" import { getCollectionSchema, getDbType, getTrackedCollections } from '../../../operations/database'; @@ -337,6 +337,14 @@ const Browse = () => { }) } + const refreshTableData = () => { + if (selectedCol) { + getTableData(); + } else { + notify("error", "Error", "No column selected"); + } + } + const tableColumns = getColumnNames(colSchemaFields, tableData) return ( @@ -365,6 +373,7 @@ const Browse = () => { > {collections.map(col => {col})} + {colSchemaFields && ( <> diff --git a/src/pages/deployments/overview/DeploymentsOverview.jsx b/src/pages/deployments/overview/DeploymentsOverview.jsx index 7ca7633d..c8ed6ea3 100644 --- a/src/pages/deployments/overview/DeploymentsOverview.jsx +++ b/src/pages/deployments/overview/DeploymentsOverview.jsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; import { useParams, useHistory } from "react-router-dom"; import { useSelector, useDispatch } from "react-redux"; -import { Button, Table, Popconfirm, Tag, Input, Empty } from "antd"; +import { Button, Table, Popconfirm, Tag, Input, Empty, Typography } from "antd"; import Sidenav from "../../../components/sidenav/Sidenav"; import Topbar from "../../../components/topbar/Topbar"; import DeploymentTabs from "../../../components/deployments/deployment-tabs/DeploymentTabs"; @@ -177,7 +177,7 @@ const DeploymentsOverview = () => { { title: "Private URL", key: "url", - render: (_, record) => `${record.id}.${projectID}.svc.cluster.local` + render: (_, record) => {`${record.id}.${projectID}.svc.cluster.local`} }, { title: "Status",