Skip to content
Open
1 change: 1 addition & 0 deletions src/components/ingress-routing/IngressRoutingModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
181 changes: 166 additions & 15 deletions src/components/security-rules/configure-rule/ConfigureRule.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -213,6 +210,15 @@ const ConfigureRule = (props) => {
values.template = "go"
}

delete values["applyTransformations"]
break;
case "graphql":
break;
case "transform":
if (values["applyTransformations"]) {
values.template = "go"
}

delete values["applyTransformations"]
break;
}
Expand All @@ -223,7 +229,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 === "graphql" || values.rule === "transform") {
values.clause = props.selectedRule.clause
values.fields = values.loadVar ? values.singleInputFields : values.multipleInputFields
delete values["loadVar"]
Expand Down Expand Up @@ -287,6 +293,7 @@ const ConfigureRule = (props) => {
}

const inheritedDataType = getTypeFromValue(value)
fields = rule === "match" ? f2 : fields
const formInitialValues = {
rule,
type: (rule === "force") ? inheritedDataType : type,
Expand All @@ -312,7 +319,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
}

if (formInitialValues.type === "object") {
Expand Down Expand Up @@ -393,9 +402,80 @@ const ConfigureRule = (props) => {
() => {
const type = form.getFieldValue("type")
return (
<Form.Item name='f2' rules={[{ required: true }, { validator: createValueAndTypeValidator(type, true) }]}>
<ObjectAutoComplete placeholder="Second operand" options={autoCompleteOptions} />
</Form.Item>
<>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this?

<ConditionalFormBlock
dependency='eval'
condition={() => form.getFieldValue('eval') !== 'in' && form.getFieldValue('eval') !== 'notIn'}
>
<Form.Item name='f2' rules={[{ required: true }, { validator: createValueAndTypeValidator(type, true) }]}>
<ObjectAutoComplete placeholder="Second operand" options={autoCompleteOptions} />
</Form.Item>
</ConditionalFormBlock>
<ConditionalFormBlock
dependency='eval'
condition={() => form.getFieldValue('eval') === 'in' || form.getFieldValue('eval') === 'notIn'}
>
<Form.Item name="loadVar" valuePropName="checked">
<Checkbox>
Load fields from a variable
</Checkbox>
</Form.Item>
<ConditionalFormBlock dependency='loadVar' condition={() => form.getFieldValue('loadVar')}>
<Row>
<Col span={14}>
<Form.Item name="singleInputFields">
<Input placeholder="Variable to load fields from" />
</Form.Item>
</Col>
</Row>
</ConditionalFormBlock>
<ConditionalFormBlock dependency='loadVar' condition={() => !form.getFieldValue('loadVar')}>
<Form.List name='multipleInputFields'>
{(fields, { add, remove }) => {
return (
<>
{fields.map((field, index) => (
<Row key={field.key}>
<Col span={14}>
<Form.Item
name={[field.name]}
key={[field.name]}
rules={[
{ required: true },
{ validator: createValueAndTypeValidator("variable", false), validateTrigger: "onBlur" }
]}
>
<ObjectAutoComplete placeholder="Field" options={autoCompleteOptions} />
</Form.Item>
</Col>
<Col span={2}>
<CloseOutlined
style={{ margin: '0 8px' }}
onClick={() => {
remove(field.name);
}}
/>
</Col>
</Row>
))}
<Form.Item>
<Button
type='dashed'
onClick={() => {
add();
}}
style={{ width: '40%' }}
>
<PlusOutlined /> Add field
</Button>
</Form.Item>
</>
);
}}
</Form.List>
</ConditionalFormBlock>
</ConditionalFormBlock>
</>
)
}
}
Expand Down Expand Up @@ -685,6 +765,77 @@ const ConfigureRule = (props) => {
</ConditionalFormBlock>
</ConditionalFormBlock>
</ConditionalFormBlock>
<ConditionalFormBlock
dependency='rule'
condition={() => form.getFieldValue('rule') === 'graphql'}
>
<FormItemLabel name='Query' style={{ border: '1px solid #D9D9D9' }} />
<Form.Item name="graphqlQuery" rules={[{ required: true }]}>
<JSONCodeMirror />
</Form.Item>
<FormItemLabel name='Variables' style={{ border: '1px solid #D9D9D9' }} />
<Form.Item name="graphqlVariables" rules={[{ required: true }]}>
<JSONCodeMirror />
</Form.Item>
<FormItemLabel name="Store" hint="(Optional)" />
<FormItem name="store" rules={[{ required: false }]}>
<Input placeholder="The variable to store the query response. For example: args.res" />
</FormItem>
</ConditionalFormBlock>
<ConditionalFormBlock
dependency="rule"
condition={() => form.getFieldValue('rule') === "transform"} >
<FormItemLabel name="Store" hint="(Optional)" />
<FormItem name="store" rules={[{ required: false }]}>
<Input placeholder="The variable to store the transform response. For example: args.res" />
</FormItem>
<FormItemLabel name='Apply transformations' />
<Form.Item name='applyTransformations' valuePropName='checked'>
<Checkbox>
Transform the request body using templates
</Checkbox>
</Form.Item>
<ConditionalFormBlock
dependency='applyTransformations'
condition={() => form.getFieldValue('applyTransformations') === true}
>
<Alert
message={<AlertMsgApplyTransformations />}
type='info'
showIcon
style={{ marginBottom: 21 }}
/>
<FormItemLabel name="Template output format" description="Format for parsing the template output" />
<Form.Item name="outputFormat">
<Select style={{ width: 96 }}>
<Option value='yaml'>YAML</Option>
<Option value='json'>JSON</Option>
</Select>
</Form.Item>
<FormItemLabel name="JWT claims template" hint="(Optional)" description="Template to generate the transformed claims of the request" />
<Form.Item name="claims">
<AntCodeMirror style={{ border: "1px solid #D9D9D9" }} options={{
mode: { name: 'go' },
lineNumbers: true,
styleActiveLine: true,
matchBrackets: true,
autoCloseBrackets: true,
tabSize: 2
}} />
</Form.Item>
<FormItemLabel name="Request template" hint="(Optional)" description="Template to generate the transformed request body" />
<Form.Item name='requestTemplate' >
<AntCodeMirror style={{ border: "1px solid #D9D9D9" }} options={{
mode: { name: 'go' },
lineNumbers: true,
styleActiveLine: true,
matchBrackets: true,
autoCloseBrackets: true,
tabSize: 2
}} />
</Form.Item>
</ConditionalFormBlock>
</ConditionalFormBlock>
<FormItemLabel name='Customize error message' />
<Form.Item name='errorMsg' valuePropName='checked'>
<Checkbox checked={error ? true : false}>
Expand Down
11 changes: 10 additions & 1 deletion src/pages/database/browse/DBBrowse.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -337,6 +337,14 @@ const Browse = () => {
})
}

const refreshTableData = () => {
if (selectedCol) {
getTableData();
} else {
notify("error", "Error", "No column selected");
}
}

const tableColumns = getColumnNames(colSchemaFields, tableData)
return (
<React.Fragment>
Expand Down Expand Up @@ -365,6 +373,7 @@ const Browse = () => {
>
{collections.map(col => <Select.Option value={col}>{col}</Select.Option>)}
</Select>
<Button onClick={refreshTableData} style={{ marginRight: 24 }}>Refresh <ReloadOutlined /></Button>
{colSchemaFields && (
<>
<Button onClick={() => setFilterSorterFormVisibility(true)}>Filters & Sorters <FilterOutlined /></Button>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/deployments/overview/DeploymentsOverview.jsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -177,7 +177,7 @@ const DeploymentsOverview = () => {
{
title: "Private URL",
key: "url",
render: (_, record) => `${record.id}.${projectID}.svc.cluster.local`
render: (_, record) => <Typography.Paragraph copyable={true}>{`${record.id}.${projectID}.svc.cluster.local`}</Typography.Paragraph>
},
{
title: "Status",
Expand Down