attio 0.0.1-experimental.20241219 → 0.0.1-experimental.20250101
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/lib/api/create-version.js +2 -2
- package/lib/attio-logo.js +24 -0
- package/lib/attio.js +17 -8
- package/lib/commands/build.js +18 -35
- package/lib/commands/connection/add.js +51 -168
- package/lib/commands/connection/index.js +9 -1
- package/lib/commands/connection/list.js +17 -47
- package/lib/commands/connection/remove.js +17 -65
- package/lib/commands/create.js +27 -126
- package/lib/commands/dev.js +17 -106
- package/lib/commands/version/create.js +17 -68
- package/lib/commands/version/index.js +11 -1
- package/lib/commands/version/invite.js +40 -84
- package/lib/commands/version/list.js +18 -40
- package/lib/commands/version/publish.js +40 -64
- package/lib/machines/actions.js +7 -0
- package/lib/machines/actors.js +7 -1
- package/lib/machines/add-connection-machine.js +169 -201
- package/lib/machines/build-machine.js +35 -4
- package/lib/machines/create-machine.js +95 -70
- package/lib/machines/create-version-machine.js +121 -4
- package/lib/machines/dev-machine.js +173 -53
- package/lib/machines/generate-invite-machine.js +64 -10
- package/lib/machines/list-connections-machine.js +57 -2
- package/lib/machines/list-versions-machine.js +33 -0
- package/lib/machines/publish-version-machine.js +45 -16
- package/lib/machines/remove-connection-machine.js +64 -17
- package/lib/machines/ts-machine.js +4 -1
- package/lib/schema.js +2 -2
- package/lib/util/clear-terminal.js +4 -0
- package/lib/util/load-developer-config.js +2 -2
- package/lib/util/print-install-instructions.js +32 -0
- package/lib/util/print-message.js +9 -0
- package/lib/util/set-terminal-title.js +8 -0
- package/lib/util/text-gradient.js +28 -0
- package/lib/util/typescript.js +25 -0
- package/package.json +13 -12
- package/schema.graphql +8 -1
- package/lib/components/BuildError.js +0 -46
- package/lib/components/BuildLog.js +0 -6
- package/lib/components/CodeGenErrors.js +0 -22
- package/lib/components/Disclaimer.js +0 -9
- package/lib/components/InitialInstructions.js +0 -69
- package/lib/components/Log.js +0 -69
- package/lib/components/Logo.js +0 -10
- package/lib/components/MultiSelect.js +0 -65
- package/lib/components/ScrollBox.js +0 -87
- package/lib/components/ScrollBox.store.js +0 -36
- package/lib/components/ScrollBox.util.js +0 -27
- package/lib/components/Select.js +0 -6
- package/lib/components/Table.js +0 -33
- package/lib/components/TypeScriptErrors.js +0 -38
- package/lib/hooks/useFullScreen.js +0 -22
- package/lib/hooks/useTerminalTitle.js +0 -11
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import chokidar from "chokidar";
|
|
2
2
|
import open from "open";
|
|
3
|
-
import readline from "readline";
|
|
4
3
|
import { assign, fromCallback, setup, enqueueActions } from "xstate";
|
|
5
4
|
import { APP } from "../env.js";
|
|
6
5
|
import { completeBundleUpload } from "../api/complete-bundle-upload.js";
|
|
@@ -9,13 +8,27 @@ import { startGraphqlServer } from "../api/start-graphql-server.js";
|
|
|
9
8
|
import { startUpload } from "../api/start-upload.js";
|
|
10
9
|
import { loadAppConfigFile } from "../util/app-config.js";
|
|
11
10
|
import { loadDeveloperConfig, loadInitialDeveloperConfig, } from "../util/load-developer-config.js";
|
|
11
|
+
import notifier from "node-notifier";
|
|
12
12
|
import { loadEnv } from "../util/load-env.js";
|
|
13
13
|
import { codeGenMachine } from "./code-gen-machine.js";
|
|
14
14
|
import { envMachine } from "./env-machine.js";
|
|
15
15
|
import { jsMachine } from "./js-machine.js";
|
|
16
16
|
import { tsMachine } from "./ts-machine.js";
|
|
17
|
-
import { error as logError } from "../components/Log.js";
|
|
18
17
|
import { fetchInstallation } from "../api/fetch-installation.js";
|
|
18
|
+
import Spinner from "tiny-spinner";
|
|
19
|
+
import { printMessage } from "../util/print-message.js";
|
|
20
|
+
import { printError } from "../util/typescript.js";
|
|
21
|
+
import { clearTerminal } from "../util/clear-terminal.js";
|
|
22
|
+
import { setTerminalTitle } from "../util/set-terminal-title.js";
|
|
23
|
+
import { printInstallInstructions } from "../util/print-install-instructions.js";
|
|
24
|
+
import { printLogo } from "./actions.js";
|
|
25
|
+
process.on("SIGINT", () => {
|
|
26
|
+
process.stdout.write("\x1B[?25h");
|
|
27
|
+
process.exit();
|
|
28
|
+
});
|
|
29
|
+
process.on("exit", () => {
|
|
30
|
+
process.stdout.write("\x1B[?25h");
|
|
31
|
+
});
|
|
19
32
|
export const devMachine = setup({
|
|
20
33
|
types: {
|
|
21
34
|
context: {},
|
|
@@ -24,6 +37,7 @@ export const devMachine = setup({
|
|
|
24
37
|
},
|
|
25
38
|
guards: {
|
|
26
39
|
"have dev version": ({ context }) => Boolean(context.devVersion),
|
|
40
|
+
"have typescript errors": (_, params) => Boolean(params.typeScriptErrors?.length),
|
|
27
41
|
},
|
|
28
42
|
actors: {
|
|
29
43
|
"javascript": jsMachine,
|
|
@@ -38,45 +52,54 @@ export const devMachine = setup({
|
|
|
38
52
|
}
|
|
39
53
|
sendBack({ type: "Initialized", config });
|
|
40
54
|
}),
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
if (key.name?.toLowerCase() === "o") {
|
|
48
|
-
open(`http://localhost:${input.graphqlPort}/graphql`);
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
process.stdin.on("keypress", handleKeyPress);
|
|
52
|
-
return () => {
|
|
53
|
-
process.stdin.removeListener("keypress", handleKeyPress);
|
|
55
|
+
"keyboard": fromCallback(({ sendBack }) => {
|
|
56
|
+
if (!process.stdin.isTTY)
|
|
57
|
+
return;
|
|
58
|
+
const originalIsRaw = process.stdin.isRaw;
|
|
59
|
+
const originalIsTTY = process.stdin.isTTY;
|
|
60
|
+
const ensureRawMode = () => {
|
|
54
61
|
if (process.stdin.isTTY) {
|
|
55
|
-
process.stdin.setRawMode(
|
|
62
|
+
process.stdin.setRawMode(true);
|
|
56
63
|
}
|
|
57
64
|
};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
const handleData = (data) => {
|
|
66
|
+
ensureRawMode();
|
|
67
|
+
const str = data.toString();
|
|
68
|
+
if (str === "\u0003") {
|
|
69
|
+
process.stdout.write("\x1B[?25h");
|
|
70
|
+
process.stdin.setRawMode(originalIsRaw);
|
|
71
|
+
process.exit();
|
|
72
|
+
}
|
|
73
|
+
switch (str) {
|
|
74
|
+
case "o":
|
|
75
|
+
sendBack({ type: "Open GraphQL Explorer" });
|
|
76
|
+
break;
|
|
77
|
+
case "i":
|
|
78
|
+
sendBack({ type: "Install Opened" });
|
|
79
|
+
break;
|
|
68
80
|
}
|
|
69
81
|
};
|
|
70
|
-
process.stdin.
|
|
82
|
+
process.stdin.setRawMode(true);
|
|
83
|
+
process.stdin.resume();
|
|
84
|
+
process.stdin.on("data", handleData);
|
|
85
|
+
process.stdin.on("focus", ensureRawMode);
|
|
86
|
+
process.stdout.on("focus", ensureRawMode);
|
|
87
|
+
process.on("focus", ensureRawMode);
|
|
71
88
|
return () => {
|
|
72
|
-
process.stdin.removeListener("
|
|
73
|
-
|
|
74
|
-
|
|
89
|
+
process.stdin.removeListener("data", handleData);
|
|
90
|
+
process.stdin.removeListener("focus", ensureRawMode);
|
|
91
|
+
process.stdout.removeListener("focus", ensureRawMode);
|
|
92
|
+
process.removeListener("focus", ensureRawMode);
|
|
93
|
+
process.stdin.setRawMode(originalIsRaw);
|
|
94
|
+
if (originalIsTTY) {
|
|
95
|
+
process.stdin.pause();
|
|
75
96
|
}
|
|
76
97
|
};
|
|
77
98
|
}),
|
|
78
99
|
"prepareUpload": fromCallback(({ sendBack }) => {
|
|
100
|
+
const spinner = new Spinner();
|
|
79
101
|
const prepareUpload = async () => {
|
|
102
|
+
spinner.start("Preparing upload...");
|
|
80
103
|
const config = await loadDeveloperConfig();
|
|
81
104
|
if (typeof config === "string")
|
|
82
105
|
throw config;
|
|
@@ -93,18 +116,24 @@ export const devMachine = setup({
|
|
|
93
116
|
targetWorkspaceId: config.target_workspace_id,
|
|
94
117
|
environmentVariables,
|
|
95
118
|
});
|
|
119
|
+
spinner.success("Upload prepared");
|
|
96
120
|
sendBack({
|
|
97
121
|
type: "Upload Prepared",
|
|
98
122
|
devVersion: { ...devVersion, app_slug: app.slug },
|
|
99
123
|
});
|
|
100
124
|
};
|
|
101
|
-
prepareUpload().catch((error) =>
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
prepareUpload().catch((error) => {
|
|
126
|
+
spinner.error(`Upload failed: ${error.message}`);
|
|
127
|
+
sendBack({
|
|
128
|
+
type: "Upload Error",
|
|
129
|
+
error: typeof error === "string" ? new Error(error) : error,
|
|
130
|
+
});
|
|
131
|
+
});
|
|
105
132
|
}),
|
|
106
133
|
"upload": fromCallback(({ sendBack, input: { config: { token, developer_slug: developerSlug }, contents, devVersion: { app_id: appId, app_dev_version_id: devVersionId }, }, }) => {
|
|
134
|
+
const spinner = new Spinner();
|
|
107
135
|
const upload = async () => {
|
|
136
|
+
spinner.start("Uploading...");
|
|
108
137
|
const { client_bundle_upload_url, server_bundle_upload_url, app_dev_version_bundle_id: bundleId, } = await startUpload({
|
|
109
138
|
token,
|
|
110
139
|
developerSlug,
|
|
@@ -130,7 +159,7 @@ export const devMachine = setup({
|
|
|
130
159
|
},
|
|
131
160
|
}),
|
|
132
161
|
]).catch((error) => {
|
|
133
|
-
|
|
162
|
+
process.stderr.write(`Upload Error: ${error}`);
|
|
134
163
|
});
|
|
135
164
|
await completeBundleUpload({
|
|
136
165
|
token,
|
|
@@ -139,9 +168,21 @@ export const devMachine = setup({
|
|
|
139
168
|
devVersionId,
|
|
140
169
|
bundleId,
|
|
141
170
|
});
|
|
171
|
+
spinner.success(`Upload completed at ${new Date().toLocaleString()}.`);
|
|
142
172
|
sendBack({ type: "Upload Complete" });
|
|
173
|
+
notifier.notify({
|
|
174
|
+
title: "Upload Complete",
|
|
175
|
+
message: "New bundle uploaded to Attio",
|
|
176
|
+
});
|
|
143
177
|
};
|
|
144
|
-
upload().catch((error) =>
|
|
178
|
+
upload().catch((error) => {
|
|
179
|
+
spinner.error(`Upload failed: ${error.message}`);
|
|
180
|
+
sendBack({ type: "Upload Error", error });
|
|
181
|
+
notifier.notify({
|
|
182
|
+
title: "Upload Failed",
|
|
183
|
+
message: "Bundle upload to Attio failed",
|
|
184
|
+
});
|
|
185
|
+
});
|
|
145
186
|
}),
|
|
146
187
|
"watch": fromCallback(({ sendBack }) => {
|
|
147
188
|
const watcher = chokidar.watch(["src", ".env"], {
|
|
@@ -188,6 +229,44 @@ export const devMachine = setup({
|
|
|
188
229
|
},
|
|
189
230
|
actions: {
|
|
190
231
|
clearUploadError: assign({ uploadError: undefined }),
|
|
232
|
+
showConfigInstructions: ({ context }) => {
|
|
233
|
+
printInstallInstructions(context.configError);
|
|
234
|
+
},
|
|
235
|
+
printLogo: (_) => {
|
|
236
|
+
process.stdout.write("\x1B[?25l");
|
|
237
|
+
printLogo();
|
|
238
|
+
},
|
|
239
|
+
printWatching: (_) => {
|
|
240
|
+
printMessage("👀 Watching for changes...");
|
|
241
|
+
},
|
|
242
|
+
printTypeScriptErrors: (_, params) => {
|
|
243
|
+
if (params.errors.length) {
|
|
244
|
+
clearTerminal();
|
|
245
|
+
params.errors.forEach(printError);
|
|
246
|
+
notifier.notify({
|
|
247
|
+
title: "TypeScript Errors",
|
|
248
|
+
message: `There were ${params.errors.length === 1 ? "one error" : `${params.errors.length} errors`} in your TypeScript code`,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
promptToInstall: (_) => {
|
|
253
|
+
process.stdout.write(`\n\n🚨 IMPORTANT: You will need to install your app in your workspace. Press "i" to open the app settings page, and then click "Install".\n\n`);
|
|
254
|
+
},
|
|
255
|
+
promptToOpenGraphQLExplorer: (_) => {
|
|
256
|
+
process.stdout.write(`\n\n Press "o" to open GraphQL Explorer.\n\n`);
|
|
257
|
+
},
|
|
258
|
+
openGraphQLExplorer: ({ context }) => {
|
|
259
|
+
open(`http://localhost:${context.graphqlPort}/graphql`);
|
|
260
|
+
},
|
|
261
|
+
openInstallPage: ({ context }) => {
|
|
262
|
+
open(`${APP}/_/settings/apps/${context.devVersion?.app_slug}`);
|
|
263
|
+
},
|
|
264
|
+
saveTypeScriptErrors: assign({
|
|
265
|
+
typeScriptErrors: (_, params) => params.errors,
|
|
266
|
+
}),
|
|
267
|
+
clearTypeScriptErrors: assign({
|
|
268
|
+
typeScriptErrors: () => [],
|
|
269
|
+
}),
|
|
191
270
|
sendChange: enqueueActions(({ enqueue, event }) => {
|
|
192
271
|
enqueue.sendTo("javascript", event);
|
|
193
272
|
enqueue.sendTo("typescript", event);
|
|
@@ -209,6 +288,11 @@ export const devMachine = setup({
|
|
|
209
288
|
setGraphqlPort: assign({
|
|
210
289
|
graphqlPort: (_, params) => params.port,
|
|
211
290
|
}),
|
|
291
|
+
setTerminalTitle: ({ context }) => {
|
|
292
|
+
setTerminalTitle(context.devVersion?.app_id
|
|
293
|
+
? `attio dev – ${context.devVersion.app_id}`
|
|
294
|
+
: `attio dev`);
|
|
295
|
+
},
|
|
212
296
|
setSuccess: assign({
|
|
213
297
|
jsContents: (_, params) => params.contents,
|
|
214
298
|
lastSuccessfulJavaScriptBuild: (_, params) => params.time,
|
|
@@ -245,6 +329,9 @@ export const devMachine = setup({
|
|
|
245
329
|
input: ({ self }) => ({ parentRef: self }),
|
|
246
330
|
},
|
|
247
331
|
{ src: "watch" },
|
|
332
|
+
{
|
|
333
|
+
src: "keyboard",
|
|
334
|
+
},
|
|
248
335
|
],
|
|
249
336
|
states: {
|
|
250
337
|
JavaScript: {
|
|
@@ -264,7 +351,9 @@ export const devMachine = setup({
|
|
|
264
351
|
},
|
|
265
352
|
},
|
|
266
353
|
},
|
|
267
|
-
"Watching": {
|
|
354
|
+
"Watching": {
|
|
355
|
+
entry: "printWatching",
|
|
356
|
+
},
|
|
268
357
|
"Uploading": {
|
|
269
358
|
on: {
|
|
270
359
|
"Upload Complete": "Watching",
|
|
@@ -286,13 +375,15 @@ export const devMachine = setup({
|
|
|
286
375
|
},
|
|
287
376
|
"Upload When Ready": {
|
|
288
377
|
always: {
|
|
289
|
-
target: "
|
|
378
|
+
target: "Can Upload?",
|
|
290
379
|
guard: "have dev version",
|
|
380
|
+
reenter: true,
|
|
291
381
|
},
|
|
292
382
|
on: {
|
|
293
383
|
"Upload Prepared": {
|
|
294
|
-
target: "
|
|
384
|
+
target: "Can Upload?",
|
|
295
385
|
actions: { type: "setDevVersion", params: ({ event }) => event },
|
|
386
|
+
reenter: true,
|
|
296
387
|
},
|
|
297
388
|
},
|
|
298
389
|
},
|
|
@@ -307,12 +398,28 @@ export const devMachine = setup({
|
|
|
307
398
|
},
|
|
308
399
|
},
|
|
309
400
|
},
|
|
401
|
+
"Can Upload?": {
|
|
402
|
+
always: [
|
|
403
|
+
{
|
|
404
|
+
target: "Watching",
|
|
405
|
+
guard: {
|
|
406
|
+
type: "have typescript errors",
|
|
407
|
+
params: ({ context }) => context,
|
|
408
|
+
},
|
|
409
|
+
reenter: true,
|
|
410
|
+
},
|
|
411
|
+
"Uploading",
|
|
412
|
+
],
|
|
413
|
+
},
|
|
310
414
|
},
|
|
311
415
|
initial: "Building",
|
|
312
416
|
on: {
|
|
313
417
|
"Upload Prepared": {
|
|
314
418
|
target: "JavaScript",
|
|
315
|
-
actions:
|
|
419
|
+
actions: [
|
|
420
|
+
{ type: "setDevVersion", params: ({ event }) => event },
|
|
421
|
+
"setTerminalTitle",
|
|
422
|
+
],
|
|
316
423
|
},
|
|
317
424
|
"Change": {
|
|
318
425
|
target: "JavaScript",
|
|
@@ -331,9 +438,19 @@ export const devMachine = setup({
|
|
|
331
438
|
states: {
|
|
332
439
|
Validating: {
|
|
333
440
|
on: {
|
|
334
|
-
"TypeScript Success":
|
|
441
|
+
"TypeScript Success": {
|
|
442
|
+
target: "Watching",
|
|
443
|
+
actions: "clearTypeScriptErrors",
|
|
444
|
+
},
|
|
335
445
|
"TypeScript Error": {
|
|
336
446
|
target: "Watching",
|
|
447
|
+
actions: [
|
|
448
|
+
{
|
|
449
|
+
type: "printTypeScriptErrors",
|
|
450
|
+
params: ({ event }) => event,
|
|
451
|
+
},
|
|
452
|
+
{ type: "saveTypeScriptErrors", params: ({ event }) => event },
|
|
453
|
+
],
|
|
337
454
|
},
|
|
338
455
|
},
|
|
339
456
|
},
|
|
@@ -369,9 +486,11 @@ export const devMachine = setup({
|
|
|
369
486
|
},
|
|
370
487
|
},
|
|
371
488
|
"Started": {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
489
|
+
on: {
|
|
490
|
+
"Open GraphQL Explorer": {
|
|
491
|
+
target: "Started",
|
|
492
|
+
actions: "openGraphQLExplorer",
|
|
493
|
+
},
|
|
375
494
|
},
|
|
376
495
|
},
|
|
377
496
|
},
|
|
@@ -396,15 +515,7 @@ export const devMachine = setup({
|
|
|
396
515
|
type: "final",
|
|
397
516
|
},
|
|
398
517
|
"Prompt to Install": {
|
|
399
|
-
|
|
400
|
-
src: "listenForInstallOpen",
|
|
401
|
-
input: ({ context }) => ({
|
|
402
|
-
appSlug: context.devVersion.app_slug,
|
|
403
|
-
}),
|
|
404
|
-
},
|
|
405
|
-
on: {
|
|
406
|
-
"Install Opened": "Poll For Installation",
|
|
407
|
-
},
|
|
518
|
+
entry: "promptToInstall",
|
|
408
519
|
},
|
|
409
520
|
"Poll For Installation": {
|
|
410
521
|
invoke: {
|
|
@@ -428,9 +539,16 @@ export const devMachine = setup({
|
|
|
428
539
|
},
|
|
429
540
|
},
|
|
430
541
|
initial: "Waiting for App ID",
|
|
542
|
+
on: {
|
|
543
|
+
"Install Opened": {
|
|
544
|
+
target: ".Poll For Installation",
|
|
545
|
+
actions: "openInstallPage",
|
|
546
|
+
},
|
|
547
|
+
},
|
|
431
548
|
},
|
|
432
549
|
},
|
|
433
550
|
type: "parallel",
|
|
551
|
+
entry: "promptToOpenGraphQLExplorer",
|
|
434
552
|
},
|
|
435
553
|
"Read Config": {
|
|
436
554
|
on: {
|
|
@@ -452,6 +570,8 @@ export const devMachine = setup({
|
|
|
452
570
|
},
|
|
453
571
|
"No Config": {
|
|
454
572
|
type: "final",
|
|
573
|
+
entry: "showConfigInstructions",
|
|
455
574
|
},
|
|
456
575
|
},
|
|
576
|
+
entry: "printLogo",
|
|
457
577
|
});
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { assign, setup, fromCallback } from "xstate";
|
|
2
|
+
import clipboard from "clipboardy";
|
|
2
3
|
import { fetchUnpublishedVersions } from "../api/fetch-versions.js";
|
|
3
4
|
import { generateInviteLink } from "../api/generate-invite-link.js";
|
|
4
5
|
import { emptyConfig } from "../schema.js";
|
|
5
|
-
import { loadAppConfig, loadDeveloperConfig } from "./actors.js";
|
|
6
|
+
import { askWithTypedChoices, loadAppConfig, loadDeveloperConfig } from "./actors.js";
|
|
7
|
+
import { printLogo, showError } from "./actions.js";
|
|
8
|
+
import { printInstallInstructions } from "../util/print-install-instructions.js";
|
|
9
|
+
import Spinner from "tiny-spinner";
|
|
10
|
+
import chalk from "chalk";
|
|
6
11
|
export const connectionTypes = [
|
|
7
12
|
{ value: "secret", label: "Secret" },
|
|
8
13
|
{ value: "oauth2-code", label: "OAuth2" },
|
|
@@ -18,19 +23,27 @@ export const generateInviteMachine = setup({
|
|
|
18
23
|
input: {},
|
|
19
24
|
},
|
|
20
25
|
actors: {
|
|
26
|
+
askForVersion: askWithTypedChoices(),
|
|
21
27
|
fetchVersions: fromCallback(({ sendBack, input: { developer: { token, slug: devSlug }, config, }, }) => {
|
|
22
28
|
const getVersions = async () => {
|
|
29
|
+
const spinner = new Spinner();
|
|
30
|
+
spinner.start("Loading versions...");
|
|
23
31
|
const versions = await fetchUnpublishedVersions({
|
|
24
32
|
token,
|
|
25
33
|
devSlug,
|
|
26
34
|
appId: config.id,
|
|
27
35
|
});
|
|
36
|
+
spinner.success("Versions loaded");
|
|
28
37
|
sendBack({ type: "Versions Fetched", versions });
|
|
29
38
|
};
|
|
30
39
|
getVersions();
|
|
31
40
|
}),
|
|
32
|
-
generateInviteLink: fromCallback(({ sendBack, input: { developer: { token, slug: devSlug }, config, major, minor, }, }) => {
|
|
41
|
+
generateInviteLink: fromCallback(({ sendBack, input: { developer: { token, slug: devSlug }, config, versionProvided, major, minor, }, }) => {
|
|
33
42
|
const add = async () => {
|
|
43
|
+
const spinner = new Spinner();
|
|
44
|
+
if (!versionProvided) {
|
|
45
|
+
spinner.start("Generating invite link...");
|
|
46
|
+
}
|
|
34
47
|
try {
|
|
35
48
|
const inviteLink = await generateInviteLink({
|
|
36
49
|
token,
|
|
@@ -39,9 +52,15 @@ export const generateInviteMachine = setup({
|
|
|
39
52
|
major: major,
|
|
40
53
|
minor: minor,
|
|
41
54
|
});
|
|
55
|
+
if (!versionProvided) {
|
|
56
|
+
spinner.success("Invite link generated");
|
|
57
|
+
}
|
|
42
58
|
sendBack({ type: "Invite Link Generated", inviteLink });
|
|
43
59
|
}
|
|
44
60
|
catch (error) {
|
|
61
|
+
if (!versionProvided) {
|
|
62
|
+
spinner.error("Error generating invite link");
|
|
63
|
+
}
|
|
45
64
|
sendBack({ type: "Error", error: error.message });
|
|
46
65
|
}
|
|
47
66
|
};
|
|
@@ -51,6 +70,27 @@ export const generateInviteMachine = setup({
|
|
|
51
70
|
loadAppConfig,
|
|
52
71
|
},
|
|
53
72
|
actions: {
|
|
73
|
+
printLogo,
|
|
74
|
+
showError,
|
|
75
|
+
showConfigInstructions: ({ context }) => {
|
|
76
|
+
printLogo();
|
|
77
|
+
printInstallInstructions(context.configError);
|
|
78
|
+
},
|
|
79
|
+
showNoUnpublishedVersions: () => {
|
|
80
|
+
process.stdout.write("No unpublished versions found.");
|
|
81
|
+
},
|
|
82
|
+
printInviteLink: ({ context }) => {
|
|
83
|
+
if (context.versionProvided) {
|
|
84
|
+
process.stdout.write(context.inviteLink);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
process.stdout.write(`\nInvite link for version ${context.major}.${context.minor} successfully generated. It will expire in 24 hours.\n\n`);
|
|
88
|
+
process.stdout.write(chalk.blue(context.inviteLink));
|
|
89
|
+
process.stdout.write("\n\n📋 It's already on your clipboard!\n");
|
|
90
|
+
},
|
|
91
|
+
copyToInviteLinkToClipboard: ({ context }) => {
|
|
92
|
+
clipboard.writeSync(context.inviteLink);
|
|
93
|
+
},
|
|
54
94
|
clearError: assign({
|
|
55
95
|
error: () => undefined,
|
|
56
96
|
}),
|
|
@@ -70,8 +110,8 @@ export const generateInviteMachine = setup({
|
|
|
70
110
|
inviteLink: (_, params) => params.inviteLink,
|
|
71
111
|
}),
|
|
72
112
|
setVersion: assign({
|
|
73
|
-
major: (_, params) => params.
|
|
74
|
-
minor: (_, params) => params.
|
|
113
|
+
major: (_, params) => params.output.major,
|
|
114
|
+
minor: (_, params) => params.output.minor,
|
|
75
115
|
}),
|
|
76
116
|
setVersions: assign({
|
|
77
117
|
versions: (_, params) => params.versions,
|
|
@@ -86,6 +126,7 @@ export const generateInviteMachine = setup({
|
|
|
86
126
|
developer: { slug: "", token: "" },
|
|
87
127
|
config: emptyConfig,
|
|
88
128
|
versions: [],
|
|
129
|
+
versionProvided: input.major !== undefined && input.minor !== undefined,
|
|
89
130
|
major: input.major,
|
|
90
131
|
minor: input.minor,
|
|
91
132
|
}),
|
|
@@ -108,6 +149,7 @@ export const generateInviteMachine = setup({
|
|
|
108
149
|
},
|
|
109
150
|
"Show config instructions": {
|
|
110
151
|
type: "final",
|
|
152
|
+
entry: "showConfigInstructions",
|
|
111
153
|
},
|
|
112
154
|
"Loading App Config": {
|
|
113
155
|
invoke: {
|
|
@@ -127,9 +169,11 @@ export const generateInviteMachine = setup({
|
|
|
127
169
|
},
|
|
128
170
|
"Error": {
|
|
129
171
|
type: "final",
|
|
172
|
+
entry: { type: "showError", params: ({ context }) => ({ error: context.error }) },
|
|
130
173
|
},
|
|
131
174
|
"Display Invite Link": {
|
|
132
175
|
type: "final",
|
|
176
|
+
entry: ["copyToInviteLinkToClipboard", "printInviteLink"],
|
|
133
177
|
},
|
|
134
178
|
"Fetching Versions": {
|
|
135
179
|
on: {
|
|
@@ -158,6 +202,7 @@ export const generateInviteMachine = setup({
|
|
|
158
202
|
{
|
|
159
203
|
target: "Fetching Versions",
|
|
160
204
|
reenter: true,
|
|
205
|
+
actions: "printLogo",
|
|
161
206
|
},
|
|
162
207
|
],
|
|
163
208
|
},
|
|
@@ -178,12 +223,6 @@ export const generateInviteMachine = setup({
|
|
|
178
223
|
},
|
|
179
224
|
},
|
|
180
225
|
"Ask for version": {
|
|
181
|
-
on: {
|
|
182
|
-
"Select Version": {
|
|
183
|
-
target: "Generating Invite Link",
|
|
184
|
-
actions: { type: "setVersion", params: ({ event }) => event },
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
226
|
always: {
|
|
188
227
|
target: "No unpublished versions",
|
|
189
228
|
guard: {
|
|
@@ -191,9 +230,24 @@ export const generateInviteMachine = setup({
|
|
|
191
230
|
params: ({ context }) => context,
|
|
192
231
|
},
|
|
193
232
|
},
|
|
233
|
+
invoke: {
|
|
234
|
+
src: "askForVersion",
|
|
235
|
+
input: ({ context }) => ({
|
|
236
|
+
choices: context.versions.map((version) => ({
|
|
237
|
+
name: `${version.major}.${version.minor}`,
|
|
238
|
+
value: version,
|
|
239
|
+
})),
|
|
240
|
+
message: "Select an unpublished version to invite someone to:",
|
|
241
|
+
}),
|
|
242
|
+
onDone: {
|
|
243
|
+
target: "Generating Invite Link",
|
|
244
|
+
actions: { type: "setVersion", params: ({ event }) => event },
|
|
245
|
+
},
|
|
246
|
+
},
|
|
194
247
|
},
|
|
195
248
|
"No unpublished versions": {
|
|
196
249
|
type: "final",
|
|
250
|
+
entry: "showNoUnpublishedVersions",
|
|
197
251
|
},
|
|
198
252
|
},
|
|
199
253
|
initial: "Loading Developer Config",
|
|
@@ -2,6 +2,12 @@ import { assign, setup, fromCallback } from "xstate";
|
|
|
2
2
|
import { fetchConnections } from "../api/fetch-connections.js";
|
|
3
3
|
import { emptyConfig } from "../schema.js";
|
|
4
4
|
import { loadAppConfig, loadDeveloperConfig } from "./actors.js";
|
|
5
|
+
import Table from "cli-table3";
|
|
6
|
+
import { showError, printLogo } from "./actions.js";
|
|
7
|
+
import { printInstallInstructions } from "../util/print-install-instructions.js";
|
|
8
|
+
import boxen from "boxen";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import Spinner from "tiny-spinner";
|
|
5
11
|
export const listConnectionsMachine = setup({
|
|
6
12
|
types: {
|
|
7
13
|
context: {},
|
|
@@ -11,17 +17,61 @@ export const listConnectionsMachine = setup({
|
|
|
11
17
|
loadDeveloperConfig,
|
|
12
18
|
loadAppConfig,
|
|
13
19
|
loadConnections: fromCallback(({ sendBack, input }) => {
|
|
20
|
+
const spinner = new Spinner();
|
|
21
|
+
spinner.start("Loading connections...");
|
|
14
22
|
fetchConnections({
|
|
15
23
|
token: input.developer.token,
|
|
16
24
|
devSlug: input.developer.slug,
|
|
17
25
|
appId: input.config.id,
|
|
18
26
|
major: input.config.major,
|
|
19
27
|
})
|
|
20
|
-
.then((connections) =>
|
|
21
|
-
.
|
|
28
|
+
.then((connections) => {
|
|
29
|
+
spinner.success("Connections loaded");
|
|
30
|
+
sendBack({ type: "Connections Loaded", connections });
|
|
31
|
+
})
|
|
32
|
+
.catch((error) => {
|
|
33
|
+
spinner.error("Error loading connections");
|
|
34
|
+
sendBack({ type: "Error", error: error.message });
|
|
35
|
+
});
|
|
22
36
|
}),
|
|
23
37
|
},
|
|
24
38
|
actions: {
|
|
39
|
+
printLogo,
|
|
40
|
+
showError,
|
|
41
|
+
showConfigInstructions: ({ context }) => printInstallInstructions(context.configError),
|
|
42
|
+
showNoConnections: () => {
|
|
43
|
+
process.stdout.write(chalk.red("This app has no connections.\n\n"));
|
|
44
|
+
process.stdout.write("To add one, use:\n");
|
|
45
|
+
process.stdout.write(boxen("attio connection add", {
|
|
46
|
+
padding: 1,
|
|
47
|
+
margin: 1,
|
|
48
|
+
borderStyle: "round",
|
|
49
|
+
}) + "\n");
|
|
50
|
+
},
|
|
51
|
+
showConnections: ({ context: { connections } }) => {
|
|
52
|
+
const maxWidth = process.stdout.columns - 10;
|
|
53
|
+
const table = new Table({
|
|
54
|
+
head: ["Name", "Level", "Type"].map((h) => chalk.bold(h)),
|
|
55
|
+
style: {
|
|
56
|
+
head: [],
|
|
57
|
+
border: [],
|
|
58
|
+
},
|
|
59
|
+
colWidths: [
|
|
60
|
+
Math.floor(maxWidth * 0.5),
|
|
61
|
+
Math.floor(maxWidth * 0.2),
|
|
62
|
+
Math.floor(maxWidth * 0.3),
|
|
63
|
+
],
|
|
64
|
+
colAligns: ["left", "center", "center"],
|
|
65
|
+
wordWrap: true,
|
|
66
|
+
wrapOnWordBoundary: true,
|
|
67
|
+
});
|
|
68
|
+
table.push(...connections.map((connection) => [
|
|
69
|
+
connection.label,
|
|
70
|
+
connection.global ? "Workspace" : "User",
|
|
71
|
+
connection.connection_type === "secret" ? "Secret" : "OAuth2 Code",
|
|
72
|
+
]));
|
|
73
|
+
process.stdout.write(table.toString());
|
|
74
|
+
},
|
|
25
75
|
setError: assign({
|
|
26
76
|
error: (_, params) => params.error,
|
|
27
77
|
}),
|
|
@@ -66,6 +116,7 @@ export const listConnectionsMachine = setup({
|
|
|
66
116
|
},
|
|
67
117
|
"Show config instructions": {
|
|
68
118
|
type: "final",
|
|
119
|
+
entry: "showConfigInstructions",
|
|
69
120
|
},
|
|
70
121
|
"Loading App Config": {
|
|
71
122
|
invoke: {
|
|
@@ -84,6 +135,7 @@ export const listConnectionsMachine = setup({
|
|
|
84
135
|
},
|
|
85
136
|
"Error": {
|
|
86
137
|
type: "final",
|
|
138
|
+
entry: { type: "showError", params: ({ context }) => ({ error: context.error }) },
|
|
87
139
|
},
|
|
88
140
|
"Loading Connections": {
|
|
89
141
|
invoke: {
|
|
@@ -110,10 +162,13 @@ export const listConnectionsMachine = setup({
|
|
|
110
162
|
},
|
|
111
163
|
"No Connections": {
|
|
112
164
|
type: "final",
|
|
165
|
+
entry: "showNoConnections",
|
|
113
166
|
},
|
|
114
167
|
"Display Connections": {
|
|
115
168
|
type: "final",
|
|
169
|
+
entry: "showConnections",
|
|
116
170
|
},
|
|
117
171
|
},
|
|
118
172
|
initial: "Loading Developer Config",
|
|
173
|
+
entry: "printLogo",
|
|
119
174
|
});
|