main's format:check was red: 20 package.json files (publishConfig key ordering) plus two source files were not oxfmt-clean under 0.44.0. Run oxfmt to bring the tree back to a passing format:check so this branch can merge.
Unified · Split
| @@ -23,7 +23,6 @@ · 22 unmodified lines | |||
| 23 | ".": "./src/index.ts" | 23 | ".": "./src/index.ts" |
| 24 | }, | 24 | }, |
| 25 | "publishConfig": { | 25 | "publishConfig": { |
| 26 | "access": "public", | ||
| 27 | "exports": { | 26 | "exports": { |
| 28 | ".": { | 27 | ".": { |
| 29 | "import": { | 28 | "import": { |
| @@ -31,7 +30,8 @@ · 1 unmodified line | |||
| 31 | "default": "./dist/index.js" | 30 | "default": "./dist/index.js" |
| 32 | } | 31 | } |
| 33 | } | 32 | } |
| 34 | } | 33 | }, |
| 34 | "access": "public" | ||
| 35 | }, | 35 | }, |
| 36 | "scripts": { | 36 | "scripts": { |
| 37 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 37 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | ".": "./src/index.ts" | 19 | ".": "./src/index.ts" |
| 20 | }, | 20 | }, |
| 21 | "publishConfig": { | 21 | "publishConfig": { |
| 22 | "access": "public", | ||
| 23 | "exports": { | 22 | "exports": { |
| 24 | ".": { | 23 | ".": { |
| 25 | "import": { | 24 | "import": { |
| @@ -27,7 +26,8 @@ · 1 unmodified line | |||
| 27 | "default": "./dist/index.js" | 26 | "default": "./dist/index.js" |
| 28 | } | 27 | } |
| 29 | } | 28 | } |
| 30 | } | 29 | }, |
| 30 | "access": "public" | ||
| 31 | }, | 31 | }, |
| 32 | "scripts": { | 32 | "scripts": { |
| 33 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 33 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | "./promise": "./src/promise.ts" | 20 | "./promise": "./src/promise.ts" |
| 21 | }, | 21 | }, |
| 22 | "publishConfig": { | 22 | "publishConfig": { |
| 23 | "access": "public", | ||
| 24 | "exports": { | 23 | "exports": { |
| 25 | ".": { | 24 | ".": { |
| 26 | "import": { | 25 | "import": { |
| @@ -34,7 +33,8 @@ · 7 unmodified lines | |||
| 34 | "default": "./dist/core.js" | 33 | "default": "./dist/core.js" |
| 35 | } | 34 | } |
| 36 | } | 35 | } |
| 37 | } | 36 | }, |
| 37 | "access": "public" | ||
| 38 | }, | 38 | }, |
| 39 | "scripts": { | 39 | "scripts": { |
| 40 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 40 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | ".": "./src/index.ts" | 20 | ".": "./src/index.ts" |
| 21 | }, | 21 | }, |
| 22 | "publishConfig": { | 22 | "publishConfig": { |
| 23 | "access": "public", | ||
| 24 | "exports": { | 23 | "exports": { |
| 25 | ".": { | 24 | ".": { |
| 26 | "import": { | 25 | "import": { |
| @@ -28,7 +27,8 @@ · 1 unmodified line | |||
| 28 | "default": "./dist/index.js" | 27 | "default": "./dist/index.js" |
| 29 | } | 28 | } |
| 30 | } | 29 | } |
| 31 | } | 30 | }, |
| 31 | "access": "public" | ||
| 32 | }, | 32 | }, |
| 33 | "scripts": { | 33 | "scripts": { |
| 34 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 34 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -28,7 +28,6 @@ · 27 unmodified lines | |||
| 28 | "./public-origin": "./src/public-origin.ts" | 28 | "./public-origin": "./src/public-origin.ts" |
| 29 | }, | 29 | }, |
| 30 | "publishConfig": { | 30 | "publishConfig": { |
| 31 | "access": "public", | ||
| 32 | "exports": { | 31 | "exports": { |
| 33 | ".": { | 32 | ".": { |
| 34 | "import": { | 33 | "import": { |
| @@ -84,7 +83,8 @@ · 49 unmodified lines | |||
| 84 | "default": "./dist/public-origin.js" | 83 | "default": "./dist/public-origin.js" |
| 85 | } | 84 | } |
| 86 | } | 85 | } |
| 87 | } | 86 | }, |
| 87 | "access": "public" | ||
| 88 | }, | 88 | }, |
| 89 | "scripts": { | 89 | "scripts": { |
| 90 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 90 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -23,7 +23,6 @@ · 22 unmodified lines | |||
| 23 | } | 23 | } |
| 24 | }, | 24 | }, |
| 25 | "publishConfig": { | 25 | "publishConfig": { |
| 26 | "access": "public", | ||
| 27 | "exports": { | 26 | "exports": { |
| 28 | ".": { | 27 | ".": { |
| 29 | "import": { | 28 | "import": { |
| @@ -31,7 +30,8 @@ · 1 unmodified line | |||
| 31 | "default": "./dist/index.js" | 30 | "default": "./dist/index.js" |
| 32 | } | 31 | } |
| 33 | } | 32 | } |
| 34 | } | 33 | }, |
| 34 | "access": "public" | ||
| 35 | }, | 35 | }, |
| 36 | "scripts": { | 36 | "scripts": { |
| 37 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 37 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | ".": "./src/index.ts" | 19 | ".": "./src/index.ts" |
| 20 | }, | 20 | }, |
| 21 | "publishConfig": { | 21 | "publishConfig": { |
| 22 | "access": "public", | ||
| 23 | "exports": { | 22 | "exports": { |
| 24 | ".": { | 23 | ".": { |
| 25 | "import": { | 24 | "import": { |
| @@ -27,7 +26,8 @@ · 1 unmodified line | |||
| 27 | "default": "./dist/index.js" | 26 | "default": "./dist/index.js" |
| 28 | } | 27 | } |
| 29 | } | 28 | } |
| 30 | } | 29 | }, |
| 30 | "access": "public" | ||
| 31 | }, | 31 | }, |
| 32 | "scripts": { | 32 | "scripts": { |
| 33 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 33 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | ".": "./src/index.ts" | 19 | ".": "./src/index.ts" |
| 20 | }, | 20 | }, |
| 21 | "publishConfig": { | 21 | "publishConfig": { |
| 22 | "access": "public", | ||
| 23 | "exports": { | 22 | "exports": { |
| 24 | ".": { | 23 | ".": { |
| 25 | "import": { | 24 | "import": { |
| @@ -27,7 +26,8 @@ · 1 unmodified line | |||
| 27 | "default": "./dist/index.js" | 26 | "default": "./dist/index.js" |
| 28 | } | 27 | } |
| 29 | } | 28 | } |
| 30 | } | 29 | }, |
| 30 | "access": "public" | ||
| 31 | }, | 31 | }, |
| 32 | "scripts": { | 32 | "scripts": { |
| 33 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 33 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | "./client": "./src/client.tsx" | 20 | "./client": "./src/client.tsx" |
| 21 | }, | 21 | }, |
| 22 | "publishConfig": { | 22 | "publishConfig": { |
| 23 | "access": "public", | ||
| 24 | "exports": { | 23 | "exports": { |
| 25 | "./server": { | 24 | "./server": { |
| 26 | "import": { | 25 | "import": { |
| @@ -34,7 +33,8 @@ · 7 unmodified lines | |||
| 34 | "default": "./dist/client.js" | 33 | "default": "./dist/client.js" |
| 35 | } | 34 | } |
| 36 | } | 35 | } |
| 37 | } | 36 | }, |
| 37 | "access": "public" | ||
| 38 | }, | 38 | }, |
| 39 | "scripts": { | 39 | "scripts": { |
| 40 | "build": "tsup", | 40 | "build": "tsup", |
| @@ -21,7 +21,6 @@ · 20 unmodified lines | |||
| 21 | "./shared": "./src/shared.ts" | 21 | "./shared": "./src/shared.ts" |
| 22 | }, | 22 | }, |
| 23 | "publishConfig": { | 23 | "publishConfig": { |
| 24 | "access": "public", | ||
| 25 | "exports": { | 24 | "exports": { |
| 26 | "./server": { | 25 | "./server": { |
| 27 | "import": { | 26 | "import": { |
| @@ -41,7 +40,8 @@ · 13 unmodified lines | |||
| 41 | "default": "./dist/shared.js" | 40 | "default": "./dist/shared.js" |
| 42 | } | 41 | } |
| 43 | } | 42 | } |
| 44 | } | 43 | }, |
| 44 | "access": "public" | ||
| 45 | }, | 45 | }, |
| 46 | "scripts": { | 46 | "scripts": { |
| 47 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 47 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | "./promise": "./src/promise.ts" | 20 | "./promise": "./src/promise.ts" |
| 21 | }, | 21 | }, |
| 22 | "publishConfig": { | 22 | "publishConfig": { |
| 23 | "access": "public", | ||
| 24 | "exports": { | 23 | "exports": { |
| 25 | ".": { | 24 | ".": { |
| 26 | "import": { | 25 | "import": { |
| @@ -34,7 +33,8 @@ · 7 unmodified lines | |||
| 34 | "default": "./dist/core.js" | 33 | "default": "./dist/core.js" |
| 35 | } | 34 | } |
| 36 | } | 35 | } |
| 37 | } | 36 | }, |
| 37 | "access": "public" | ||
| 38 | }, | 38 | }, |
| 39 | "scripts": { | 39 | "scripts": { |
| 40 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 40 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -23,7 +23,6 @@ · 22 unmodified lines | |||
| 23 | "./client": "./src/react/plugin-client.tsx" | 23 | "./client": "./src/react/plugin-client.tsx" |
| 24 | }, | 24 | }, |
| 25 | "publishConfig": { | 25 | "publishConfig": { |
| 26 | "access": "public", | ||
| 27 | "exports": { | 26 | "exports": { |
| 28 | ".": { | 27 | ".": { |
| 29 | "import": { | 28 | "import": { |
| @@ -43,7 +42,8 @@ · 13 unmodified lines | |||
| 43 | "default": "./dist/client.js" | 42 | "default": "./dist/client.js" |
| 44 | } | 43 | } |
| 45 | } | 44 | } |
| 46 | } | 45 | }, |
| 46 | "access": "public" | ||
| 47 | }, | 47 | }, |
| 48 | "scripts": { | 48 | "scripts": { |
| 49 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 49 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -25,7 +25,6 @@ · 24 unmodified lines | |||
| 25 | "./testing": "./src/testing/index.ts" | 25 | "./testing": "./src/testing/index.ts" |
| 26 | }, | 26 | }, |
| 27 | "publishConfig": { | 27 | "publishConfig": { |
| 28 | "access": "public", | ||
| 29 | "exports": { | 28 | "exports": { |
| 30 | ".": { | 29 | ".": { |
| 31 | "import": { | 30 | "import": { |
| @@ -51,7 +50,8 @@ · 19 unmodified lines | |||
| 51 | "default": "./dist/testing.js" | 50 | "default": "./dist/testing.js" |
| 52 | } | 51 | } |
| 53 | } | 52 | } |
| 54 | } | 53 | }, |
| 54 | "access": "public" | ||
| 55 | }, | 55 | }, |
| 56 | "scripts": { | 56 | "scripts": { |
| 57 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 57 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -20,7 +20,6 @@ · 19 unmodified lines | |||
| 20 | "./promise": "./src/promise.ts" | 20 | "./promise": "./src/promise.ts" |
| 21 | }, | 21 | }, |
| 22 | "publishConfig": { | 22 | "publishConfig": { |
| 23 | "access": "public", | ||
| 24 | "exports": { | 23 | "exports": { |
| 25 | ".": { | 24 | ".": { |
| 26 | "import": { | 25 | "import": { |
| @@ -34,7 +33,8 @@ · 7 unmodified lines | |||
| 34 | "default": "./dist/core.js" | 33 | "default": "./dist/core.js" |
| 35 | } | 34 | } |
| 36 | } | 35 | } |
| 37 | } | 36 | }, |
| 37 | "access": "public" | ||
| 38 | }, | 38 | }, |
| 39 | "scripts": { | 39 | "scripts": { |
| 40 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 40 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -25,7 +25,6 @@ · 24 unmodified lines | |||
| 25 | "./testing": "./src/testing/index.ts" | 25 | "./testing": "./src/testing/index.ts" |
| 26 | }, | 26 | }, |
| 27 | "publishConfig": { | 27 | "publishConfig": { |
| 28 | "access": "public", | ||
| 29 | "exports": { | 28 | "exports": { |
| 30 | ".": { | 29 | ".": { |
| 31 | "import": { | 30 | "import": { |
| @@ -51,7 +50,8 @@ · 19 unmodified lines | |||
| 51 | "default": "./dist/testing.js" | 50 | "default": "./dist/testing.js" |
| 52 | } | 51 | } |
| 53 | } | 52 | } |
| 54 | } | 53 | }, |
| 54 | "access": "public" | ||
| 55 | }, | 55 | }, |
| 56 | "scripts": { | 56 | "scripts": { |
| 57 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 57 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -23,7 +23,6 @@ · 22 unmodified lines | |||
| 23 | "./client": "./src/react/plugin-client.tsx" | 23 | "./client": "./src/react/plugin-client.tsx" |
| 24 | }, | 24 | }, |
| 25 | "publishConfig": { | 25 | "publishConfig": { |
| 26 | "access": "public", | ||
| 27 | "exports": { | 26 | "exports": { |
| 28 | ".": { | 27 | ".": { |
| 29 | "import": { | 28 | "import": { |
| @@ -43,7 +42,8 @@ · 13 unmodified lines | |||
| 43 | "default": "./dist/client.js" | 42 | "default": "./dist/client.js" |
| 44 | } | 43 | } |
| 45 | } | 44 | } |
| 46 | } | 45 | }, |
| 46 | "access": "public" | ||
| 47 | }, | 47 | }, |
| 48 | "scripts": { | 48 | "scripts": { |
| 49 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 49 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -23,7 +23,6 @@ · 22 unmodified lines | |||
| 23 | "./client": "./src/react/plugin-client.tsx" | 23 | "./client": "./src/react/plugin-client.tsx" |
| 24 | }, | 24 | }, |
| 25 | "publishConfig": { | 25 | "publishConfig": { |
| 26 | "access": "public", | ||
| 27 | "exports": { | 26 | "exports": { |
| 28 | ".": { | 27 | ".": { |
| 29 | "import": { | 28 | "import": { |
| @@ -43,7 +42,8 @@ · 13 unmodified lines | |||
| 43 | "default": "./dist/client.js" | 42 | "default": "./dist/client.js" |
| 44 | } | 43 | } |
| 45 | } | 44 | } |
| 46 | } | 45 | }, |
| 46 | "access": "public" | ||
| 47 | }, | 47 | }, |
| 48 | "scripts": { | 48 | "scripts": { |
| 49 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 49 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -25,7 +25,6 @@ · 24 unmodified lines | |||
| 25 | "./testing": "./src/testing/index.ts" | 25 | "./testing": "./src/testing/index.ts" |
| 26 | }, | 26 | }, |
| 27 | "publishConfig": { | 27 | "publishConfig": { |
| 28 | "access": "public", | ||
| 29 | "exports": { | 28 | "exports": { |
| 30 | ".": { | 29 | ".": { |
| 31 | "import": { | 30 | "import": { |
| @@ -51,7 +50,8 @@ · 19 unmodified lines | |||
| 51 | "default": "./dist/testing.js" | 50 | "default": "./dist/testing.js" |
| 52 | } | 51 | } |
| 53 | } | 52 | } |
| 54 | } | 53 | }, |
| 54 | "access": "public" | ||
| 55 | }, | 55 | }, |
| 56 | "scripts": { | 56 | "scripts": { |
| 57 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 57 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -21,7 +21,6 @@ · 20 unmodified lines | |||
| 21 | "./shared": "./src/shared.ts" | 21 | "./shared": "./src/shared.ts" |
| 22 | }, | 22 | }, |
| 23 | "publishConfig": { | 23 | "publishConfig": { |
| 24 | "access": "public", | ||
| 25 | "exports": { | 24 | "exports": { |
| 26 | "./server": { | 25 | "./server": { |
| 27 | "import": { | 26 | "import": { |
| @@ -41,7 +40,8 @@ · 13 unmodified lines | |||
| 41 | "default": "./dist/shared.js" | 40 | "default": "./dist/shared.js" |
| 42 | } | 41 | } |
| 43 | } | 42 | } |
| 44 | } | 43 | }, |
| 44 | "access": "public" | ||
| 45 | }, | 45 | }, |
| 46 | "scripts": { | 46 | "scripts": { |
| 47 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 47 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -23,7 +23,6 @@ · 22 unmodified lines | |||
| 23 | "./testing": "./src/sdk/testing.ts" | 23 | "./testing": "./src/sdk/testing.ts" |
| 24 | }, | 24 | }, |
| 25 | "publishConfig": { | 25 | "publishConfig": { |
| 26 | "access": "public", | ||
| 27 | "exports": { | 26 | "exports": { |
| 28 | ".": { | 27 | ".": { |
| 29 | "import": { | 28 | "import": { |
| @@ -43,7 +42,8 @@ · 13 unmodified lines | |||
| 43 | "default": "./dist/testing.js" | 42 | "default": "./dist/testing.js" |
| 44 | } | 43 | } |
| 45 | } | 44 | } |
| 46 | } | 45 | }, |
| 46 | "access": "public" | ||
| 47 | }, | 47 | }, |
| 48 | "scripts": { | 48 | "scripts": { |
| 49 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", | 49 | "build": "tsup && (tsc --declaration --emitDeclarationOnly --outDir dist --rootDir src || true)", |
| @@ -2,11 +2,7 @@ import { useEffect, useMemo, useState } from "react"; · 1 unmodified line | |||
| 2 | import { useAtomValue, useAtomSet } from "@effect/atom-react"; | 2 | import { useAtomValue, useAtomSet } from "@effect/atom-react"; |
| 3 | import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; | 3 | import * as AsyncResult from "effect/unstable/reactivity/AsyncResult"; |
| 4 | import * as Exit from "effect/Exit"; | 4 | import * as Exit from "effect/Exit"; |
| 5 | import { | 5 | import { IntegrationSlug, type Connection, type Owner } from "@executor-js/sdk/shared"; |
| 6 | IntegrationSlug, | ||
| 7 | type Connection, | ||
| 8 | type Owner, | ||
| 9 | } from "@executor-js/sdk/shared"; | ||
| 10 | import type { IntegrationAccountHandoff } from "@executor-js/sdk/client"; | 6 | import type { IntegrationAccountHandoff } from "@executor-js/sdk/client"; |
| 11 | import { toast } from "sonner"; | 7 | import { toast } from "sonner"; |
| 12 | 8 | ||
| @@ -84,10 +80,7 @@ function AccountRow(props: { · 71 unmodified lines | |||
| 84 | <CardStackEntryTitle className="flex min-w-0 items-center gap-2"> | 80 | <CardStackEntryTitle className="flex min-w-0 items-center gap-2"> |
| 85 | <span className="truncate">{displayLabel}</span> | 81 | <span className="truncate">{displayLabel}</span> |
| 86 | {needsReconsent ? ( | 82 | {needsReconsent ? ( |
| 87 | <Badge | 83 | <Badge variant="outline" className="shrink-0 border-border text-muted-foreground"> |
| 88 | variant="outline" | ||
| 89 | className="shrink-0 border-border text-muted-foreground" | ||
| 90 | > | ||
| 91 | Reconnect to grant access | 84 | Reconnect to grant access |
| 92 | </Badge> | 85 | </Badge> |
| 93 | ) : null} | 86 | ) : null} |
| @@ -99,8 +92,7 @@ function AccountRow(props: { · 5 unmodified lines | |||
| 99 | ) : null} | 92 | ) : null} |
| 100 | {needsReconsent ? ( | 93 | {needsReconsent ? ( |
| 101 | <CardStackEntryDescription className="mt-1 text-xs text-muted-foreground"> | 94 | <CardStackEntryDescription className="mt-1 text-xs text-muted-foreground"> |
| 102 | This connection wasn't granted all the access this integration now | 95 | This connection wasn't granted all the access this integration now needs. |
| 103 | needs. | ||
| 104 | </CardStackEntryDescription> | 96 | </CardStackEntryDescription> |
| 105 | ) : null} | 97 | ) : null} |
| 106 | </CardStackEntryContent> | 98 | </CardStackEntryContent> |
| @@ -129,11 +121,7 @@ function AccountRow(props: { · 22 unmodified lines | |||
| 129 | <DropdownMenuItem className="text-sm" onClick={props.onReconnect}> | 121 | <DropdownMenuItem className="text-sm" onClick={props.onReconnect}> |
| 130 | Reconnect | 122 | Reconnect |
| 131 | </DropdownMenuItem> | 123 | </DropdownMenuItem> |
| 132 | <DropdownMenuItem | 124 | <DropdownMenuItem variant="destructive" className="text-sm" onClick={props.onRemove}> |
| 133 | variant="destructive" | ||
| 134 | className="text-sm" | ||
| 135 | onClick={props.onRemove} | ||
| 136 | > | ||
| 137 | Remove | 125 | Remove |
| 138 | </DropdownMenuItem> | 126 | </DropdownMenuItem> |
| 139 | </DropdownMenuContent> | 127 | </DropdownMenuContent> |
| @@ -155,9 +143,7 @@ function OwnerAccounts(props: { · 15 unmodified lines | |||
| 155 | readonly declaredScopes: readonly string[] | undefined; | 143 | readonly declaredScopes: readonly string[] | undefined; |
| 156 | }) { | 144 | }) { |
| 157 | const { integration, owner } = props; | 145 | const { integration, owner } = props; |
| 158 | const connections = useAtomValue( | 146 | const connections = useAtomValue(connectionsForIntegrationAtom({ integration, owner })); |
| 159 | connectionsForIntegrationAtom({ integration, owner }), | ||
| 160 | ); | ||
| 161 | const doRemove = useAtomSet(removeConnectionOptimistic(owner), { | 147 | const doRemove = useAtomSet(removeConnectionOptimistic(owner), { |
| 162 | mode: "promiseExit", | 148 | mode: "promiseExit", |
| 163 | }); | 149 | }); |
| @@ -174,9 +160,7 @@ function OwnerAccounts(props: { · 10 unmodified lines | |||
| 174 | startErrorMessage: "Failed to reconnect", | 160 | startErrorMessage: "Failed to reconnect", |
| 175 | }); | 161 | }); |
| 176 | 162 | ||
| 177 | const rows: readonly Connection[] = AsyncResult.isSuccess(connections) | 163 | const rows: readonly Connection[] = AsyncResult.isSuccess(connections) ? connections.value : []; |
| 178 | ? connections.value | ||
| 179 | : []; | ||
| 180 | if (rows.length === 0) return null; | 164 | if (rows.length === 0) return null; |
| 181 | 165 | ||
| 182 | const handleReconnect = async (connection: Connection) => { | 166 | const handleReconnect = async (connection: Connection) => { |
| @@ -185,8 +169,7 @@ function OwnerAccounts(props: { · 2 unmodified lines | |||
| 185 | if (reconnectMode(connection) === "oauth") { | 169 | if (reconnectMode(connection) === "oauth") { |
| 186 | const method = props.methods.find( | 170 | const method = props.methods.find( |
| 187 | (candidate: AuthMethod) => | 171 | (candidate: AuthMethod) => |
| 188 | candidate.kind === "oauth" && | 172 | candidate.kind === "oauth" && String(candidate.template) === String(connection.template), |
| 189 | String(candidate.template) === String(connection.template), | ||
| 190 | ); | 173 | ); |
| 191 | if ( | 174 | if ( |
| 192 | method?.oauth?.supportsDynamicRegistration === true || | 175 | method?.oauth?.supportsDynamicRegistration === true || |
| @@ -293,18 +276,13 @@ function OwnerAccounts(props: { · 100 unmodified lines | |||
| 293 | 276 | ||
| 294 | return ( | 277 | return ( |
| 295 | <CardStack> | 278 | <CardStack> |
| 296 | {props.showOwnerLabels ? ( | 279 | {props.showOwnerLabels ? <CardStackHeader>{ownerLabel(owner)}</CardStackHeader> : null} |
| 297 | <CardStackHeader>{ownerLabel(owner)}</CardStackHeader> | ||
| 298 | ) : null} | ||
| 299 | <CardStackContent> | 280 | <CardStackContent> |
| 300 | {rows.map((connection: Connection) => ( | 281 | {rows.map((connection: Connection) => ( |
| 301 | <AccountRow | 282 | <AccountRow |
| 302 | key={`${connection.owner}:${connection.integration}:${connection.name}`} | 283 | key={`${connection.owner}:${connection.integration}:${connection.name}`} |
| 303 | connection={connection} | 284 | connection={connection} |
| 304 | needsReconsent={connectionNeedsReconsent( | 285 | needsReconsent={connectionNeedsReconsent(connection, props.declaredScopes)} |
| 305 | connection, | ||
| 306 | props.declaredScopes, | ||
| 307 | )} | ||
| 308 | showOwnerLabel={props.showOwnerLabels} | 286 | showOwnerLabel={props.showOwnerLabels} |
| 309 | onEdit={() => props.onEdit(connection)} | 287 | onEdit={() => props.onEdit(connection)} |
| 310 | onReconnect={() => void handleReconnect(connection)} | 288 | onReconnect={() => void handleReconnect(connection)} |
| @@ -335,14 +313,10 @@ export function AccountsSection(props: { · 24 unmodified lines | |||
| 335 | removeCustomMethod, | 313 | removeCustomMethod, |
| 336 | } = props; | 314 | } = props; |
| 337 | const [adding, setAdding] = useState(false); | 315 | const [adding, setAdding] = useState(false); |
| 338 | const [editingConnection, setEditingConnection] = useState<Connection | null>( | 316 | const [editingConnection, setEditingConnection] = useState<Connection | null>(null); |
| 339 | null, | 317 | const [reconnectHandoff, setReconnectHandoff] = useState<IntegrationAccountHandoff | null>(null); |
| 340 | ); | ||
| 341 | const [reconnectHandoff, setReconnectHandoff] = | ||
| 342 | useState<IntegrationAccountHandoff | null>(null); | ||
| 343 | const ownerDisplay = useOwnerDisplay(); | 318 | const ownerDisplay = useOwnerDisplay(); |
| 344 | const canAddConnection = | 319 | const canAddConnection = methods.length > 0 || createCustomMethod !== undefined; |
| 345 | methods.length > 0 || createCustomMethod !== undefined; | ||
| 346 | 320 | ||
| 347 | useEffect(() => { | 321 | useEffect(() => { |
| 348 | if (accountHandoff) { | 322 | if (accountHandoff) { |
| @@ -364,9 +338,7 @@ export function AccountsSection(props: { · 15 unmodified lines | |||
| 364 | 338 | ||
| 365 | // Read both owners to decide between the grouped view and the empty CTA. The | 339 | // Read both owners to decide between the grouped view and the empty CTA. The |
| 366 | // grouped sub-components re-read these (effect-atom dedupes) and self-hide. | 340 | // grouped sub-components re-read these (effect-atom dedupes) and self-hide. |
| 367 | const orgConnections = useAtomValue( | 341 | const orgConnections = useAtomValue(connectionsForIntegrationAtom({ integration, owner: "org" })); |
| 368 | connectionsForIntegrationAtom({ integration, owner: "org" }), | ||
| 369 | ); | ||
| 370 | const userConnections = useAtomValue( | 342 | const userConnections = useAtomValue( |
| 371 | connectionsForIntegrationAtom({ integration, owner: "user" }), | 343 | connectionsForIntegrationAtom({ integration, owner: "user" }), |
| 372 | ); | 344 | ); |
| @@ -377,18 +349,12 @@ export function AccountsSection(props: { · 4 unmodified lines | |||
| 377 | useAtomSet(addConnectionOptimistic("user")); | 349 | useAtomSet(addConnectionOptimistic("user")); |
| 378 | 350 | ||
| 379 | const totalCount = useMemo(() => { | 351 | const totalCount = useMemo(() => { |
| 380 | const orgRows = AsyncResult.isSuccess(orgConnections) | 352 | const orgRows = AsyncResult.isSuccess(orgConnections) ? orgConnections.value.length : 0; |
| 381 | ? orgConnections.value.length | 353 | const userRows = AsyncResult.isSuccess(userConnections) ? userConnections.value.length : 0; |
| 382 | : 0; | ||
| 383 | const userRows = AsyncResult.isSuccess(userConnections) | ||
| 384 | ? userConnections.value.length | ||
| 385 | : 0; | ||
| 386 | return orgRows + userRows; | 354 | return orgRows + userRows; |
| 387 | }, [orgConnections, userConnections]); | 355 | }, [orgConnections, userConnections]); |
| 388 | 356 | ||
| 389 | const loading = | 357 | const loading = !AsyncResult.isSuccess(orgConnections) && !AsyncResult.isSuccess(userConnections); |
| 390 | !AsyncResult.isSuccess(orgConnections) && | ||
| 391 | !AsyncResult.isSuccess(userConnections); | ||
| 392 | 358 | ||
| 393 | const modalState = reconnectHandoff ?? accountHandoff; | 359 | const modalState = reconnectHandoff ?? accountHandoff; |
| 394 | const modal = ( | 360 | const modal = ( |
| @@ -420,9 +386,7 @@ export function AccountsSection(props: { · 25 unmodified lines | |||
| 420 | onClick={() => { | 386 | onClick={() => { |
| 421 | trackEvent("connection_add_opened", { | 387 | trackEvent("connection_add_opened", { |
| 422 | integration_slug: String(integration), | 388 | integration_slug: String(integration), |
| 423 | has_oauth_method: methods.some( | 389 | has_oauth_method: methods.some((m: AuthMethod) => m.kind === "oauth"), |
| 424 | (m: AuthMethod) => m.kind === "oauth", | ||
| 425 | ), | ||
| 426 | has_api_key_method: methods.some( | 390 | has_api_key_method: methods.some( |
| 427 | (m: AuthMethod) => m.kind !== "oauth" && m.kind !== "none", | 391 | (m: AuthMethod) => m.kind !== "oauth" && m.kind !== "none", |
| 428 | ), | 392 | ), |
| @@ -442,9 +406,7 @@ export function AccountsSection(props: { · 13 unmodified lines | |||
| 442 | </div> | 406 | </div> |
| 443 | ) : totalCount === 0 ? ( | 407 | ) : totalCount === 0 ? ( |
| 444 | <div className="rounded-lg border border-dashed border-border/60 px-6 py-8 text-center"> | 408 | <div className="rounded-lg border border-dashed border-border/60 px-6 py-8 text-center"> |
| 445 | <p className="text-sm font-medium text-foreground"> | 409 | <p className="text-sm font-medium text-foreground">No connections yet</p> |
| 446 | No connections yet | ||
| 447 | </p> | ||
| 448 | <p className="mt-1 text-sm text-muted-foreground"> | 410 | <p className="mt-1 text-sm text-muted-foreground"> |
| 449 | Add a connection to make this integration's tools available. | 411 | Add a connection to make this integration's tools available. |
| 450 | </p> | 412 | </p> |
| @@ -455,9 +417,7 @@ export function AccountsSection(props: { · 4 unmodified lines | |||
| 455 | onClick={() => { | 417 | onClick={() => { |
| 456 | trackEvent("connection_add_opened", { | 418 | trackEvent("connection_add_opened", { |
| 457 | integration_slug: String(integration), | 419 | integration_slug: String(integration), |
| 458 | has_oauth_method: methods.some( | 420 | has_oauth_method: methods.some((m: AuthMethod) => m.kind === "oauth"), |
| 459 | (m: AuthMethod) => m.kind === "oauth", | ||
| 460 | ), | ||
| 461 | has_api_key_method: methods.some( | 421 | has_api_key_method: methods.some( |
| 462 | (m: AuthMethod) => m.kind !== "oauth" && m.kind !== "none", | 422 | (m: AuthMethod) => m.kind !== "oauth" && m.kind !== "none", |
| 463 | ), | 423 | ), |
| @@ -28,9 +28,7 @@ export function reconnectMode(connection: Connection): ReconnectMode { · 27 unmodified lines | |||
| 28 | * connection are exactly the branded types `oauth.start` expects, so the same | 28 | * connection are exactly the branded types `oauth.start` expects, so the same |
| 29 | * connection (owner/integration/name) is re-minted with a fresh refresh token | 29 | * connection (owner/integration/name) is re-minted with a fresh refresh token |
| 30 | * and the widened scope union. Returns null for a non-OAuth connection. */ | 30 | * and the widened scope union. Returns null for a non-OAuth connection. */ |
| 31 | export function oauthReconnectPayload( | 31 | export function oauthReconnectPayload(connection: Connection): OAuthStartPayload | null { |
| 32 | connection: Connection, | ||
| 33 | ): OAuthStartPayload | null { | ||
| 34 | if (connection.oauthClient == null) return null; | 32 | if (connection.oauthClient == null) return null; |
| 35 | return { | 33 | return { |
| 36 | client: connection.oauthClient, | 34 | client: connection.oauthClient, |
| @@ -61,8 +59,7 @@ const OAUTH_SCOPE_ALIASES: Readonly<Record<string, string>> = { · 24 unmodified lines | |||
| 61 | "https://www.googleapis.com/auth/userinfo.profile": "profile", | 59 | "https://www.googleapis.com/auth/userinfo.profile": "profile", |
| 62 | }; | 60 | }; |
| 63 | 61 | ||
| 64 | const canonicalScope = (scope: string): string => | 62 | const canonicalScope = (scope: string): string => OAUTH_SCOPE_ALIASES[scope] ?? scope; |
| 65 | OAUTH_SCOPE_ALIASES[scope] ?? scope; | ||
| 66 | 63 | ||
| 67 | /** Normalize a scope list: trim, canonicalize known provider aliases, drop | 64 | /** Normalize a scope list: trim, canonicalize known provider aliases, drop |
| 68 | * empties, de-dupe (order-preserving). A scope set is compared as a SET — | 65 | * empties, de-dupe (order-preserving). A scope set is compared as a SET — |
| @@ -94,12 +91,8 @@ export function missingScopes( · 25 unmodified lines | |||
| 94 | 91 | ||
| 95 | /** The scopes a connection was actually GRANTED, parsed from its space-delimited | 92 | /** The scopes a connection was actually GRANTED, parsed from its space-delimited |
| 96 | * `oauthScope` record. Empty for static creds / when the AS omitted scope. */ | 93 | * `oauthScope` record. Empty for static creds / when the AS omitted scope. */ |
| 97 | export function connectionGrantedScopes( | 94 | export function connectionGrantedScopes(connection: Connection): readonly string[] { |
| 98 | connection: Connection, | 95 | return connection.oauthScope ? connection.oauthScope.split(/\s+/).filter(Boolean) : []; |
| 99 | ): readonly string[] { | ||
| 100 | return connection.oauthScope | ||
| 101 | ? connection.oauthScope.split(/\s+/).filter(Boolean) | ||
| 102 | : []; | ||
| 103 | } | 96 | } |
| 104 | 97 | ||
| 105 | /** Whether an OAuth connection must RECONNECT to grant newly-needed access: the | 98 | /** Whether an OAuth connection must RECONNECT to grant newly-needed access: the |
| @@ -113,10 +106,7 @@ export function connectionNeedsReconsent( · 7 unmodified lines | |||
| 113 | declaredScopes: readonly string[] | undefined, | 106 | declaredScopes: readonly string[] | undefined, |
| 114 | ): boolean { | 107 | ): boolean { |
| 115 | if (connection.oauthClient == null) return false; | 108 | if (connection.oauthClient == null) return false; |
| 116 | return ( | 109 | return missingScopes(declaredScopes, connectionGrantedScopes(connection)).length > 0; |
| 117 | missingScopes(declaredScopes, connectionGrantedScopes(connection)).length > | ||
| 118 | 0 | ||
| 119 | ); | ||
| 120 | } | 110 | } |
| 121 | 111 | ||
| 122 | /** The scopes that count as REQUIRED for a connection to be considered fully | 112 | /** The scopes that count as REQUIRED for a connection to be considered fully |