@superblocksteam/cli 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -4
- package/assets/custom-components/example/component.tsx +86 -0
- package/assets/custom-components/example/main.scss +75 -0
- package/assets/custom-components/example/validation.tsx +41 -0
- package/assets/custom-components/{package.json → setup/package.json} +1 -1
- package/dist/commands/components/create.d.ts +2 -0
- package/dist/commands/components/create.js +72 -9
- package/dist/commands/components/upload.js +1 -1
- package/dist/commands/components/watch.js +1 -1
- package/dist/commands/config/set.d.ts +11 -0
- package/dist/commands/config/set.js +79 -0
- package/dist/commands/init.js +2 -3
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +20 -26
- package/dist/common/authenticated-command.js +11 -6
- package/dist/common/version-control.d.ts +1 -1
- package/dist/common/version-control.js +4 -4
- package/oclif.manifest.json +31 -9
- package/package.json +4 -1
- /package/assets/custom-components/{.eslintrc.js → setup/.eslintrc.js} +0 -0
- /package/assets/custom-components/{tsconfig.json → setup/tsconfig.json} +0 -0
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ $ npm install -g @superblocksteam/cli
|
|
|
12
12
|
$ superblocks COMMAND
|
|
13
13
|
running command...
|
|
14
14
|
$ superblocks (--version)
|
|
15
|
-
@superblocksteam/cli/0.0.
|
|
15
|
+
@superblocksteam/cli/0.0.18 linux-x64 node-v18.17.0
|
|
16
16
|
$ superblocks --help [COMMAND]
|
|
17
17
|
USAGE
|
|
18
18
|
$ superblocks COMMAND
|
|
@@ -25,6 +25,7 @@ USAGE
|
|
|
25
25
|
* [`superblocks components register`](#superblocks-components-register)
|
|
26
26
|
* [`superblocks components upload`](#superblocks-components-upload)
|
|
27
27
|
* [`superblocks components watch`](#superblocks-components-watch)
|
|
28
|
+
* [`superblocks config set PROPERTY VALUE`](#superblocks-config-set-property-value)
|
|
28
29
|
* [`superblocks help [COMMANDS]`](#superblocks-help-commands)
|
|
29
30
|
* [`superblocks init [RESOURCEURL]`](#superblocks-init-resourceurl)
|
|
30
31
|
* [`superblocks login`](#superblocks-login)
|
|
@@ -84,6 +85,28 @@ DESCRIPTION
|
|
|
84
85
|
watch for changes to your custom components
|
|
85
86
|
```
|
|
86
87
|
|
|
88
|
+
## `superblocks config set PROPERTY VALUE`
|
|
89
|
+
|
|
90
|
+
Sets the specified property in your Superblocks configuration. A property governs the behavior of the Superblocks CLI, such as Superblocks region to interact with
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
USAGE
|
|
94
|
+
$ superblocks config set PROPERTY VALUE
|
|
95
|
+
|
|
96
|
+
ARGUMENTS
|
|
97
|
+
PROPERTY (domain) Superblocks config name, e.g. domain
|
|
98
|
+
VALUE Superblocks config value
|
|
99
|
+
|
|
100
|
+
DESCRIPTION
|
|
101
|
+
Sets the specified property in your Superblocks configuration. A property governs the behavior of the Superblocks CLI,
|
|
102
|
+
such as Superblocks region to interact with
|
|
103
|
+
|
|
104
|
+
EXAMPLES
|
|
105
|
+
$ superblocks config set domain eu.superblocks.com
|
|
106
|
+
|
|
107
|
+
$ superblocks config set domain app.superblocks.com
|
|
108
|
+
```
|
|
109
|
+
|
|
87
110
|
## `superblocks help [COMMANDS]`
|
|
88
111
|
|
|
89
112
|
Display help for superblocks.
|
|
@@ -135,11 +158,10 @@ Authenticates with Superblocks cloud
|
|
|
135
158
|
|
|
136
159
|
```
|
|
137
160
|
USAGE
|
|
138
|
-
$ superblocks login [-t <value>]
|
|
161
|
+
$ superblocks login [-t <value>]
|
|
139
162
|
|
|
140
163
|
FLAGS
|
|
141
|
-
-
|
|
142
|
-
-t, --token=<value> Superblocks user access token
|
|
164
|
+
-t, --token=<value> Superblocks user API key
|
|
143
165
|
|
|
144
166
|
DESCRIPTION
|
|
145
167
|
Authenticates with Superblocks cloud
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React, { useCallback, useState } from "react";
|
|
2
|
+
import { Task, ErrorComponent, validateTasks } from "./validation";
|
|
3
|
+
import { Props } from "./types";
|
|
4
|
+
import "./main.scss";
|
|
5
|
+
|
|
6
|
+
export default function Component({
|
|
7
|
+
updateStatefulProperties,
|
|
8
|
+
tasks,
|
|
9
|
+
onTaskAdded,
|
|
10
|
+
onTaskStatusChanged,
|
|
11
|
+
}: Props) {
|
|
12
|
+
const { validatedTasks, hasError } = validateTasks(tasks);
|
|
13
|
+
const [value, setValue] = useState("");
|
|
14
|
+
|
|
15
|
+
const onTodoAdded = useCallback(() => {
|
|
16
|
+
const id = Math.random().toString(36).substring(2, 8);
|
|
17
|
+
updateStatefulProperties({
|
|
18
|
+
tasks: {
|
|
19
|
+
...validatedTasks,
|
|
20
|
+
[id]: {
|
|
21
|
+
taskName: value,
|
|
22
|
+
taskStatus: "todo",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
onTaskAdded();
|
|
27
|
+
}, [updateStatefulProperties, validatedTasks, value, onTaskAdded]);
|
|
28
|
+
|
|
29
|
+
const onTaskStatusChange = useCallback(
|
|
30
|
+
(id: string, status: boolean) => {
|
|
31
|
+
updateStatefulProperties({
|
|
32
|
+
tasks: {
|
|
33
|
+
...validatedTasks,
|
|
34
|
+
[id]: {
|
|
35
|
+
...tasks[id],
|
|
36
|
+
taskStatus: status ? "complete" : "todo",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
onTaskStatusChanged();
|
|
41
|
+
},
|
|
42
|
+
[updateStatefulProperties, validatedTasks, tasks, onTaskStatusChanged]
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
return hasError ? (
|
|
46
|
+
<ErrorComponent />
|
|
47
|
+
) : (
|
|
48
|
+
<div className="sb-example-root">
|
|
49
|
+
<h2>Todo List</h2>
|
|
50
|
+
<div className="horizontal-layout">
|
|
51
|
+
<input
|
|
52
|
+
type="text"
|
|
53
|
+
value={value}
|
|
54
|
+
className="fill"
|
|
55
|
+
placeholder="Add a new item"
|
|
56
|
+
onChange={(e) => setValue(e.target.value)}
|
|
57
|
+
// Prevents the event from bubbling up to the parent (i.e. prevent arrow keys from moving custom component in Superblocks editor)
|
|
58
|
+
onKeyDown={(e) => e.stopPropagation()}
|
|
59
|
+
/>
|
|
60
|
+
<button onClick={onTodoAdded}>Add Todo</button>
|
|
61
|
+
</div>
|
|
62
|
+
<div className="checkboxes">
|
|
63
|
+
{Object.entries(validatedTasks).map(
|
|
64
|
+
([id, task]: [string, Task], idx) => (
|
|
65
|
+
<div key={idx} className="horizontal-layout">
|
|
66
|
+
<input
|
|
67
|
+
type="checkbox"
|
|
68
|
+
checked={task.taskStatus === "complete"}
|
|
69
|
+
onChange={(e) => onTaskStatusChange(id, e.target.checked)}
|
|
70
|
+
/>
|
|
71
|
+
<p>
|
|
72
|
+
<span
|
|
73
|
+
className={
|
|
74
|
+
task.taskStatus === "complete" ? "is-complete" : ""
|
|
75
|
+
}
|
|
76
|
+
>
|
|
77
|
+
{task.taskName}
|
|
78
|
+
</span>
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
)
|
|
82
|
+
)}
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// We recommend scoping your styles with a unique classname
|
|
2
|
+
// that won't affect other styles on the page
|
|
3
|
+
// alternatively, you can use CSS modules
|
|
4
|
+
.sb-example-root {
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
background-color: #27374d;
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
font-size: 16px;
|
|
11
|
+
font-weight: 600;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
gap: 12px;
|
|
14
|
+
|
|
15
|
+
h1, h2, h3, h4, h5, p, pre {
|
|
16
|
+
color: white;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
p {
|
|
20
|
+
margin: 0px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
input {
|
|
24
|
+
font: inherit;
|
|
25
|
+
padding: 10px 24px;
|
|
26
|
+
border-radius: 8px;
|
|
27
|
+
color: black;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
button {
|
|
31
|
+
display: inline-block;
|
|
32
|
+
outline: none;
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
line-height: 20px;
|
|
35
|
+
border-radius: 8px;
|
|
36
|
+
padding: 14px 24px;
|
|
37
|
+
border: none;
|
|
38
|
+
transition:
|
|
39
|
+
box-shadow 0.2s ease 0s,
|
|
40
|
+
-ms-transform 0.1s ease 0s,
|
|
41
|
+
-webkit-transform 0.1s ease 0s,
|
|
42
|
+
transform 0.1s ease 0s;
|
|
43
|
+
background: linear-gradient(
|
|
44
|
+
to right,
|
|
45
|
+
rgb(230, 30, 77) 0%,
|
|
46
|
+
rgb(227, 28, 95) 50%,
|
|
47
|
+
rgb(215, 4, 102) 100%
|
|
48
|
+
);
|
|
49
|
+
color: #fff;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
button:active {
|
|
53
|
+
background: linear-gradient(
|
|
54
|
+
to right,
|
|
55
|
+
rgb(198, 20, 61) 0%,
|
|
56
|
+
rgb(188, 8, 68) 50%,
|
|
57
|
+
rgb(208, 0, 97) 100%
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.fill {
|
|
62
|
+
flex-grow: 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.horizontal-layout {
|
|
66
|
+
display: flex;
|
|
67
|
+
align-items: center;
|
|
68
|
+
text-align: center;
|
|
69
|
+
gap: 8px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.is-complete {
|
|
73
|
+
text-decoration: line-through;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface Task {
|
|
2
|
+
taskName: string;
|
|
3
|
+
taskStatus: "todo" | "complete";
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export const validateTasks = (tasks: any) => {
|
|
7
|
+
return {
|
|
8
|
+
validatedTasks: tasks as Record<string, Task>,
|
|
9
|
+
hasError:
|
|
10
|
+
typeof tasks !== "object" ||
|
|
11
|
+
Array.isArray(tasks) ||
|
|
12
|
+
Object.values(tasks).some((task: any) => {
|
|
13
|
+
return (
|
|
14
|
+
typeof task !== "object" ||
|
|
15
|
+
Array.isArray(task) ||
|
|
16
|
+
!("taskName" in task) ||
|
|
17
|
+
!("taskStatus" in task) ||
|
|
18
|
+
typeof task.taskName !== "string" ||
|
|
19
|
+
typeof task.taskStatus !== "string" ||
|
|
20
|
+
!["todo", "complete"].includes(task.taskStatus)
|
|
21
|
+
);
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const ErrorComponent: React.FC = () => {
|
|
27
|
+
return (
|
|
28
|
+
<div className="sb-example-root">
|
|
29
|
+
<h3>Invalid Tasks List!</h3>
|
|
30
|
+
<p>Tasks should be of the format:</p>
|
|
31
|
+
<pre>
|
|
32
|
+
{`{
|
|
33
|
+
"<task-id>": {
|
|
34
|
+
taskName: "<task-name>",
|
|
35
|
+
taskStatus: "todo" | "complete",
|
|
36
|
+
},
|
|
37
|
+
...}`}
|
|
38
|
+
</pre>
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AuthenticatedApplicationCommand } from "../../common/authenticated-command";
|
|
2
2
|
export default class CreateComponent extends AuthenticatedApplicationCommand {
|
|
3
3
|
static description: string;
|
|
4
|
+
private initializeComponentByWizard;
|
|
5
|
+
private initializeComponentByExample;
|
|
4
6
|
run(): Promise<void>;
|
|
5
7
|
}
|
|
@@ -17,7 +17,8 @@ const create_component_defaults_1 = require("../../common/defaults/create-compon
|
|
|
17
17
|
const identifiers_1 = require("../../util/identifiers");
|
|
18
18
|
// eslint-disable-next-line unicorn/prefer-module
|
|
19
19
|
const rootDirectory = node_path_1.default.resolve(__dirname, "../../../");
|
|
20
|
-
const DEFAULT_PACKAGE_JSON_TEMPLATE_PATH = node_path_1.default.resolve(rootDirectory, "assets/custom-components");
|
|
20
|
+
const DEFAULT_PACKAGE_JSON_TEMPLATE_PATH = node_path_1.default.resolve(rootDirectory, "assets/custom-components/setup");
|
|
21
|
+
const DEFAULT_EXAMPLE_COMPONENT_TEMPLATE_PATH = node_path_1.default.resolve(rootDirectory, "assets/custom-components/example");
|
|
21
22
|
const tsStringify = (obj) => {
|
|
22
23
|
const entries = Object.entries(obj);
|
|
23
24
|
const stringifiedEntries = entries.map(([key, value]) => {
|
|
@@ -26,7 +27,7 @@ const tsStringify = (obj) => {
|
|
|
26
27
|
return `{\n${stringifiedEntries.join(",\n")}\n},\n`;
|
|
27
28
|
};
|
|
28
29
|
class CreateComponent extends authenticated_command_1.AuthenticatedApplicationCommand {
|
|
29
|
-
async
|
|
30
|
+
async initializeComponentByWizard(isFirstTimeCreate) {
|
|
30
31
|
const displayName = (await (0, enquirer_1.prompt)({
|
|
31
32
|
type: "input",
|
|
32
33
|
name: "displayName",
|
|
@@ -163,28 +164,90 @@ class CreateComponent extends authenticated_command_1.AuthenticatedApplicationCo
|
|
|
163
164
|
.join(""),
|
|
164
165
|
});
|
|
165
166
|
const componentTsx = (0, create_component_defaults_1.getDefaultComponentTsx)(statefulProps, eventHandlers.map((prop) => prop.path));
|
|
166
|
-
|
|
167
|
-
if (!packageJsonExists) {
|
|
167
|
+
if (isFirstTimeCreate) {
|
|
168
168
|
await fs.copy(DEFAULT_PACKAGE_JSON_TEMPLATE_PATH, ".");
|
|
169
169
|
}
|
|
170
170
|
await fs.ensureDir("components/" + name);
|
|
171
171
|
await fs.writeFile(`components/${name}/config.ts`, configTs);
|
|
172
172
|
await fs.writeFile(`components/${name}/component.tsx`, componentTsx);
|
|
173
|
+
return {
|
|
174
|
+
name,
|
|
175
|
+
displayName,
|
|
176
|
+
statefulProps,
|
|
177
|
+
eventHandlers,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
async initializeComponentByExample() {
|
|
181
|
+
const response = {
|
|
182
|
+
displayName: "Example Component",
|
|
183
|
+
name: "ExampleComponent",
|
|
184
|
+
statefulProps: [
|
|
185
|
+
{
|
|
186
|
+
label: "Default Tasks",
|
|
187
|
+
path: "tasks",
|
|
188
|
+
inputType: "js",
|
|
189
|
+
placeholder: "{ taskId: { taskName: 'Task Name', taskStatus: 'complete' | 'todo' } }",
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
eventHandlers: [
|
|
193
|
+
{
|
|
194
|
+
label: "On Task Added",
|
|
195
|
+
path: "onTaskAdded",
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
label: "On Task Status Changed",
|
|
199
|
+
path: "onTaskStatusChanged",
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
};
|
|
203
|
+
const configTs = (0, create_component_defaults_1.getDefaultConfigTs)({
|
|
204
|
+
id: (0, node_crypto_1.randomUUID)(),
|
|
205
|
+
name: response.name,
|
|
206
|
+
displayName: response.displayName,
|
|
207
|
+
statefulPropsRendered: response.statefulProps
|
|
208
|
+
.map((statefulProp) => tsStringify(statefulProp))
|
|
209
|
+
.join(""),
|
|
210
|
+
eventHandlersRendered: response.eventHandlers
|
|
211
|
+
.map((eventHandler) => tsStringify(eventHandler))
|
|
212
|
+
.join(""),
|
|
213
|
+
});
|
|
214
|
+
await fs.copy(DEFAULT_PACKAGE_JSON_TEMPLATE_PATH, ".");
|
|
215
|
+
await fs.ensureDir("components/" + response.name);
|
|
216
|
+
await fs.copy(DEFAULT_EXAMPLE_COMPONENT_TEMPLATE_PATH, `./components/${response.name}/`);
|
|
217
|
+
await fs.writeFile(`components/${response.name}/config.ts`, configTs);
|
|
218
|
+
return response;
|
|
219
|
+
}
|
|
220
|
+
async run() {
|
|
221
|
+
const isFirstTimeCreate = !(await fs.exists("package.json"));
|
|
222
|
+
const initExampleComponent = isFirstTimeCreate &&
|
|
223
|
+
(await (0, enquirer_1.prompt)({
|
|
224
|
+
name: "value",
|
|
225
|
+
type: "confirm",
|
|
226
|
+
message: "Would you like to use a pre-generated example custom component?",
|
|
227
|
+
initial: false,
|
|
228
|
+
})).value;
|
|
229
|
+
let response;
|
|
230
|
+
if (!initExampleComponent) {
|
|
231
|
+
response = await this.initializeComponentByWizard(isFirstTimeCreate);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
response = await this.initializeComponentByExample();
|
|
235
|
+
}
|
|
173
236
|
this.log((0, colorette_1.green)("Successfully created component! Added the following files:"));
|
|
174
237
|
this.log();
|
|
175
238
|
const tree = core_1.ux.tree();
|
|
176
239
|
tree.insert("components");
|
|
177
|
-
tree.nodes.components.insert(name);
|
|
178
|
-
tree.nodes.components.nodes[name].insert("config.ts # update this file to configure your component's properties panel");
|
|
179
|
-
tree.nodes.components.nodes[name].insert("component.tsx # your component's react code");
|
|
240
|
+
tree.nodes.components.insert(response.name);
|
|
241
|
+
tree.nodes.components.nodes[response.name].insert("config.ts # update this file to configure your component's properties panel");
|
|
242
|
+
tree.nodes.components.nodes[response.name].insert("component.tsx # your component's react code");
|
|
180
243
|
tree.display();
|
|
181
244
|
this.log();
|
|
182
245
|
this.log(`${(0, colorette_1.green)("Remember to run $ ")}${(0, colorette_1.cyan)("superblocks components watch")}${(0, colorette_1.green)(" to watch for changes to your component files")}`);
|
|
183
246
|
this.log();
|
|
184
247
|
this.log(`Edit your component's react code here:
|
|
185
|
-
${(0, colorette_1.green)(`components/${name}/component.tsx`)}`);
|
|
248
|
+
${(0, colorette_1.green)(`components/${response.name}/component.tsx`)}`);
|
|
186
249
|
this.log();
|
|
187
|
-
if (
|
|
250
|
+
if (isFirstTimeCreate) {
|
|
188
251
|
core_1.ux.action.start("Installing dependencies...");
|
|
189
252
|
try {
|
|
190
253
|
await node_util_1.default.promisify(node_child_process_1.exec)("npm i");
|
|
@@ -121,7 +121,7 @@ async function walkThroughDirectory(directory, mutableFiles, excluded) {
|
|
|
121
121
|
const files = await fs.readdir(directory);
|
|
122
122
|
for (const file of files) {
|
|
123
123
|
if (excluded.includes(file))
|
|
124
|
-
|
|
124
|
+
continue;
|
|
125
125
|
const absolute = path_1.default.join(directory, file);
|
|
126
126
|
if ((await fs.stat(absolute)).isDirectory()) {
|
|
127
127
|
await walkThroughDirectory(absolute, mutableFiles, excluded);
|
|
@@ -69,7 +69,7 @@ class Watch extends authenticated_command_1.AuthenticatedApplicationCommand {
|
|
|
69
69
|
this.log((0, colorette_1.green)(`Local server started at port ${port}`));
|
|
70
70
|
this.log((0, colorette_1.green)(`Visit your application at:`));
|
|
71
71
|
this.log();
|
|
72
|
-
this.log((0, colorette_1.
|
|
72
|
+
this.log((0, colorette_1.bold)((0, colorette_1.magenta)(`${editModeUrl}?devMode=true`)));
|
|
73
73
|
this.log();
|
|
74
74
|
this.log((0, colorette_1.yellow)("Remember to refresh your already open Application page and turn on local development in Superblocks to connect to your local server!"));
|
|
75
75
|
})();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class SetSuperblocksConfig extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
property: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
|
|
7
|
+
value: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
run(): Promise<void>;
|
|
10
|
+
validateDomain(domain: string): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const dns_1 = tslib_1.__importDefault(require("dns"));
|
|
5
|
+
const util_1 = require("util");
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const util_2 = require("@superblocksteam/util");
|
|
8
|
+
class SetSuperblocksConfig extends core_1.Command {
|
|
9
|
+
async run() {
|
|
10
|
+
const { args } = await this.parse(SetSuperblocksConfig);
|
|
11
|
+
try {
|
|
12
|
+
switch (args.property) {
|
|
13
|
+
case "domain": {
|
|
14
|
+
const newDomain = args.value;
|
|
15
|
+
const newSuperblocksBaseUrl = `https://${newDomain}/`;
|
|
16
|
+
await this.validateDomain(newDomain);
|
|
17
|
+
const result = await (0, util_2.getLocalTokenWithUrlIfExists)();
|
|
18
|
+
if (result) {
|
|
19
|
+
if (!("token" in result)) {
|
|
20
|
+
// domain only, no token
|
|
21
|
+
await (0, util_2.saveApiToken)(newSuperblocksBaseUrl);
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
// existing token with domain
|
|
25
|
+
const { token, superblocksBaseUrl } = result;
|
|
26
|
+
const tokenToSave = newSuperblocksBaseUrl === superblocksBaseUrl ? token : undefined;
|
|
27
|
+
if (tokenToSave) {
|
|
28
|
+
await (0, util_2.saveApiToken)(newSuperblocksBaseUrl, tokenToSave);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
await (0, util_2.saveApiToken)(newSuperblocksBaseUrl);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// no existing token
|
|
36
|
+
await (0, util_2.saveApiToken)(newSuperblocksBaseUrl);
|
|
37
|
+
}
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`Unknown property ${args.property}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
this.error(`Failed to set ${args.property} to ${args.value}: ${error.message}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async validateDomain(domain) {
|
|
49
|
+
const domainRegex = /^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\.)+[A-Za-z]{2,6}$/;
|
|
50
|
+
const errorMessage = `Domain ${domain} is not valid, please make sure it's correct. Example: eu.superblocks.com`;
|
|
51
|
+
if (!domainRegex.test(domain)) {
|
|
52
|
+
throw new Error(errorMessage);
|
|
53
|
+
}
|
|
54
|
+
const lookup = (0, util_1.promisify)(dns_1.default.lookup);
|
|
55
|
+
try {
|
|
56
|
+
await lookup(domain);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw new Error(errorMessage);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
SetSuperblocksConfig.description = "Sets the specified property in your Superblocks configuration. A property governs the behavior of the Superblocks CLI, such as Superblocks region to interact with";
|
|
64
|
+
SetSuperblocksConfig.examples = [
|
|
65
|
+
"<%= config.bin %> <%= command.id %> domain eu.superblocks.com",
|
|
66
|
+
"<%= config.bin %> <%= command.id %> domain app.superblocks.com",
|
|
67
|
+
];
|
|
68
|
+
SetSuperblocksConfig.args = {
|
|
69
|
+
property: core_1.Args.string({
|
|
70
|
+
description: "Superblocks config name, e.g. domain",
|
|
71
|
+
options: ["domain"],
|
|
72
|
+
required: true,
|
|
73
|
+
}),
|
|
74
|
+
value: core_1.Args.string({
|
|
75
|
+
description: "Superblocks config value",
|
|
76
|
+
required: true,
|
|
77
|
+
}),
|
|
78
|
+
};
|
|
79
|
+
exports.default = SetSuperblocksConfig;
|
package/dist/commands/init.js
CHANGED
|
@@ -83,10 +83,10 @@ class Initialize extends authenticated_command_1.AuthenticatedCommand {
|
|
|
83
83
|
{
|
|
84
84
|
title: "Selecting resources to initialize...",
|
|
85
85
|
task: async (ctx, task) => {
|
|
86
|
-
const viewMode = await (0, version_control_1.getMode)(task, flags.mode);
|
|
87
|
-
ctx.viewMode = viewMode;
|
|
88
86
|
const resourceIdsToInitialize = await this.getResourcesToInitialize(ctx, task, args);
|
|
89
87
|
ctx.resourceIdsToInitialize = resourceIdsToInitialize;
|
|
88
|
+
const viewMode = await (0, version_control_1.getMode)(task, flags.mode);
|
|
89
|
+
ctx.viewMode = viewMode;
|
|
90
90
|
},
|
|
91
91
|
},
|
|
92
92
|
{
|
|
@@ -145,7 +145,6 @@ class Initialize extends authenticated_command_1.AuthenticatedCommand {
|
|
|
145
145
|
resources: {},
|
|
146
146
|
metadata: {
|
|
147
147
|
cliVersion: this.config.version,
|
|
148
|
-
remote: this.getSdk().superblocksBaseUrl,
|
|
149
148
|
lastUpdated: ctx.now,
|
|
150
149
|
created: (_b = (_a = ctx.existingSuperblocksConfig) === null || _a === void 0 ? void 0 : _a.metadata.created) !== null && _b !== void 0 ? _b : ctx.now,
|
|
151
150
|
},
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export default class Login extends Command {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
5
|
token: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
6
|
-
superblocksBaseUrl: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
7
6
|
};
|
|
7
|
+
DEFAULT_BASE_URL: string;
|
|
8
8
|
run(): Promise<void>;
|
|
9
9
|
}
|
package/dist/commands/login.js
CHANGED
|
@@ -4,41 +4,40 @@ const core_1 = require("@oclif/core");
|
|
|
4
4
|
const sdk_1 = require("@superblocksteam/sdk");
|
|
5
5
|
const util_1 = require("@superblocksteam/util");
|
|
6
6
|
const colorette_1 = require("colorette");
|
|
7
|
-
|
|
8
|
-
const
|
|
7
|
+
const enquirer_1 = require("enquirer");
|
|
8
|
+
const lodash_1 = require("lodash");
|
|
9
9
|
class Login extends core_1.Command {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
this.DEFAULT_BASE_URL = "https://app.superblocks.com/";
|
|
13
|
+
}
|
|
10
14
|
async run() {
|
|
15
|
+
var _a;
|
|
11
16
|
const { flags } = await this.parse(Login);
|
|
12
17
|
let token = flags.token;
|
|
13
|
-
let superblocksBaseUrl =
|
|
18
|
+
let superblocksBaseUrl = "";
|
|
14
19
|
if (!token) {
|
|
15
20
|
const result = await (0, util_1.getLocalTokenWithUrlIfExists)();
|
|
16
|
-
if (result) {
|
|
21
|
+
if (result && "token" in result) {
|
|
17
22
|
({ token, superblocksBaseUrl } = result);
|
|
18
23
|
}
|
|
19
24
|
else {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
message: "Select the Superblocks base URL",
|
|
23
|
-
choices: [
|
|
24
|
-
"https://app.superblocks.com/",
|
|
25
|
-
"https://eu.superblocks.com/",
|
|
26
|
-
customChoice,
|
|
27
|
-
],
|
|
28
|
-
});
|
|
29
|
-
superblocksBaseUrl = await selectPrompt.run();
|
|
30
|
-
if (superblocksBaseUrl === customChoice) {
|
|
31
|
-
superblocksBaseUrl = await core_1.ux.prompt("Enter the Superblocks base URL (then press Enter)", { type: "normal" });
|
|
32
|
-
}
|
|
25
|
+
superblocksBaseUrl =
|
|
26
|
+
(_a = result === null || result === void 0 ? void 0 : result.superblocksBaseUrl) !== null && _a !== void 0 ? _a : this.DEFAULT_BASE_URL;
|
|
33
27
|
const tokenPageUrl = new URL("personal-settings#apiKey", superblocksBaseUrl).href;
|
|
34
|
-
token = await
|
|
28
|
+
token = (await (0, enquirer_1.prompt)({
|
|
29
|
+
type: "password",
|
|
30
|
+
name: "token",
|
|
31
|
+
message: `Enter your Superblocks API key (then press Enter) which can be found at ${tokenPageUrl}`,
|
|
32
|
+
validate: (response) => !(0, lodash_1.isEmpty)(response.trim()),
|
|
33
|
+
})).token;
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
this.log();
|
|
38
37
|
try {
|
|
39
38
|
const sdk = new sdk_1.SuperblocksSdk(token, superblocksBaseUrl);
|
|
40
39
|
const user = await sdk.fetchCurrentUser();
|
|
41
|
-
await (0, util_1.saveApiToken)(
|
|
40
|
+
await (0, util_1.saveApiToken)(superblocksBaseUrl, token);
|
|
42
41
|
this.log((0, colorette_1.green)(`Welcome to the Superblocks 🐨 CLI ${user.name}!`));
|
|
43
42
|
}
|
|
44
43
|
catch (error) {
|
|
@@ -46,7 +45,7 @@ class Login extends core_1.Command {
|
|
|
46
45
|
this.log((0, colorette_1.red)("Could not save token, ensure the Superblocks CLI has access to create folders in your home directory."));
|
|
47
46
|
return;
|
|
48
47
|
}
|
|
49
|
-
this.log((0, colorette_1.red)(
|
|
48
|
+
this.log((0, colorette_1.red)(`Login failed. Ensure you've copied the correct token from ${superblocksBaseUrl}. If using a different domain, run "superblocks help config set" for configuration options.`));
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
51
|
}
|
|
@@ -55,12 +54,7 @@ Login.flags = {
|
|
|
55
54
|
// flag with a value (-t, --token=VALUE)
|
|
56
55
|
token: core_1.Flags.string({
|
|
57
56
|
char: "t",
|
|
58
|
-
description: "Superblocks user
|
|
59
|
-
}),
|
|
60
|
-
// flag with a value (-b, --superblocksBaseUrl=VALUE)
|
|
61
|
-
superblocksBaseUrl: core_1.Flags.string({
|
|
62
|
-
char: "b",
|
|
63
|
-
description: "Superblocks base URL",
|
|
57
|
+
description: "Superblocks user API key",
|
|
64
58
|
}),
|
|
65
59
|
};
|
|
66
60
|
exports.default = Login;
|
|
@@ -10,7 +10,11 @@ class AuthenticatedCommand extends core_1.Command {
|
|
|
10
10
|
async init() {
|
|
11
11
|
await super.init();
|
|
12
12
|
try {
|
|
13
|
-
const
|
|
13
|
+
const result = await (0, util_1.getLocalTokenWithUrl)();
|
|
14
|
+
if (!("token" in result)) {
|
|
15
|
+
throw new Error();
|
|
16
|
+
}
|
|
17
|
+
const { token, superblocksBaseUrl } = result;
|
|
14
18
|
this.sdk = new sdk_1.SuperblocksSdk(token, superblocksBaseUrl);
|
|
15
19
|
}
|
|
16
20
|
catch {
|
|
@@ -19,8 +23,8 @@ class AuthenticatedCommand extends core_1.Command {
|
|
|
19
23
|
}
|
|
20
24
|
async getBaseUrl() {
|
|
21
25
|
var _a;
|
|
22
|
-
const
|
|
23
|
-
return (_a =
|
|
26
|
+
const result = await (0, util_1.getLocalTokenWithUrlIfExists)();
|
|
27
|
+
return (_a = result === null || result === void 0 ? void 0 : result.superblocksBaseUrl) !== null && _a !== void 0 ? _a : "";
|
|
24
28
|
}
|
|
25
29
|
getSdk() {
|
|
26
30
|
if (!this.sdk) {
|
|
@@ -41,8 +45,8 @@ class AuthenticatedApplicationCommand extends AuthenticatedCommand {
|
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
async getEditModeUrl() {
|
|
44
|
-
const
|
|
45
|
-
const baseUrl =
|
|
48
|
+
const result = await (0, util_1.getLocalTokenWithUrlIfExists)();
|
|
49
|
+
const baseUrl = typeof result === "string" ? result : result === null || result === void 0 ? void 0 : result.superblocksBaseUrl;
|
|
46
50
|
return new URL(`/applications/${this.applicationConfig.id}/pages/${this.applicationConfig.defaultPageId}/edit`, baseUrl).toString();
|
|
47
51
|
}
|
|
48
52
|
async init() {
|
|
@@ -82,8 +86,9 @@ class AuthenticatedApplicationCommand extends AuthenticatedCommand {
|
|
|
82
86
|
await this.getSdk().registerComponents(this.applicationConfig.id, configs);
|
|
83
87
|
core_1.ux.action.stop();
|
|
84
88
|
}
|
|
85
|
-
catch {
|
|
89
|
+
catch (e) {
|
|
86
90
|
core_1.ux.action.stop();
|
|
91
|
+
console.log(e.message);
|
|
87
92
|
this.error("Failed to register components", { exit: 1 });
|
|
88
93
|
}
|
|
89
94
|
return configs;
|
|
@@ -13,7 +13,7 @@ export declare const modeFlagValuesMap: Record<string, string>;
|
|
|
13
13
|
export declare function modeFlagToViewMode(modeFlag: ModeFlag): ViewMode;
|
|
14
14
|
export type ModeFlag = (keyof typeof modeFlagValuesMap)[number];
|
|
15
15
|
export declare const SELECT_PROMPT_HELP = "Use \u2191/\u2193 arrow keys, Enter to confirm";
|
|
16
|
-
export declare const MULTI_SELECT_PROMPT_HELP = "Use \u2191/\u2193 arrow keys, Space to select, Enter to confirm";
|
|
16
|
+
export declare const MULTI_SELECT_PROMPT_HELP = "Type to filter, Use \u2191/\u2193 arrow keys, Space to select, Enter to confirm";
|
|
17
17
|
export declare const atLeastOneSelection: (value: string[]) => string | true;
|
|
18
18
|
export declare function writeResourceToDisk(resourceType: string, resourceId: string, resource: any, now: string, rootPath: string, existingRelativeLocation?: string): Promise<VersionedResourceConfig>;
|
|
19
19
|
export declare function getMode(task: any, mode: ModeFlag): Promise<ViewMode>;
|
|
@@ -32,7 +32,7 @@ function modeFlagToViewMode(modeFlag) {
|
|
|
32
32
|
}
|
|
33
33
|
exports.modeFlagToViewMode = modeFlagToViewMode;
|
|
34
34
|
exports.SELECT_PROMPT_HELP = "Use ↑/↓ arrow keys, Enter to confirm";
|
|
35
|
-
exports.MULTI_SELECT_PROMPT_HELP = "Use ↑/↓ arrow keys, Space to select, Enter to confirm";
|
|
35
|
+
exports.MULTI_SELECT_PROMPT_HELP = "Type to filter, Use ↑/↓ arrow keys, Space to select, Enter to confirm";
|
|
36
36
|
const atLeastOneSelection = (value) => {
|
|
37
37
|
if ((0, lodash_1.isEmpty)(value)) {
|
|
38
38
|
return `Please select at least one item ${(0, colorette_1.bold)("by pressing space")}`;
|
|
@@ -47,7 +47,7 @@ function slugifyName(originalName) {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
async function writeResourceToDisk(resourceType, resourceId, resource, now, rootPath, existingRelativeLocation) {
|
|
50
|
-
var _a, _b, _c;
|
|
50
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
51
51
|
switch (resourceType) {
|
|
52
52
|
case "APPLICATION": {
|
|
53
53
|
const parentDirName = "apps";
|
|
@@ -78,7 +78,7 @@ async function writeResourceToDisk(resourceType, resourceId, resource, now, root
|
|
|
78
78
|
};
|
|
79
79
|
if (resource.apis) {
|
|
80
80
|
for (const api of resource.apis) {
|
|
81
|
-
const apiName = slugifyName((_b = api.apiPb.metadata.name) !== null &&
|
|
81
|
+
const apiName = slugifyName((_d = (_c = (_b = api.apiPb) === null || _b === void 0 ? void 0 : _b.metadata) === null || _c === void 0 ? void 0 : _c.name) !== null && _d !== void 0 ? _d : api.actions.name);
|
|
82
82
|
// server is still sending actions for a backwards compatibility
|
|
83
83
|
delete api.actions;
|
|
84
84
|
const apiContent = (0, yaml_1.stringify)(api, {
|
|
@@ -102,7 +102,7 @@ async function writeResourceToDisk(resourceType, resourceId, resource, now, root
|
|
|
102
102
|
}
|
|
103
103
|
case "BACKEND": {
|
|
104
104
|
const parentDirName = "backends";
|
|
105
|
-
const apiName = slugifyName((
|
|
105
|
+
const apiName = slugifyName((_g = (_f = (_e = resource.apiPb) === null || _e === void 0 ? void 0 : _e.metadata) === null || _f === void 0 ? void 0 : _f.name) !== null && _g !== void 0 ? _g : resource.actions.name);
|
|
106
106
|
// server is still sending actions for a backwards compatibility
|
|
107
107
|
delete resource.actions;
|
|
108
108
|
const newRelativeLocation = `${parentDirName}/${apiName}`;
|
package/oclif.manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.0.
|
|
2
|
+
"version": "0.0.18",
|
|
3
3
|
"commands": {
|
|
4
4
|
"init": {
|
|
5
5
|
"id": "init",
|
|
@@ -48,14 +48,7 @@
|
|
|
48
48
|
"name": "token",
|
|
49
49
|
"type": "option",
|
|
50
50
|
"char": "t",
|
|
51
|
-
"description": "Superblocks user
|
|
52
|
-
"multiple": false
|
|
53
|
-
},
|
|
54
|
-
"superblocksBaseUrl": {
|
|
55
|
-
"name": "superblocksBaseUrl",
|
|
56
|
-
"type": "option",
|
|
57
|
-
"char": "b",
|
|
58
|
-
"description": "Superblocks base URL",
|
|
51
|
+
"description": "Superblocks user API key",
|
|
59
52
|
"multiple": false
|
|
60
53
|
}
|
|
61
54
|
},
|
|
@@ -147,6 +140,35 @@
|
|
|
147
140
|
"aliases": [],
|
|
148
141
|
"flags": {},
|
|
149
142
|
"args": {}
|
|
143
|
+
},
|
|
144
|
+
"config:set": {
|
|
145
|
+
"id": "config:set",
|
|
146
|
+
"description": "Sets the specified property in your Superblocks configuration. A property governs the behavior of the Superblocks CLI, such as Superblocks region to interact with",
|
|
147
|
+
"strict": true,
|
|
148
|
+
"pluginName": "@superblocksteam/cli",
|
|
149
|
+
"pluginAlias": "@superblocksteam/cli",
|
|
150
|
+
"pluginType": "core",
|
|
151
|
+
"aliases": [],
|
|
152
|
+
"examples": [
|
|
153
|
+
"<%= config.bin %> <%= command.id %> domain eu.superblocks.com",
|
|
154
|
+
"<%= config.bin %> <%= command.id %> domain app.superblocks.com"
|
|
155
|
+
],
|
|
156
|
+
"flags": {},
|
|
157
|
+
"args": {
|
|
158
|
+
"property": {
|
|
159
|
+
"name": "property",
|
|
160
|
+
"description": "Superblocks config name, e.g. domain",
|
|
161
|
+
"required": true,
|
|
162
|
+
"options": [
|
|
163
|
+
"domain"
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
"value": {
|
|
167
|
+
"name": "value",
|
|
168
|
+
"description": "Superblocks config value",
|
|
169
|
+
"required": true
|
|
170
|
+
}
|
|
171
|
+
}
|
|
150
172
|
}
|
|
151
173
|
}
|
|
152
174
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superblocksteam/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.18",
|
|
4
4
|
"description": "Official Superblocks CLI",
|
|
5
5
|
"bin": {
|
|
6
6
|
"superblocks": "bin/run"
|
|
@@ -92,6 +92,9 @@
|
|
|
92
92
|
"topics": {
|
|
93
93
|
"components": {
|
|
94
94
|
"description": "Manage Superblocks components"
|
|
95
|
+
},
|
|
96
|
+
"config": {
|
|
97
|
+
"description": "Manage Superblocks configuration"
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
}
|
|
File without changes
|
|
File without changes
|