Skip to content

Commit 0298eee

Browse files
authored
Merge branch 'cyclops-ui:main' into main
2 parents 5118c95 + 667beec commit 0298eee

File tree

19 files changed

+781
-180
lines changed

19 files changed

+781
-180
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Cyclops can either be installed manually by applying the latest manifest, by usi
4949
To install Cyclops using `kubectl` into your cluster, run the commands below:
5050

5151
```bash
52-
kubectl apply -f https://raw.githubusercontent.com/cyclops-ui/cyclops/v0.14.1/install/cyclops-install.yaml && kubectl apply -f https://raw.githubusercontent.com/cyclops-ui/cyclops/v0.14.1/install/demo-templates.yaml
52+
kubectl apply -f https://raw.githubusercontent.com/cyclops-ui/cyclops/v0.15.2/install/cyclops-install.yaml && kubectl apply -f https://raw.githubusercontent.com/cyclops-ui/cyclops/v0.15.2/install/demo-templates.yaml
5353
```
5454

5555
It will create a new namespace called `cyclops` and deploy everything you need for your Cyclops instance to run.

cyclops-ctrl/config/crd/kustomization.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
# It should be run by config/default
44
resources:
55
- bases/cyclops-ui.com_modules.yaml
6+
- bases/cyclops-ui.com_templateauthrules.yaml
7+
- bases/cyclops-ui.com_templatestores.yaml
68
#+kubebuilder:scaffold:crdkustomizeresource
79

810
patchesStrategicMerge:

cyclops-ctrl/internal/mapper/helm.go

+27
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import (
99
)
1010

1111
func HelmSchemaToFields(name string, schema helm.Property, defs map[string]helm.Property, dependencies []*models.Template) models.Field {
12+
if shouldResolvePropertyComposition(schema) {
13+
return HelmSchemaToFields(name, resolvePropertyComposition(schema), defs, dependencies)
14+
}
15+
1216
if schema.Type == "array" {
1317
return models.Field{
1418
Name: name,
@@ -211,3 +215,26 @@ func resolveJSONSchemaRef(defs map[string]helm.Property, ref []string) helm.Prop
211215

212216
return resolveJSONSchemaRef(def.Properties, ref[1:])
213217
}
218+
219+
func shouldResolvePropertyComposition(schema helm.Property) bool {
220+
return len(schema.AnyOf) != 0
221+
}
222+
223+
func resolvePropertyComposition(schema helm.Property) helm.Property {
224+
if len(schema.AnyOf) == 0 {
225+
return schema
226+
}
227+
228+
// go over all options of anyOf and if there is a boolean version, return it.
229+
// If a field can be represented with a boolean we should use it since it is
230+
// the easiest way to input a correct value.
231+
//
232+
// If there are multiple boolean anyOfs, return the first one.
233+
for _, p := range schema.AnyOf {
234+
if p.Type == "boolean" {
235+
return p
236+
}
237+
}
238+
239+
return schema.AnyOf[0]
240+
}

cyclops-ctrl/internal/models/helm/helmschema.go

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ type Property struct {
3131
MinLength *int `json:"minLength"`
3232
MaxLength *int `json:"maxLength"`
3333
Pattern *string `json:"pattern"`
34+
35+
// schema compositions
36+
AnyOf []Property `json:"anyOf"`
3437
}
3538

3639
type PropertyType string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import React, { useCallback, useEffect, useState } from "react";
2+
import { Col, Divider, Row, Alert, Table, Tag } from "antd";
3+
import axios from "axios";
4+
import { mapResponseError } from "../../utils/api/errors";
5+
6+
interface Props {
7+
name: string;
8+
}
9+
10+
interface Rule {
11+
verbs?: string[];
12+
apiGroups?: string[];
13+
resources?: string[];
14+
nonResourceURLs?: string[];
15+
}
16+
17+
interface ClusterRoleData {
18+
rules: Rule[];
19+
}
20+
21+
const ClusterRole = ({ name }: Props) => {
22+
const [clusterRole, setClusterRole] = useState<ClusterRoleData>({
23+
rules: [],
24+
});
25+
26+
const [error, setError] = useState({
27+
message: "",
28+
description: "",
29+
});
30+
31+
const fetchClusterRole = useCallback(() => {
32+
axios
33+
.get(`/api/resources`, {
34+
params: {
35+
group: `rbac.authorization.k8s.io`,
36+
version: `v1`,
37+
kind: `ClusterRole`,
38+
name: name,
39+
},
40+
})
41+
.then((res) => {
42+
setClusterRole({
43+
rules: res.data.rules || [],
44+
});
45+
})
46+
.catch((error) => {
47+
setError(mapResponseError(error));
48+
});
49+
}, [name]);
50+
51+
useEffect(() => {
52+
fetchClusterRole();
53+
54+
const interval = setInterval(() => fetchClusterRole(), 15000);
55+
return () => {
56+
clearInterval(interval);
57+
};
58+
}, [fetchClusterRole]);
59+
60+
const columns = [
61+
{
62+
title: "Verbs",
63+
dataIndex: "verbs",
64+
key: "verbs",
65+
render: (verbs?: string[]) => (
66+
<>
67+
{verbs?.map((verb) => (
68+
<Tag key={verb} color="orange">
69+
{verb}
70+
</Tag>
71+
))}
72+
</>
73+
),
74+
},
75+
{
76+
title: "API Groups",
77+
dataIndex: "apiGroups",
78+
key: "apiGroups",
79+
render: (apiGroups?: string[]) => (
80+
<>
81+
{apiGroups?.map((group) => (
82+
<Tag key={group} color="blue">
83+
{group || "*"}
84+
</Tag>
85+
))}
86+
</>
87+
),
88+
},
89+
{
90+
title: "Resources",
91+
dataIndex: "resources",
92+
key: "resources",
93+
render: (resources?: string[]) => (
94+
<>
95+
{resources?.map((resource) => (
96+
<Tag key={resource} color="green">
97+
{resource}
98+
</Tag>
99+
))}
100+
</>
101+
),
102+
},
103+
];
104+
105+
if (clusterRole.rules.some((rule) => rule.nonResourceURLs)) {
106+
columns.push({
107+
title: "Non resource URLs",
108+
dataIndex: "nonResourceURLs",
109+
key: "nonResourceURLs",
110+
render: (nonResourceURLs?: string[]) => (
111+
<>
112+
{nonResourceURLs?.map((url) => (
113+
<Tag key={url} color="purple">
114+
{url}
115+
</Tag>
116+
))}
117+
</>
118+
),
119+
});
120+
}
121+
122+
return (
123+
<div>
124+
{error.message.length !== 0 && (
125+
<Alert
126+
message={error.message}
127+
description={error.description}
128+
type="error"
129+
closable
130+
afterClose={() => {
131+
setError({
132+
message: "",
133+
description: "",
134+
});
135+
}}
136+
style={{ marginBottom: "20px" }}
137+
/>
138+
)}
139+
<Divider
140+
style={{ fontSize: "120%" }}
141+
orientationMargin="0"
142+
orientation={"left"}
143+
>
144+
Rules
145+
</Divider>
146+
<Row>
147+
<Col span={24} style={{ overflowX: "auto" }}>
148+
<Table dataSource={clusterRole.rules} columns={columns} />
149+
</Col>
150+
</Row>
151+
</div>
152+
);
153+
};
154+
155+
export default ClusterRole;

cyclops-ui/src/components/k8s-resources/ResourceList/ResourceList.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import DaemonSet from "../DaemonSet";
2727
import StatefulSet from "../StatefulSet";
2828
import Pod from "../Pod";
2929
import Service from "../Service";
30+
import ClusterRole from "../ClusterRole";
3031
import ConfigMap from "../ConfigMap";
3132
import PersistentVolumeClaim from "../PersistentVolumeClaim";
3233
import Secret from "../Secret";
@@ -329,6 +330,9 @@ const ResourceList = ({
329330
<Secret name={resource.name} namespace={resource.namespace} />
330331
);
331332
break;
333+
case "ClusterRole":
334+
resourceDetails = <ClusterRole name={resource.name} />;
335+
break;
332336
}
333337

334338
let deletedWarning = <p />;

cyclops-ui/src/components/pages/EditModule/EditModule.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ const EditModule = () => {
148148
setValues(values);
149149
setPreviousValues(res.data.values);
150150
} else {
151-
console.log(result);
152151
setError(result.error);
153152
}
154153

0 commit comments

Comments
 (0)