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",