diff --git a/.env.example b/.env.example index 90293a0a..a231b6f3 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ VERSION=0.3.0-alpha -NODE_ENV=production +NODE_ENV=development ############# Common ############### @@ -69,9 +69,10 @@ OLLAMA_HOST=http://localhost:11434 ############# Frontend ############### # Sync server url used by the frontend to connect to the websocket and server -NEXT_PUBLIC_BACKEND_URL=${BACKEND_URL} NEXT_PUBLIC_BASE_HOST=${FRONTEND_HOST} NEXT_PUBLIC_BACKEND_HOST=${BACKEND_HOST} +NEXT_PUBLIC_POSTHOG_KEY= +NEXT_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com # You need to set your domain if self-hosted PUBLIC_ATTACHMENT_URL=http://localhost:3000/api @@ -85,6 +86,7 @@ TRIGGER_COMMON_ID=clyofc7dn0000o33e4sup590l TRIGGER_TOKEN=27192e6432564f4788d55c15131bd5ac TRIGGER_ACCESS_TOKEN=tr_pat_${TRIGGER_TOKEN} +TRIGGER_API_URL=http://localhost:3030 TRIGGER_DB=trigger TRIGGER_DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${DB_HOST}/${TRIGGER_DB} diff --git a/actions/slack-common-workflows/package.json b/actions/slack-common-workflows/package.json index 09d7e44b..989dab31 100644 --- a/actions/slack-common-workflows/package.json +++ b/actions/slack-common-workflows/package.json @@ -9,9 +9,10 @@ }, "packageManager": "pnpm@8.15.6", "dependencies": { - "@tegonhq/sdk": "^0.1.0-beta.15", + "@tegonhq/sdk": "^0.1.3", + "@trigger.dev/sdk": "3.0.0-beta.55", "axios": "^1.6.7", - "@trigger.dev/sdk": "3.0.0-beta.55" + "form-data": "^4.0.0" }, "devDependencies": { "@types/jsonwebtoken": "^9.0.6", diff --git a/actions/slack-common-workflows/pnpm-lock.yaml b/actions/slack-common-workflows/pnpm-lock.yaml index 95dad091..9cc63edb 100644 --- a/actions/slack-common-workflows/pnpm-lock.yaml +++ b/actions/slack-common-workflows/pnpm-lock.yaml @@ -9,21 +9,24 @@ importers: .: dependencies: '@tegonhq/sdk': - specifier: ^0.1.0-beta.15 - version: 0.1.0-beta.15(typescript@5.5.4) + specifier: ^0.1.3 + version: 0.1.3(typescript@5.5.4) '@trigger.dev/sdk': specifier: 3.0.0-beta.55 version: 3.0.0-beta.55(typescript@5.5.4) axios: specifier: ^1.6.7 - version: 1.7.4(debug@4.3.6) + version: 1.7.5(debug@4.3.6) + form-data: + specifier: ^4.0.0 + version: 4.0.0 devDependencies: '@types/jsonwebtoken': specifier: ^9.0.6 version: 9.0.6 '@types/node': specifier: ^22.1.0 - version: 22.3.0 + version: 22.5.1 '@typescript-eslint/eslint-plugin': specifier: ^7.1.0 version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) @@ -169,8 +172,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' - '@opentelemetry/context-async-hooks@1.25.1': - resolution: {integrity: sha512-UW/ge9zjvAEmRWVapOP0qyCvPulWU6cQxGxDbWEFfGOj1VBBZAuOqTo3X6yWmDTD3Xe15ysCZChHncr2xFMIfQ==} + '@opentelemetry/context-async-hooks@1.26.0': + resolution: {integrity: sha512-HedpXXYzzbaoutw6DFLWLDket2FwLkLpil4hGCZ1xYEIMTcivdfwEOISgdbLEWyG3HW52gTq2V9mOVJrONgiwg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -181,8 +184,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' - '@opentelemetry/core@1.25.1': - resolution: {integrity: sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==} + '@opentelemetry/core@1.26.0': + resolution: {integrity: sha512-1iKxXXE8415Cdv0yjG3G6hQnB5eVEsJce3QaawX8SjDn0mAS0ZM8fAbZZJD4ajvhC15cePvosSCut404KrIIvQ==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -253,8 +256,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' - '@opentelemetry/propagator-b3@1.25.1': - resolution: {integrity: sha512-p6HFscpjrv7//kE+7L+3Vn00VEDUJB0n6ZrjkTYHrJ58QZ8B3ajSJhRbCcY6guQ3PDjTbxWklyvIN2ojVbIb1A==} + '@opentelemetry/propagator-b3@1.26.0': + resolution: {integrity: sha512-vvVkQLQ/lGGyEy9GT8uFnI047pajSOVnZI2poJqVGD3nJ+B9sFGdlHNnQKophE3lHfnIH0pw2ubrCTjZCgIj+Q==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -265,8 +268,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' - '@opentelemetry/propagator-jaeger@1.25.1': - resolution: {integrity: sha512-nBprRf0+jlgxks78G/xq72PipVK+4or9Ypntw0gVZYNTCSK8rg5SeaGV19tV920CMqBD/9UIOiFr23Li/Q8tiA==} + '@opentelemetry/propagator-jaeger@1.26.0': + resolution: {integrity: sha512-DelFGkCdaxA1C/QA0Xilszfr0t4YbGd3DjxiCDPh34lfnFr+VkkrjV9S8ZTJvAzfdKERXhfOxIKBoGPJwoSz7Q==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -277,8 +280,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' - '@opentelemetry/resources@1.25.1': - resolution: {integrity: sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ==} + '@opentelemetry/resources@1.26.0': + resolution: {integrity: sha512-CPNYchBE7MBecCSVy0HKpUISEeJOniWqcHaAHpmasZ3j9o6V3AyBzhRc90jdmemq0HOxDr6ylhUbDhBqqPpeNw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -308,8 +311,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' - '@opentelemetry/sdk-trace-base@1.25.1': - resolution: {integrity: sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw==} + '@opentelemetry/sdk-trace-base@1.26.0': + resolution: {integrity: sha512-olWQldtvbK4v22ymrKLbIcBi9L2SpMO84sCPY54IVsJhP9fRsxJT194C/AVaAuJzLE30EdhhM1VmvVYR7az+cw==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -320,8 +323,8 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.9.0' - '@opentelemetry/sdk-trace-node@1.25.1': - resolution: {integrity: sha512-nMcjFIKxnFqoez4gUmihdBrbpsEnAX/Xj16sGvZm+guceYE0NE00vLhpDVK6f3q8Q4VFI5xG8JjlXKMB/SkTTQ==} + '@opentelemetry/sdk-trace-node@1.26.0': + resolution: {integrity: sha512-Fj5IVKrj0yeUwlewCRwzOVcr5avTuNnMHWf7GPc1t6WaT78J6CJyF3saZ/0RkZfdeNO8IcBl/bNcWMVZBMRW8Q==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' @@ -330,8 +333,8 @@ packages: resolution: {integrity: sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==} engines: {node: '>=14'} - '@opentelemetry/semantic-conventions@1.25.1': - resolution: {integrity: sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==} + '@opentelemetry/semantic-conventions@1.27.0': + resolution: {integrity: sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==} engines: {node: '>=14'} '@pkgr/core@0.1.1': @@ -371,8 +374,8 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - '@tegonhq/sdk@0.1.0-beta.15': - resolution: {integrity: sha512-GKbYUCDvdLM6rmhF7u884ULx3trWax3ytc68Qz+n27iCSAkL5Ba4QAFkf/QhYDcIZUOZ2ejGy6Dpdz1TYPOTNA==} + '@tegonhq/sdk@0.1.3': + resolution: {integrity: sha512-2PMrE2rdPO2Qc9C6Oey9pPxJ/44nJUR375ur4+7rE7bajfwwGSjA9VvTzJM8tucA79gJFd/uI1qsuFqCdhukoA==} engines: {node: '>=18.0.0'} '@trigger.dev/core-backend@3.0.0-beta.50': @@ -411,8 +414,8 @@ packages: '@types/mute-stream@0.0.4': resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==} - '@types/node@22.3.0': - resolution: {integrity: sha512-nrWpWVaDZuaVc5X84xJ0vNrLvomM205oQyLsRt7OHNZbSHslcWsvgFR7O7hire2ZonjLrWBbedmotmIlJDVd6g==} + '@types/node@22.5.1': + resolution: {integrity: sha512-KkHsxej0j9IW1KKOOAA/XBA0z08UFSrRQHErzEfA3Vgq57eXIMYboIlHJuYIfd+lwCQjtKqUu3UnmKbtUc9yRw==} '@types/shimmer@1.2.0': resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} @@ -562,8 +565,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axios@1.7.4: - resolution: {integrity: sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==} + axios@1.7.5: + resolution: {integrity: sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -597,8 +600,8 @@ packages: resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - cjs-module-lexer@1.3.1: - resolution: {integrity: sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==} + cjs-module-lexer@1.4.0: + resolution: {integrity: sha512-N1NGmowPlGBLsOZLPvm48StN04V4YvQRL0i6b7ctrVY3epjP/ct7hFLOItz6pDIvRjwpfPxi52a2UWV2ziir8g==} cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} @@ -763,8 +766,8 @@ packages: eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-module-utils@2.8.1: - resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} + eslint-module-utils@2.8.2: + resolution: {integrity: sha512-3XnC5fDyc8M4J2E8pt8pmSVRX2M+5yWMCfI/kDZwauQeFgzQOuhcRBFKjTeJagqgk4sFKxe1mvNVnaWwImx/Tg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -985,10 +988,6 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - graphql@16.9.0: - resolution: {integrity: sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} @@ -1065,8 +1064,8 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.15.0: - resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==} + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} is-data-view@1.0.1: @@ -1216,8 +1215,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - micromatch@4.0.7: - resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} mime-db@1.52.0: @@ -1250,13 +1249,16 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw@2.3.5: - resolution: {integrity: sha512-+GUI4gX5YC5Bv33epBrD+BGdmDvBg2XGruiWnI3GbIbRmMMBeZ5gs3mJ51OWSGHgJKztZ8AtZeYMMNMVrje2/Q==} + msw@2.4.0: + resolution: {integrity: sha512-NqAjbDvJ66J/VS9KqLmY8ZF6ceQpYRy+s2yJYLl+3vUdNa4C7zouXVDl1TLast/o9gLzPMTrfaTJkeR7qJ41ew==} engines: {node: '>=18'} hasBin: true peerDependencies: + graphql: '*' typescript: '>= 4.7.x' peerDependenciesMeta: + graphql: + optional: true typescript: optional: true @@ -1356,8 +1358,8 @@ packages: engines: {node: '>=14'} hasBin: true - protobufjs@7.3.2: - resolution: {integrity: sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==} + protobufjs@7.4.0: + resolution: {integrity: sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==} engines: {node: '>=12.0.0'} proxy-from-env@1.1.0: @@ -1560,8 +1562,8 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - tslib@2.6.3: - resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -1579,8 +1581,8 @@ packages: resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} engines: {node: '>=10'} - type-fest@4.24.0: - resolution: {integrity: sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==} + type-fest@4.26.0: + resolution: {integrity: sha512-OduNjVJsFbifKb57UqZ2EMP1i4u64Xwow3NYXUtBbD4vIwJdQd4+xl8YDou1dlm4DVrtwT/7Ky8z8WyCULVfxw==} engines: {node: '>=16'} typed-array-buffer@1.0.2: @@ -1608,15 +1610,15 @@ packages: resolution: {integrity: sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==} hasBin: true - ulidx@2.4.0: - resolution: {integrity: sha512-iTZHiSCrIZeXvbJ34qCSBO4fmwf4GRzkv3hb7adB+00nyJKCwVFK0xw2gXGNfJsIFfET7Av+OP8/rsxxJHRSVQ==} + ulidx@2.4.1: + resolution: {integrity: sha512-xY7c8LPyzvhvew0Fn+Ek3wBC9STZAuDI/Y5andCKi9AX6/jvfaX45PhsDX8oxgPL0YFp0Jhr8qWMbS/p9375Xg==} engines: {node: '>=16'} unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - undici-types@6.18.2: - resolution: {integrity: sha512-5ruQbENj95yDYJNS3TvcaxPMshV7aizdv/hWYjGIKoANWKjhWNBsr2YEuYZKodQulB1b8l7ILOuDQep3afowQQ==} + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} @@ -1775,7 +1777,7 @@ snapshots: dependencies: lodash.camelcase: 4.3.0 long: 5.2.3 - protobufjs: 7.3.2 + protobufjs: 7.4.0 yargs: 17.7.2 '@humanwhocodes/config-array@0.11.14': @@ -1800,7 +1802,7 @@ snapshots: '@inquirer/figures': 1.0.5 '@inquirer/type': 1.5.2 '@types/mute-stream': 0.0.4 - '@types/node': 22.3.0 + '@types/node': 22.5.1 '@types/wrap-ansi': 3.0.0 ansi-escapes: 4.3.2 cli-spinners: 2.9.2 @@ -1863,7 +1865,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks@1.25.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/context-async-hooks@1.26.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -1872,10 +1874,10 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.22.0 - '@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/semantic-conventions': 1.27.0 '@opentelemetry/exporter-logs-otlp-http@0.49.1(@opentelemetry/api@1.9.0)': dependencies: @@ -1946,14 +1948,14 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.22.0(@opentelemetry/api@1.9.0) '@opentelemetry/otlp-exporter-base': 0.49.1(@opentelemetry/api@1.9.0) - protobufjs: 7.3.2 + protobufjs: 7.4.0 '@opentelemetry/otlp-proto-exporter-base@0.49.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.22.0(@opentelemetry/api@1.9.0) '@opentelemetry/otlp-exporter-base': 0.49.1(@opentelemetry/api@1.9.0) - protobufjs: 7.3.2 + protobufjs: 7.4.0 '@opentelemetry/otlp-transformer@0.49.1(@opentelemetry/api@1.9.0)': dependencies: @@ -1970,20 +1972,20 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.22.0(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-b3@1.25.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/propagator-b3@1.26.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.26.0(@opentelemetry/api@1.9.0) '@opentelemetry/propagator-jaeger@1.22.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 1.22.0(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-jaeger@1.25.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/propagator-jaeger@1.26.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.26.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources@1.22.0(@opentelemetry/api@1.9.0)': dependencies: @@ -1991,11 +1993,11 @@ snapshots: '@opentelemetry/core': 1.22.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.22.0 - '@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/resources@1.26.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/core': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.27.0 '@opentelemetry/sdk-logs@0.49.1(@opentelemetry/api-logs@0.48.0)(@opentelemetry/api@1.9.0)': dependencies: @@ -2044,12 +2046,12 @@ snapshots: '@opentelemetry/resources': 1.22.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.22.0 - '@opentelemetry/sdk-trace-base@1.25.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/core': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.27.0 '@opentelemetry/sdk-trace-node@1.22.0(@opentelemetry/api@1.9.0)': dependencies: @@ -2061,19 +2063,19 @@ snapshots: '@opentelemetry/sdk-trace-base': 1.22.0(@opentelemetry/api@1.9.0) semver: 7.6.3 - '@opentelemetry/sdk-trace-node@1.25.1(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace-node@1.26.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-b3': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/propagator-jaeger': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/context-async-hooks': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/core': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-b3': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/propagator-jaeger': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 1.26.0(@opentelemetry/api@1.9.0) semver: 7.6.3 '@opentelemetry/semantic-conventions@1.22.0': {} - '@opentelemetry/semantic-conventions@1.25.1': {} + '@opentelemetry/semantic-conventions@1.27.0': {} '@pkgr/core@0.1.1': {} @@ -2102,10 +2104,10 @@ snapshots: '@socket.io/component-emitter@3.1.2': {} - '@tegonhq/sdk@0.1.0-beta.15(typescript@5.5.4)': + '@tegonhq/sdk@0.1.3(typescript@5.5.4)': dependencies: '@trigger.dev/sdk': 3.0.0-beta.50(typescript@5.5.4) - axios: 1.7.4(debug@4.3.6) + axios: 1.7.5(debug@4.3.6) chalk: 5.3.0 configstore: 7.0.0 cronstrue: 2.50.0 @@ -2117,6 +2119,7 @@ snapshots: zod: 3.22.3 transitivePeerDependencies: - bufferutil + - graphql - supports-color - typescript - utf-8-validate @@ -2137,16 +2140,16 @@ snapshots: '@opentelemetry/exporter-logs-otlp-http': 0.49.1(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-trace-otlp-http': 0.49.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.49.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.26.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-logs': 0.49.1(@opentelemetry/api-logs@0.48.0)(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.49.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-node': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/sdk-trace-base': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.27.0 humanize-duration: 3.32.1 socket.io-client: 4.7.5 superjson: 2.2.1 - ulidx: 2.4.0 + ulidx: 2.4.1 zod: 3.22.3 zod-error: 1.5.0 zod-validation-error: 1.5.0(zod@3.22.3) @@ -2163,16 +2166,16 @@ snapshots: '@opentelemetry/exporter-logs-otlp-http': 0.49.1(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-trace-otlp-http': 0.49.1(@opentelemetry/api@1.9.0) '@opentelemetry/instrumentation': 0.49.1(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 1.26.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-logs': 0.49.1(@opentelemetry/api-logs@0.48.0)(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-node': 0.49.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-node': 1.25.1(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/sdk-trace-base': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-node': 1.26.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.27.0 humanize-duration: 3.32.1 socket.io-client: 4.7.5 superjson: 2.2.1 - ulidx: 2.4.0 + ulidx: 2.4.1 zod: 3.22.3 zod-error: 1.5.0 zod-validation-error: 1.5.0(zod@3.22.3) @@ -2185,7 +2188,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/api-logs': 0.48.0 - '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/semantic-conventions': 1.27.0 '@trigger.dev/core': 3.0.0-beta.50 '@trigger.dev/core-backend': 3.0.0-beta.50 chalk: 5.3.0 @@ -2195,7 +2198,7 @@ snapshots: get-caller-file: 2.0.5 git-remote-origin-url: 4.0.0 git-repo-info: 2.1.1 - msw: 2.3.5(typescript@5.5.4) + msw: 2.4.0(typescript@5.5.4) slug: 6.1.0 terminal-link: 3.0.0 ulid: 2.3.0 @@ -2204,6 +2207,7 @@ snapshots: zod: 3.22.3 transitivePeerDependencies: - bufferutil + - graphql - supports-color - typescript - utf-8-validate @@ -2212,7 +2216,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/api-logs': 0.48.0 - '@opentelemetry/semantic-conventions': 1.25.1 + '@opentelemetry/semantic-conventions': 1.27.0 '@trigger.dev/core': 3.0.0-beta.55 '@trigger.dev/core-backend': 3.0.0-beta.55 chalk: 5.3.0 @@ -2222,7 +2226,7 @@ snapshots: get-caller-file: 2.0.5 git-remote-origin-url: 4.0.0 git-repo-info: 2.1.1 - msw: 2.3.5(typescript@5.5.4) + msw: 2.4.0(typescript@5.5.4) slug: 6.1.0 terminal-link: 3.0.0 ulid: 2.3.0 @@ -2231,6 +2235,7 @@ snapshots: zod: 3.22.3 transitivePeerDependencies: - bufferutil + - graphql - supports-color - typescript - utf-8-validate @@ -2241,15 +2246,15 @@ snapshots: '@types/jsonwebtoken@9.0.6': dependencies: - '@types/node': 22.3.0 + '@types/node': 22.5.1 '@types/mute-stream@0.0.4': dependencies: - '@types/node': 22.3.0 + '@types/node': 22.5.1 - '@types/node@22.3.0': + '@types/node@22.5.1': dependencies: - undici-types: 6.18.2 + undici-types: 6.19.8 '@types/shimmer@1.2.0': {} @@ -2436,7 +2441,7 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 - axios@1.7.4(debug@4.3.6): + axios@1.7.5(debug@4.3.6): dependencies: follow-redirects: 1.15.6(debug@4.3.6) form-data: 4.0.0 @@ -2478,7 +2483,7 @@ snapshots: chalk@5.3.0: {} - cjs-module-lexer@1.3.1: {} + cjs-module-lexer@1.4.0: {} cli-spinners@2.9.2: {} @@ -2579,7 +2584,7 @@ snapshots: dot-prop@9.0.0: dependencies: - type-fest: 4.24.0 + type-fest: 4.26.0 ecdsa-sig-formatter@1.0.11: dependencies: @@ -2687,12 +2692,12 @@ snapshots: eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.15.0 + is-core-module: 2.15.1 resolve: 1.22.8 transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + eslint-module-utils@2.8.2(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -2712,9 +2717,9 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.8.2(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) hasown: 2.0.2 - is-core-module: 2.15.0 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 @@ -2833,7 +2838,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.7 + micromatch: 4.0.8 fast-json-stable-stringify@2.1.0: {} @@ -2960,8 +2965,6 @@ snapshots: graphemer@1.4.0: {} - graphql@16.9.0: {} - has-bigints@1.0.2: {} has-flag@4.0.0: {} @@ -2997,7 +3000,7 @@ snapshots: dependencies: acorn: 8.12.1 acorn-import-assertions: 1.9.0(acorn@8.12.1) - cjs-module-lexer: 1.3.1 + cjs-module-lexer: 1.4.0 module-details-from-path: 1.0.3 imurmurhash@0.1.4: {} @@ -3033,7 +3036,7 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.15.0: + is-core-module@2.15.1: dependencies: hasown: 2.0.2 @@ -3171,7 +3174,7 @@ snapshots: merge2@1.4.1: {} - micromatch@4.0.7: + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 @@ -3200,7 +3203,7 @@ snapshots: ms@2.1.3: {} - msw@2.3.5(typescript@5.5.4): + msw@2.4.0(typescript@5.5.4): dependencies: '@bundled-es-modules/cookie': 2.0.0 '@bundled-es-modules/statuses': 1.0.1 @@ -3211,13 +3214,12 @@ snapshots: '@types/cookie': 0.6.0 '@types/statuses': 2.0.5 chalk: 4.1.2 - graphql: 16.9.0 headers-polyfill: 4.0.3 is-node-process: 1.2.0 outvariant: 1.4.3 path-to-regexp: 6.2.2 strict-event-emitter: 0.5.1 - type-fest: 4.24.0 + type-fest: 4.26.0 yargs: 17.7.2 optionalDependencies: typescript: 5.5.4 @@ -3307,7 +3309,7 @@ snapshots: prettier@3.3.3: {} - protobufjs@7.3.2: + protobufjs@7.4.0: dependencies: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 @@ -3319,7 +3321,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 22.3.0 + '@types/node': 22.5.1 long: 5.2.3 proxy-from-env@1.1.0: {} @@ -3355,7 +3357,7 @@ snapshots: resolve@1.22.8: dependencies: - is-core-module: 2.15.0 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -3504,7 +3506,7 @@ snapshots: synckit@0.9.1: dependencies: '@pkgr/core': 0.1.1 - tslib: 2.6.3 + tslib: 2.7.0 terminal-link@3.0.0: dependencies: @@ -3537,7 +3539,7 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tslib@2.6.3: {} + tslib@2.7.0: {} type-check@0.4.0: dependencies: @@ -3549,7 +3551,7 @@ snapshots: type-fest@1.4.0: {} - type-fest@4.24.0: {} + type-fest@4.26.0: {} typed-array-buffer@1.0.2: dependencies: @@ -3587,7 +3589,7 @@ snapshots: ulid@2.3.0: {} - ulidx@2.4.0: + ulidx@2.4.1: dependencies: layerr: 3.0.0 @@ -3598,7 +3600,7 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - undici-types@6.18.2: {} + undici-types@6.19.8: {} universalify@0.2.0: {} diff --git a/actions/slack-common-workflows/triggers/comment-sync.ts b/actions/slack-common-workflows/triggers/comment-sync.ts index 66d3098c..27c1fa06 100644 --- a/actions/slack-common-workflows/triggers/comment-sync.ts +++ b/actions/slack-common-workflows/triggers/comment-sync.ts @@ -15,8 +15,8 @@ export const commentSync = async (actionPayload: ActionEventPayload) => { modelId: issueCommentId, } = actionPayload; - const integrationDefinitionName = - integrationAccount.integrationDefinition.name; + const integrationDefinitionSlug = + integrationAccount.integrationDefinition.slug; const issueComment = await getIssueComment({ issueCommentId }); @@ -77,7 +77,7 @@ export const commentSync = async (actionPayload: ActionEventPayload) => { parentTs: message.thread_ts, channelId: messageData.channel, channelType: messageData.channel_type, - type: integrationDefinitionName, + type: integrationDefinitionSlug, userDisplayName: message.username ? message.username : message.user, }; @@ -89,4 +89,6 @@ export const commentSync = async (actionPayload: ActionEventPayload) => { sourceData, }); } + + return null; }; diff --git a/actions/slack-common-workflows/triggers/thread.ts b/actions/slack-common-workflows/triggers/thread.ts index 80e19f43..204dd830 100644 --- a/actions/slack-common-workflows/triggers/thread.ts +++ b/actions/slack-common-workflows/triggers/thread.ts @@ -7,11 +7,13 @@ import { updateIssueComment, getLinkedComment, getLinkedIssueBySource, + uploadAttachment, } from '@tegonhq/sdk'; import { convertSlackMessageToTiptapJson, getExternalSlackUser, + getFilesBuffer, } from '../utils'; export const slackThread = async ( @@ -77,19 +79,32 @@ export const slackThread = async ( parentTs: message.thread_ts, channelId: event.channel, channelType: event.channel_type, - type: integrationAccount.integrationDefinition.name, + type: integrationAccount.integrationDefinition.slug, id: integrationAccount.id, userDisplayName: message.username ? message.username : displayName, }; - const attachmentUrls: AttachmentResponse[] = []; + let attachmentUrls: AttachmentResponse[] = []; + if (message.files) { + // Get the files buffer from Slack using the integration account and message files + const filesFormData = await getFilesBuffer( + integrationAccount, + message.files, + ); + + // Upload the files to GCP and get the attachment URLs + attachmentUrls = await uploadAttachment( + integrationAccount.workspaceId, + filesFormData, + ); + } const tiptapMessage = convertSlackMessageToTiptapJson( message.blocks, attachmentUrls, ); - let linkedComment = await getLinkedComment({ sourceId: threadId }); + const linkedComment = await getLinkedComment({ sourceId: threadId }); if (linkedComment) { // If a linked comment exists, update the existing comment logger.debug(`Updating existing comment for thread ID: ${threadId}`); @@ -100,7 +115,7 @@ export const slackThread = async ( }); } - linkedComment = { + const linkedCommentMetadata = { url: threadId, sourceId: threadId, sourceData: sourceMetadata, @@ -111,6 +126,6 @@ export const slackThread = async ( body: tiptapMessage, parentId, sourceMetadata, - linkCommentMetadata: linkedComment, + linkCommentMetadata: linkedCommentMetadata, }); }; diff --git a/actions/slack-common-workflows/triggers/triage.ts b/actions/slack-common-workflows/triggers/triage.ts index e096ff6f..01e9babd 100644 --- a/actions/slack-common-workflows/triggers/triage.ts +++ b/actions/slack-common-workflows/triggers/triage.ts @@ -8,6 +8,7 @@ import { logger, getLinkedIssueBySource, getWorkflowsByTeam, + uploadAttachment, } from '@tegonhq/sdk'; import { slackIssueCreate } from './issue-create'; @@ -19,6 +20,7 @@ import { import { convertSlackMessageToTiptapJson, getExternalSlackUser, + getFilesBuffer, getSlackMessage, getStateId, sendEphemeralMessage, @@ -87,10 +89,11 @@ export const slackTriage = async ( // Check if the thread is already linked to an existing issue const [linkedIssue, workflowStates] = await Promise.all([ getLinkedIssueBySource({ sourceId }), + // (await axios.get(`/api/v1/linked_issues/source?sourceId=${sourceId}`)).data, getWorkflowsByTeam({ teamId }), ]); - // If the thread is already linked to an issue, send an ephemeral message and return + // // If the thread is already linked to an issue, send an ephemeral message and return if (linkedIssue) { await sendEphemeralMessage( integrationAccount, @@ -128,14 +131,28 @@ export const slackTriage = async ( // Create source metadata object const sourceMetadata = { id: integrationAccount.id, - type: integrationAccount.integrationDefinition.name, + type: integrationAccount.integrationDefinition.slug, subType: 'Thread', channelId: sessionData.channelId, userDisplayName: slackUsername, }; - const attachmentUrls: AttachmentResponse[] = []; + let attachmentUrls: AttachmentResponse[] = []; // add Attachments + if (slackMessageResponse.messages[0].files) { + // Get the files buffer from Slack using the integration account and message files + const filesFormData = await getFilesBuffer( + integrationAccount, + slackMessageResponse.messages[0].files, + ); + filesFormData.append('sourceMetadata', JSON.stringify(sourceMetadata)); + + // Upload the files to GCP and get the attachment URLs + attachmentUrls = await uploadAttachment( + integrationAccount.workspaceId, + filesFormData, + ); + } // Convert the Slack message blocks to Tiptap JSON format, including the attachment URLs const description = convertSlackMessageToTiptapJson( @@ -147,10 +164,12 @@ export const slackTriage = async ( url: `https://${sessionData.slackTeamDomain}.slack.com/archives/${sessionData.channelId}/p${mainTs.replace('.', '')}`, sourceId, sourceData: { - type: integrationAccount.integrationDefinition.name, + type: integrationAccount.integrationDefinition.slug, channelId: sessionData.channelId, parentTs: mainTs, + title: `Slack message from: ${slackUsername}`, slackTeamDomain: sessionData.slackTeamDomain, + userDisplayName: slackUsername, }, createdById: userId, }; diff --git a/actions/slack-common-workflows/utils.ts b/actions/slack-common-workflows/utils.ts index 53ebfea0..0ed8ac2c 100644 --- a/actions/slack-common-workflows/utils.ts +++ b/actions/slack-common-workflows/utils.ts @@ -14,6 +14,8 @@ import { } from '@tegonhq/sdk'; import axios from 'axios'; +import fs from 'fs'; +import FormData from 'form-data'; import { SlackBlock, SlackElement, SlashCommandSessionRecord } from './types'; @@ -201,6 +203,49 @@ export async function getSlackTeamInfo(slackTeamId: string, apiKey: string) { return response.data; } +/** + * Retrieves the files buffer from Slack. + * @param integrationAccount The integration account with relations. + * @param files The array of files from the Slack event body. + * @returns Formdata with files. + */ +export async function getFilesBuffer( + integrationAccount: IntegrationAccount, + files: EventBody[], +) { + const formData = new FormData(); + + // Retrieve the files buffer for each file + await Promise.all( + files.map(async (file) => { + const response = await axios.get(file.url_private, { + ...getSlackHeaders(integrationAccount), + responseType: 'stream', + }); + + const tempFilePath = `/tmp/${file.name}`; + const writeStream = fs.createWriteStream(tempFilePath); + + await new Promise((resolve, reject) => { + response.data.pipe(writeStream); + writeStream.on('finish', resolve); + writeStream.on('error', reject); + }); + + formData.append('files', fs.createReadStream(tempFilePath)); + + return tempFilePath; + }), + ); + + // Clean up the temporary files after the request is complete + // tempFilePaths.forEach((filePath) => { + // fs.unlinkSync(filePath); + // }); + + return formData; +} + /// ******************* Tip tap utils *******************////// export function convertSlackMessageToTiptapJson( diff --git a/apps/server/package.json b/apps/server/package.json index aec041f3..afccfa4f 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -34,7 +34,6 @@ "prisma:studio": "prisma studio", "generate": "prisma generate", "db:init-resources": "pnpm run migrate:dev && pnpm run generate", - "create-resources": "node scripts/createUserWorkspaceTeam", "deploy-trigger-tasks": "npx trigger.dev@beta deploy --self-hosted", "trigger-dev": "npx trigger.dev@beta dev -a http://localhost:3030" }, @@ -99,6 +98,7 @@ "openai": "^4.28.4", "passport": "0.7.0", "passport-jwt": "4.0.1", + "passwordless": "link:supertokens-node/recipe/passwordless", "pg": "^8.12.0", "pg-logical-replication": "^2.0.3", "prisma": "5.17.0", diff --git a/apps/server/prisma/migrations/000000000000_squashed_migrations/migration.sql b/apps/server/prisma/migrations/000000000000_squashed_migrations/migration.sql new file mode 100644 index 00000000..8a8f24b0 --- /dev/null +++ b/apps/server/prisma/migrations/000000000000_squashed_migrations/migration.sql @@ -0,0 +1,707 @@ +-- CreateEnum +CREATE TYPE "Preference" AS ENUM ('ISSUE_ESTIMATES', 'PRIORITIES'); + +-- CreateEnum +CREATE TYPE "Role" AS ENUM ('ADMIN', 'USER', 'BOT', 'AGENT'); + +-- CreateEnum +CREATE TYPE "Status" AS ENUM ('INVITED', 'ACTIVE', 'SUSPENDED'); + +-- CreateEnum +CREATE TYPE "ActionStatus" AS ENUM ('DEPLOYING', 'ERRORED', 'INSTALLED', 'NEEDS_CONFIGURATION', 'ACTIVE', 'SUSPENDED'); + +-- CreateEnum +CREATE TYPE "ModelName" AS ENUM ('Action', 'ActionEntity', 'Attachment', 'AIRequest', 'Emoji', 'IntegrationAccount', 'IntegrationDefinition', 'IntegrationDefinitionV2', 'Invite', 'Issue', 'IssueComment', 'IssueHistory', 'IssueRelation', 'IssueSuggestion', 'Label', 'LinkedComment', 'LinkedIssue', 'Notification', 'Prompt', 'Reaction', 'SyncAction', 'Team', 'TeamPreference', 'Template', 'TriggerProject', 'User', 'UsersOnWorkspaces', 'View', 'Workflow', 'Workspace', 'WorkspaceTriggerProject'); + +-- CreateEnum +CREATE TYPE "ActionType" AS ENUM ('I', 'U', 'D'); + +-- CreateEnum +CREATE TYPE "WorkflowCategory" AS ENUM ('TRIAGE', 'BACKLOG', 'UNSTARTED', 'STARTED', 'COMPLETED', 'CANCELED'); + +-- CreateEnum +CREATE TYPE "TemplateCategory" AS ENUM ('ISSUE', 'PROJECT', 'DOCUMENT'); + +-- CreateEnum +CREATE TYPE "IssueRelationType" AS ENUM ('BLOCKS', 'BLOCKED', 'RELATED', 'DUPLICATE', 'DUPLICATE_OF', 'SIMILAR'); + +-- CreateEnum +CREATE TYPE "NotificationActionType" AS ENUM ('IssueAssigned', 'IssueUnAssigned', 'IssueStatusChanged', 'IssuePriorityChanged', 'IssueNewComment', 'IssueBlocks'); + +-- CreateEnum +CREATE TYPE "AttachmentStatus" AS ENUM ('Pending', 'Failed', 'Uploaded', 'Deleted', 'External'); + +-- CreateEnum +CREATE TYPE "InviteStatus" AS ENUM ('INVITED', 'ACCEPTED', 'DECLINED'); + +-- CreateEnum +CREATE TYPE "LLMModels" AS ENUM ('GPT35TURBO', 'GPT4TURBO', 'LLAMA3', 'CLAUDEOPUS', 'GPT4O'); + +-- CreateTable +CREATE TABLE "Action" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "integrations" TEXT[], + "status" "ActionStatus" NOT NULL, + "version" TEXT NOT NULL, + "triggerVersion" TEXT NOT NULL, + "config" JSONB NOT NULL, + "data" JSONB, + "cron" TEXT, + "workspaceId" TEXT, + "createdById" TEXT NOT NULL, + + CONSTRAINT "Action_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ActionEntity" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "type" TEXT NOT NULL, + "entity" TEXT NOT NULL, + "actionId" TEXT NOT NULL, + + CONSTRAINT "ActionEntity_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "ActionEvent" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "eventType" TEXT NOT NULL, + "modelName" TEXT NOT NULL, + "modelId" TEXT NOT NULL, + "eventData" JSONB, + "sequenceId" BIGINT NOT NULL, + "processed" BOOLEAN NOT NULL DEFAULT false, + "processedAt" TIMESTAMP(3), + "processedIds" TEXT[], + "workspaceId" TEXT NOT NULL, + + CONSTRAINT "ActionEvent_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Attachment" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "fileName" TEXT, + "originalName" TEXT NOT NULL, + "fileType" TEXT NOT NULL, + "fileExt" TEXT NOT NULL, + "size" INTEGER NOT NULL, + "url" TEXT, + "status" "AttachmentStatus" NOT NULL, + "sourceMetadata" JSONB, + "uploadedById" TEXT, + "workspaceId" TEXT, + + CONSTRAINT "Attachment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "AIRequest" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "modelName" TEXT NOT NULL, + "data" TEXT NOT NULL, + "response" TEXT, + "llmModel" TEXT NOT NULL, + "workspaceId" TEXT NOT NULL, + "successful" BOOLEAN NOT NULL DEFAULT false, + + CONSTRAINT "AIRequest_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Emoji" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + + CONSTRAINT "Emoji_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "IntegrationAccount" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "integrationConfiguration" JSONB NOT NULL, + "accountId" TEXT, + "settings" JSONB, + "isActive" BOOLEAN NOT NULL DEFAULT true, + "personal" BOOLEAN NOT NULL DEFAULT false, + "integratedById" TEXT NOT NULL, + "integrationDefinitionId" TEXT NOT NULL, + "workspaceId" TEXT NOT NULL, + + CONSTRAINT "IntegrationAccount_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "IntegrationDefinitionV2" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "description" TEXT NOT NULL, + "icon" TEXT NOT NULL, + "clientId" TEXT NOT NULL, + "clientSecret" TEXT NOT NULL, + "workspaceId" TEXT, + + CONSTRAINT "IntegrationDefinitionV2_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Invite" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "sentAt" TIMESTAMP(3) NOT NULL, + "expiresAt" TIMESTAMP(3) NOT NULL, + "emailId" TEXT NOT NULL, + "fullName" TEXT NOT NULL, + "workspaceId" TEXT NOT NULL, + "status" "InviteStatus" NOT NULL, + "teamIds" TEXT[], + "role" "Role" NOT NULL, + + CONSTRAINT "Invite_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Issue" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "title" TEXT NOT NULL, + "number" INTEGER NOT NULL, + "description" TEXT, + "priority" INTEGER, + "dueDate" TIMESTAMP(3), + "sortOrder" INTEGER, + "subIssueSortOrder" INTEGER, + "estimate" INTEGER, + "sourceMetadata" JSONB, + "isBidirectional" BOOLEAN, + "teamId" TEXT NOT NULL, + "createdById" TEXT, + "updatedById" TEXT, + "subscriberIds" TEXT[], + "assigneeId" TEXT, + "labelIds" TEXT[], + "stateId" TEXT NOT NULL, + "parentId" TEXT, + "attachments" TEXT[], + "issueSuggestionId" TEXT, + + CONSTRAINT "Issue_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "IssueComment" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "body" TEXT NOT NULL, + "sourceMetadata" JSONB, + "userId" TEXT, + "updatedById" TEXT, + "reactionsData" JSONB[], + "issueId" TEXT NOT NULL, + "parentId" TEXT, + "attachments" TEXT[], + + CONSTRAINT "IssueComment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "IssueHistory" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "userId" TEXT, + "issueId" TEXT NOT NULL, + "sourceMetaData" JSONB, + "addedLabelIds" TEXT[], + "removedLabelIds" TEXT[], + "fromPriority" INTEGER, + "toPriority" INTEGER, + "fromStateId" TEXT, + "toStateId" TEXT, + "fromEstimate" INTEGER, + "toEstimate" INTEGER, + "fromAssigneeId" TEXT, + "toAssigneeId" TEXT, + "fromParentId" TEXT, + "toParentId" TEXT, + "fromTeamId" TEXT, + "toTeamId" TEXT, + "relationChanges" JSONB, + + CONSTRAINT "IssueHistory_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "IssueRelation" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "issueId" TEXT NOT NULL, + "relatedIssueId" TEXT NOT NULL, + "type" "IssueRelationType" NOT NULL, + "metadata" JSONB, + "createdById" TEXT, + "deletedById" TEXT, + "deleted" TIMESTAMP(3), + + CONSTRAINT "IssueRelation_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "IssueSuggestion" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "issueId" TEXT NOT NULL, + "suggestedLabelIds" TEXT[], + "suggestedAssigneeId" TEXT, + "metadata" JSONB, + + CONSTRAINT "IssueSuggestion_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "PersonalAccessToken" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "jwt" TEXT NOT NULL, + "token" TEXT NOT NULL, + "userId" TEXT NOT NULL, + "type" TEXT NOT NULL DEFAULT 'user', + + CONSTRAINT "PersonalAccessToken_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Label" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "color" TEXT NOT NULL, + "description" TEXT, + "workspaceId" TEXT NOT NULL, + "teamId" TEXT, + "groupId" TEXT, + + CONSTRAINT "Label_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "LinkedComment" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "url" TEXT NOT NULL, + "sourceId" TEXT NOT NULL, + "sourceData" JSONB, + "createdById" TEXT, + "commentId" TEXT NOT NULL, + + CONSTRAINT "LinkedComment_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "LinkedIssue" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "url" TEXT NOT NULL, + "sourceId" TEXT, + "sourceData" JSONB, + "createdById" TEXT, + "updatedById" TEXT, + "issueId" TEXT NOT NULL, + + CONSTRAINT "LinkedIssue_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Notification" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "type" "NotificationActionType" NOT NULL, + "userId" TEXT NOT NULL, + "issueId" TEXT, + "actionData" JSONB, + "createdById" TEXT, + "sourceMetadata" JSONB, + "readAt" TIMESTAMP(3), + "snoozedUntil" TIMESTAMP(3), + "workspaceId" TEXT NOT NULL, + + CONSTRAINT "Notification_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Prompt" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "prompt" TEXT NOT NULL, + "model" "LLMModels" NOT NULL DEFAULT 'GPT35TURBO', + "workspaceId" TEXT NOT NULL, + + CONSTRAINT "Prompt_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Reaction" ( + "id" TEXT NOT NULL, + "reactedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "deleted" TIMESTAMP(3), + "userId" TEXT NOT NULL, + "commentId" TEXT NOT NULL, + "emojiId" TEXT NOT NULL, + + CONSTRAINT "Reaction_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "SyncAction" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "modelName" "ModelName" NOT NULL, + "modelId" TEXT NOT NULL, + "action" "ActionType" NOT NULL, + "sequenceId" BIGINT NOT NULL, + "workspaceId" TEXT NOT NULL, + + CONSTRAINT "SyncAction_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Team" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "identifier" TEXT NOT NULL, + "icon" TEXT, + "workspaceId" TEXT NOT NULL, + + CONSTRAINT "Team_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "TeamPreference" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "teamId" TEXT NOT NULL, + "preference" "Preference" NOT NULL, + "value" TEXT NOT NULL, + + CONSTRAINT "TeamPreference_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Template" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "category" "TemplateCategory" NOT NULL, + "templateData" JSONB NOT NULL, + "createdById" TEXT NOT NULL, + "workspaceId" TEXT NOT NULL, + "teamId" TEXT, + + CONSTRAINT "Template_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "User" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "email" TEXT NOT NULL, + "fullname" TEXT, + "username" TEXT NOT NULL, + "initialSetupComplete" BOOLEAN NOT NULL DEFAULT false, + "anonymousDataCollection" BOOLEAN NOT NULL DEFAULT false, + + CONSTRAINT "User_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "UsersOnWorkspaces" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "userId" TEXT NOT NULL, + "workspaceId" TEXT NOT NULL, + "teamIds" TEXT[], + "status" "Status" NOT NULL DEFAULT 'ACTIVE', + "externalAccountMappings" JSONB, + "role" "Role" NOT NULL DEFAULT 'ADMIN', + "joinedAt" TIMESTAMP(3), + + CONSTRAINT "UsersOnWorkspaces_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "View" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "workspaceId" TEXT NOT NULL, + "teamId" TEXT, + "name" TEXT NOT NULL, + "description" TEXT NOT NULL, + "filters" JSONB NOT NULL, + "isBookmarked" BOOLEAN NOT NULL DEFAULT false, + "createdById" TEXT NOT NULL, + + CONSTRAINT "View_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Workflow" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "position" INTEGER NOT NULL, + "color" TEXT NOT NULL, + "category" "WorkflowCategory" NOT NULL, + "teamId" TEXT NOT NULL, + + CONSTRAINT "Workflow_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "Workspace" ( + "id" TEXT NOT NULL, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "deleted" TIMESTAMP(3), + "name" TEXT NOT NULL, + "slug" TEXT NOT NULL, + "icon" TEXT, + "actionsEnabled" BOOLEAN NOT NULL DEFAULT false, + + CONSTRAINT "Workspace_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "ActionEntity_type_entity_actionId_key" ON "ActionEntity"("type", "entity", "actionId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Emoji_name_key" ON "Emoji"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "IntegrationAccount_accountId_integrationDefinitionId_worksp_key" ON "IntegrationAccount"("accountId", "integrationDefinitionId", "workspaceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "IntegrationDefinitionV2_name_key" ON "IntegrationDefinitionV2"("name"); + +-- CreateIndex +CREATE UNIQUE INDEX "Issue_issueSuggestionId_key" ON "Issue"("issueSuggestionId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Issue_teamId_number_key" ON "Issue"("teamId", "number"); + +-- CreateIndex +CREATE UNIQUE INDEX "IssueRelation_issueId_relatedIssueId_type_key" ON "IssueRelation"("issueId", "relatedIssueId", "type"); + +-- CreateIndex +CREATE UNIQUE INDEX "IssueSuggestion_issueId_key" ON "IssueSuggestion"("issueId"); + +-- CreateIndex +CREATE UNIQUE INDEX "PersonalAccessToken_name_userId_token_key" ON "PersonalAccessToken"("name", "userId", "token"); + +-- CreateIndex +CREATE UNIQUE INDEX "Label_name_workspaceId_key" ON "Label"("name", "workspaceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "LinkedComment_url_key" ON "LinkedComment"("url"); + +-- CreateIndex +CREATE UNIQUE INDEX "LinkedIssue_url_key" ON "LinkedIssue"("url"); + +-- CreateIndex +CREATE UNIQUE INDEX "Prompt_name_workspaceId_key" ON "Prompt"("name", "workspaceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Reaction_emojiId_commentId_userId_key" ON "Reaction"("emojiId", "commentId", "userId"); + +-- CreateIndex +CREATE UNIQUE INDEX "SyncAction_modelId_action_key" ON "SyncAction"("modelId", "action"); + +-- CreateIndex +CREATE UNIQUE INDEX "Team_name_identifier_workspaceId_key" ON "Team"("name", "identifier", "workspaceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "TeamPreference_teamId_preference_key" ON "TeamPreference"("teamId", "preference"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_id_key" ON "User"("id"); + +-- CreateIndex +CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); + +-- CreateIndex +CREATE UNIQUE INDEX "UsersOnWorkspaces_userId_workspaceId_key" ON "UsersOnWorkspaces"("userId", "workspaceId"); + +-- CreateIndex +CREATE UNIQUE INDEX "Workspace_slug_key" ON "Workspace"("slug"); + +-- AddForeignKey +ALTER TABLE "Action" ADD CONSTRAINT "Action_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ActionEntity" ADD CONSTRAINT "ActionEntity_actionId_fkey" FOREIGN KEY ("actionId") REFERENCES "Action"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "ActionEvent" ADD CONSTRAINT "ActionEvent_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_uploadedById_fkey" FOREIGN KEY ("uploadedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "AIRequest" ADD CONSTRAINT "AIRequest_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_integratedById_fkey" FOREIGN KEY ("integratedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_integrationDefinitionId_fkey" FOREIGN KEY ("integrationDefinitionId") REFERENCES "IntegrationDefinitionV2"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IntegrationDefinitionV2" ADD CONSTRAINT "IntegrationDefinitionV2_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Issue" ADD CONSTRAINT "Issue_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Issue" ADD CONSTRAINT "Issue_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "Issue"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Issue" ADD CONSTRAINT "Issue_issueSuggestionId_fkey" FOREIGN KEY ("issueSuggestionId") REFERENCES "IssueSuggestion"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IssueComment" ADD CONSTRAINT "IssueComment_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "Issue"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IssueComment" ADD CONSTRAINT "IssueComment_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "IssueComment"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IssueHistory" ADD CONSTRAINT "IssueHistory_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "Issue"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "IssueRelation" ADD CONSTRAINT "IssueRelation_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "Issue"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Label" ADD CONSTRAINT "Label_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Label" ADD CONSTRAINT "Label_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Label" ADD CONSTRAINT "Label_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Label"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "LinkedComment" ADD CONSTRAINT "LinkedComment_commentId_fkey" FOREIGN KEY ("commentId") REFERENCES "IssueComment"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "LinkedIssue" ADD CONSTRAINT "LinkedIssue_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "Issue"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Prompt" ADD CONSTRAINT "Prompt_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Reaction" ADD CONSTRAINT "Reaction_commentId_fkey" FOREIGN KEY ("commentId") REFERENCES "IssueComment"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Reaction" ADD CONSTRAINT "Reaction_emojiId_fkey" FOREIGN KEY ("emojiId") REFERENCES "Emoji"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "SyncAction" ADD CONSTRAINT "SyncAction_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Team" ADD CONSTRAINT "Team_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "TeamPreference" ADD CONSTRAINT "TeamPreference_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Template" ADD CONSTRAINT "Template_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Template" ADD CONSTRAINT "Template_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Template" ADD CONSTRAINT "Template_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UsersOnWorkspaces" ADD CONSTRAINT "UsersOnWorkspaces_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "UsersOnWorkspaces" ADD CONSTRAINT "UsersOnWorkspaces_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "View" ADD CONSTRAINT "View_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "View" ADD CONSTRAINT "View_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "Workflow" ADD CONSTRAINT "Workflow_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + diff --git a/apps/server/prisma/migrations/20240126085350_init/migration.sql b/apps/server/prisma/migrations/20240126085350_init/migration.sql deleted file mode 100644 index 1c4e1c21..00000000 --- a/apps/server/prisma/migrations/20240126085350_init/migration.sql +++ /dev/null @@ -1,36 +0,0 @@ --- CreateEnum -CREATE TYPE "Role" AS ENUM ('ADMIN', 'USER'); - --- CreateTable -CREATE TABLE "User" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "email" TEXT NOT NULL, - "password" TEXT NOT NULL, - "fullname" TEXT, - "username" TEXT NOT NULL, - "role" "Role" NOT NULL, - "workspaceId" TEXT, - - CONSTRAINT "User_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Workspace" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "name" TEXT NOT NULL, - - CONSTRAINT "Workspace_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); - --- CreateIndex -CREATE UNIQUE INDEX "Workspace_name_key" ON "Workspace"("name"); - --- AddForeignKey -ALTER TABLE "User" ADD CONSTRAINT "User_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240127084002_add_workspace_slug/migration.sql b/apps/server/prisma/migrations/20240127084002_add_workspace_slug/migration.sql deleted file mode 100644 index 289813b0..00000000 --- a/apps/server/prisma/migrations/20240127084002_add_workspace_slug/migration.sql +++ /dev/null @@ -1,15 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[slug]` on the table `Workspace` will be added. If there are existing duplicate values, this will fail. - - Added the required column `slug` to the `Workspace` table without a default value. This is not possible if the table is not empty. - -*/ --- DropIndex -DROP INDEX "Workspace_name_key"; - --- AlterTable -ALTER TABLE "Workspace" ADD COLUMN "slug" TEXT NOT NULL; - --- CreateIndex -CREATE UNIQUE INDEX "Workspace_slug_key" ON "Workspace"("slug"); diff --git a/apps/server/prisma/migrations/20240130100143_add_teams/migration.sql b/apps/server/prisma/migrations/20240130100143_add_teams/migration.sql deleted file mode 100644 index 56db104f..00000000 --- a/apps/server/prisma/migrations/20240130100143_add_teams/migration.sql +++ /dev/null @@ -1,46 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `password` on the `User` table. All the data in the column will be lost. - - You are about to drop the column `workspaceId` on the `User` table. All the data in the column will be lost. - -*/ --- DropForeignKey -ALTER TABLE "User" DROP CONSTRAINT "User_workspaceId_fkey"; - --- AlterTable -ALTER TABLE "User" DROP COLUMN "password", -DROP COLUMN "workspaceId", -ADD COLUMN "anonymousDataCollection" BOOLEAN NOT NULL DEFAULT false, -ADD COLUMN "initialSetupComplete" BOOLEAN NOT NULL DEFAULT false; - --- CreateTable -CREATE TABLE "UsersOnWorkspaces" ( - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "userId" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - - CONSTRAINT "UsersOnWorkspaces_pkey" PRIMARY KEY ("userId","workspaceId") -); - --- CreateTable -CREATE TABLE "Team" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "name" TEXT NOT NULL, - "identifier" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - - CONSTRAINT "Team_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "UsersOnWorkspaces" ADD CONSTRAINT "UsersOnWorkspaces_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "UsersOnWorkspaces" ADD CONSTRAINT "UsersOnWorkspaces_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Team" ADD CONSTRAINT "Team_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240201101018_user_index/migration.sql b/apps/server/prisma/migrations/20240201101018_user_index/migration.sql deleted file mode 100644 index bac316e6..00000000 --- a/apps/server/prisma/migrations/20240201101018_user_index/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[id]` on the table `User` will be added. If there are existing duplicate values, this will fail. - -*/ --- CreateIndex -CREATE UNIQUE INDEX "User_id_key" ON "User"("id"); diff --git a/apps/server/prisma/migrations/20240201144242_add_labels_templates/migration.sql b/apps/server/prisma/migrations/20240201144242_add_labels_templates/migration.sql deleted file mode 100644 index 6a29717d..00000000 --- a/apps/server/prisma/migrations/20240201144242_add_labels_templates/migration.sql +++ /dev/null @@ -1,73 +0,0 @@ -/* - Warnings: - - - Added the required column `userId` to the `Team` table without a default value. This is not possible if the table is not empty. - -*/ --- CreateEnum -CREATE TYPE "Status" AS ENUM ('ACTIVE', 'SUSPENDED'); - --- AlterTable -ALTER TABLE "Team" ADD COLUMN "deleted" TIMESTAMP(3), -ADD COLUMN "icon" TEXT, -ADD COLUMN "userId" TEXT NOT NULL; - --- AlterTable -ALTER TABLE "UsersOnWorkspaces" ADD COLUMN "status" "Status" NOT NULL DEFAULT 'ACTIVE'; - --- AlterTable -ALTER TABLE "Workspace" ADD COLUMN "deleted" TIMESTAMP(3), -ADD COLUMN "icon" TEXT; - --- CreateTable -CREATE TABLE "Label" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "deleted" TIMESTAMP(3), - "name" TEXT NOT NULL, - "color" TEXT NOT NULL, - "description" TEXT, - "workspaceId" TEXT NOT NULL, - "teamId" TEXT, - "groupId" TEXT, - - CONSTRAINT "Label_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Template" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "deleted" TIMESTAMP(3), - "name" TEXT NOT NULL, - "type" TEXT NOT NULL, - "templateData" JSONB NOT NULL, - "createdById" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - "teamId" TEXT, - - CONSTRAINT "Template_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "Team" ADD CONSTRAINT "Team_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Label" ADD CONSTRAINT "Label_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Label" ADD CONSTRAINT "Label_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Label" ADD CONSTRAINT "Label_groupId_fkey" FOREIGN KEY ("groupId") REFERENCES "Label"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Template" ADD CONSTRAINT "Template_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Template" ADD CONSTRAINT "Template_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Template" ADD CONSTRAINT "Template_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240204153230_add_team_preferences/migration.sql b/apps/server/prisma/migrations/20240204153230_add_team_preferences/migration.sql deleted file mode 100644 index 4e2322e8..00000000 --- a/apps/server/prisma/migrations/20240204153230_add_team_preferences/migration.sql +++ /dev/null @@ -1,24 +0,0 @@ --- CreateEnum -CREATE TYPE "Preference" AS ENUM ('ISSUE_ESTIMATES', 'PRIORITIES'); - --- CreateEnum -CREATE TYPE "IssueEstimateValues" AS ENUM ('EXPONENTIAL', 'FIBONACCI', 'LINEAR', 'T_SHIRT'); - --- CreateEnum -CREATE TYPE "Priorities" AS ENUM ('NO_PRIORITY_FIRST', 'NO_PRIORITY_LAST'); - --- CreateTable -CREATE TABLE "TeamPreference" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "deleted" TIMESTAMP(3), - "teamId" TEXT NOT NULL, - "preference" "Preference" NOT NULL, - "value" TEXT NOT NULL, - - CONSTRAINT "TeamPreference_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "TeamPreference" ADD CONSTRAINT "TeamPreference_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240207090743_add_workflows/migration.sql b/apps/server/prisma/migrations/20240207090743_add_workflows/migration.sql deleted file mode 100644 index 39db8b3a..00000000 --- a/apps/server/prisma/migrations/20240207090743_add_workflows/migration.sql +++ /dev/null @@ -1,17 +0,0 @@ --- CreateTable -CREATE TABLE "Workflow" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "deleted" TIMESTAMP(3), - "name" TEXT NOT NULL, - "position" INTEGER NOT NULL, - "color" TEXT NOT NULL, - "type" TEXT NOT NULL, - "teamId" TEXT NOT NULL, - - CONSTRAINT "Workflow_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "Workflow" ADD CONSTRAINT "Workflow_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240208195732_add_sync_actions/migration.sql b/apps/server/prisma/migrations/20240208195732_add_sync_actions/migration.sql deleted file mode 100644 index 15c08c2f..00000000 --- a/apps/server/prisma/migrations/20240208195732_add_sync_actions/migration.sql +++ /dev/null @@ -1,35 +0,0 @@ --- CreateEnum -CREATE TYPE "ActionType" AS ENUM ('I', 'U', 'D'); - --- AlterTable -ALTER TABLE "Label" ALTER COLUMN "updatedAt" DROP DEFAULT; - --- AlterTable -ALTER TABLE "TeamPreference" ALTER COLUMN "updatedAt" DROP DEFAULT; - --- AlterTable -ALTER TABLE "Template" ALTER COLUMN "updatedAt" DROP DEFAULT; - --- AlterTable -ALTER TABLE "Workflow" ALTER COLUMN "updatedAt" DROP DEFAULT; - --- CreateTable -CREATE TABLE "SyncAction" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "modelName" TEXT NOT NULL, - "modelId" TEXT NOT NULL, - "action" "ActionType" NOT NULL, - "sequenceId" INTEGER NOT NULL, - "workspaceId" TEXT NOT NULL, - - CONSTRAINT "SyncAction_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "SyncAction_modelId_action_key" ON "SyncAction"("modelId", "action"); - --- AddForeignKey -ALTER TABLE "SyncAction" ADD CONSTRAINT "SyncAction_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240210053142_unique_team_id_preference/migration.sql b/apps/server/prisma/migrations/20240210053142_unique_team_id_preference/migration.sql deleted file mode 100644 index 593e7595..00000000 --- a/apps/server/prisma/migrations/20240210053142_unique_team_id_preference/migration.sql +++ /dev/null @@ -1,14 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[teamId,preference]` on the table `TeamPreference` will be added. If there are existing duplicate values, this will fail. - -*/ --- DropEnum -DROP TYPE "IssueEstimateValues"; - --- DropEnum -DROP TYPE "Priorities"; - --- CreateIndex -CREATE UNIQUE INDEX "TeamPreference_teamId_preference_key" ON "TeamPreference"("teamId", "preference"); diff --git a/apps/server/prisma/migrations/20240211162048_add_issues/migration.sql b/apps/server/prisma/migrations/20240211162048_add_issues/migration.sql deleted file mode 100644 index 2856421c..00000000 --- a/apps/server/prisma/migrations/20240211162048_add_issues/migration.sql +++ /dev/null @@ -1,35 +0,0 @@ --- CreateTable -CREATE TABLE "Issue" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "title" TEXT NOT NULL, - "number" INTEGER NOT NULL, - "description" TEXT NOT NULL, - "priority" INTEGER, - "dueDate" TIMESTAMP(3), - "sortOrder" INTEGER NOT NULL, - "subIssueSortOrder" INTEGER, - "teamId" TEXT NOT NULL, - "createdById" TEXT NOT NULL, - "subscriberIds" TEXT[], - "assigneeIds" TEXT[], - "labelIds" TEXT[], - "stateId" TEXT NOT NULL, - "parentId" TEXT, - - CONSTRAINT "Issue_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "Issue_teamId_number_key" ON "Issue"("teamId", "number"); - --- AddForeignKey -ALTER TABLE "Issue" ADD CONSTRAINT "Issue_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Issue" ADD CONSTRAINT "Issue_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Issue" ADD CONSTRAINT "Issue_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "Issue"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240212114320_add_issue_comments/migration.sql b/apps/server/prisma/migrations/20240212114320_add_issue_comments/migration.sql deleted file mode 100644 index 1ed8450a..00000000 --- a/apps/server/prisma/migrations/20240212114320_add_issue_comments/migration.sql +++ /dev/null @@ -1,52 +0,0 @@ --- CreateTable -CREATE TABLE "IssueComment" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "body" TEXT NOT NULL, - "userId" TEXT NOT NULL, - "reactionsData" JSONB[], - "issueId" TEXT NOT NULL, - "parentId" TEXT, - - CONSTRAINT "IssueComment_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Reaction" ( - "id" TEXT NOT NULL, - "reactedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "deleted" TIMESTAMP(3), - "userId" TEXT NOT NULL, - "commentId" TEXT NOT NULL, - "emojiId" TEXT NOT NULL, - - CONSTRAINT "Reaction_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "Emoji" ( - "id" TEXT NOT NULL, - "name" TEXT NOT NULL, - - CONSTRAINT "Emoji_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "Reaction_emojiId_commentId_userId_key" ON "Reaction"("emojiId", "commentId", "userId"); - --- CreateIndex -CREATE UNIQUE INDEX "Emoji_name_key" ON "Emoji"("name"); - --- AddForeignKey -ALTER TABLE "IssueComment" ADD CONSTRAINT "IssueComment_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "Issue"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "IssueComment" ADD CONSTRAINT "IssueComment_parentId_fkey" FOREIGN KEY ("parentId") REFERENCES "IssueComment"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Reaction" ADD CONSTRAINT "Reaction_commentId_fkey" FOREIGN KEY ("commentId") REFERENCES "IssueComment"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Reaction" ADD CONSTRAINT "Reaction_emojiId_fkey" FOREIGN KEY ("emojiId") REFERENCES "Emoji"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240214122913_add_issue_history/migration.sql b/apps/server/prisma/migrations/20240214122913_add_issue_history/migration.sql deleted file mode 100644 index ecdb0a4a..00000000 --- a/apps/server/prisma/migrations/20240214122913_add_issue_history/migration.sql +++ /dev/null @@ -1,38 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `assigneeIds` on the `Issue` table. All the data in the column will be lost. - -*/ --- AlterTable -ALTER TABLE "Issue" DROP COLUMN "assigneeIds", -ADD COLUMN "assigneeId" TEXT, -ADD COLUMN "estimate" INTEGER; - --- CreateTable -CREATE TABLE "IssueHistory" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "userId" TEXT NOT NULL, - "issueId" TEXT NOT NULL, - "addedLabelIds" TEXT[], - "removedLabelIds" TEXT[], - "fromPriority" INTEGER, - "toPriority" INTEGER, - "fromStateId" TEXT, - "toStateId" TEXT, - "fromEstimate" INTEGER, - "toEstimate" INTEGER, - "fromAssigneeId" TEXT, - "toAssigneeId" TEXT, - "fromParentId" TEXT, - "toParentId" TEXT, - "relationChanges" JSONB[], - - CONSTRAINT "IssueHistory_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "IssueHistory" ADD CONSTRAINT "IssueHistory_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "Issue"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240216051220_change_user_team_relation/migration.sql b/apps/server/prisma/migrations/20240216051220_change_user_team_relation/migration.sql deleted file mode 100644 index 1730faea..00000000 --- a/apps/server/prisma/migrations/20240216051220_change_user_team_relation/migration.sql +++ /dev/null @@ -1,46 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `userId` on the `Team` table. All the data in the column will be lost. - - You are about to drop the column `type` on the `Template` table. All the data in the column will be lost. - - You are about to drop the column `type` on the `Workflow` table. All the data in the column will be lost. - - Added the required column `category` to the `Template` table without a default value. This is not possible if the table is not empty. - - Added the required column `category` to the `Workflow` table without a default value. This is not possible if the table is not empty. - -*/ --- CreateEnum -CREATE TYPE "WorkflowCategory" AS ENUM ('BACKLOG', 'UNSTARTED', 'STARTED', 'COMPLETED', 'CANCELED'); - --- CreateEnum -CREATE TYPE "TemplateCategory" AS ENUM ('ISSUE', 'PROJECT', 'DOCUMENT'); - --- DropForeignKey -ALTER TABLE "Team" DROP CONSTRAINT "Team_userId_fkey"; - --- AlterTable -ALTER TABLE "Team" DROP COLUMN "userId"; - --- AlterTable -ALTER TABLE "Template" DROP COLUMN "type", -ADD COLUMN "category" "TemplateCategory" NOT NULL; - --- AlterTable -ALTER TABLE "Workflow" DROP COLUMN "type", -ADD COLUMN "category" "WorkflowCategory" NOT NULL; - --- CreateTable -CREATE TABLE "UsersOnTeams" ( - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "userId" TEXT NOT NULL, - "teamId" TEXT NOT NULL, - "status" "Status" NOT NULL DEFAULT 'ACTIVE', - - CONSTRAINT "UsersOnTeams_pkey" PRIMARY KEY ("userId","teamId") -); - --- AddForeignKey -ALTER TABLE "UsersOnTeams" ADD CONSTRAINT "UsersOnTeams_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "UsersOnTeams" ADD CONSTRAINT "UsersOnTeams_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240303182456_add_team_ids_to_users_on_workspaces/migration.sql b/apps/server/prisma/migrations/20240303182456_add_team_ids_to_users_on_workspaces/migration.sql deleted file mode 100644 index 06e365cb..00000000 --- a/apps/server/prisma/migrations/20240303182456_add_team_ids_to_users_on_workspaces/migration.sql +++ /dev/null @@ -1,26 +0,0 @@ -/* - Warnings: - - - The primary key for the `UsersOnWorkspaces` table will be changed. If it partially fails, the table could be left without primary key constraint. - - You are about to drop the `UsersOnTeams` table. If the table is not empty, all the data it contains will be lost. - - A unique constraint covering the columns `[userId,workspaceId]` on the table `UsersOnWorkspaces` will be added. If there are existing duplicate values, this will fail. - - The required column `id` was added to the `UsersOnWorkspaces` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required. - -*/ --- DropForeignKey -ALTER TABLE "UsersOnTeams" DROP CONSTRAINT "UsersOnTeams_teamId_fkey"; - --- DropForeignKey -ALTER TABLE "UsersOnTeams" DROP CONSTRAINT "UsersOnTeams_userId_fkey"; - --- AlterTable -ALTER TABLE "UsersOnWorkspaces" DROP CONSTRAINT "UsersOnWorkspaces_pkey", -ADD COLUMN "id" TEXT NOT NULL, -ADD COLUMN "teamIds" TEXT[], -ADD CONSTRAINT "UsersOnWorkspaces_pkey" PRIMARY KEY ("id"); - --- DropTable -DROP TABLE "UsersOnTeams"; - --- CreateIndex -CREATE UNIQUE INDEX "UsersOnWorkspaces_userId_workspaceId_key" ON "UsersOnWorkspaces"("userId", "workspaceId"); diff --git a/apps/server/prisma/migrations/20240305073612_change_model_name_to_enum/migration.sql b/apps/server/prisma/migrations/20240305073612_change_model_name_to_enum/migration.sql deleted file mode 100644 index 118a3d8a..00000000 --- a/apps/server/prisma/migrations/20240305073612_change_model_name_to_enum/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ -/* - Warnings: - - - Changed the type of `modelName` on the `SyncAction` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. - -*/ --- CreateEnum -CREATE TYPE "ModelName" AS ENUM ('Workspace', 'Team', 'TeamPreference', 'Issue', 'Label', 'Workflow', 'Template', 'IssueComment', 'IssueHistory', 'UsersOnWorkspaces'); - --- AlterTable -ALTER TABLE "SyncAction" DROP COLUMN "modelName", -ADD COLUMN "modelName" "ModelName" NOT NULL; diff --git a/apps/server/prisma/migrations/20240305080627_add_team_unique_constraint/migration.sql b/apps/server/prisma/migrations/20240305080627_add_team_unique_constraint/migration.sql deleted file mode 100644 index bc674f58..00000000 --- a/apps/server/prisma/migrations/20240305080627_add_team_unique_constraint/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[name,identifier,workspaceId]` on the table `Team` will be added. If there are existing duplicate values, this will fail. - -*/ --- CreateIndex -CREATE UNIQUE INDEX "Team_name_identifier_workspaceId_key" ON "Team"("name", "identifier", "workspaceId"); diff --git a/apps/server/prisma/migrations/20240309161548_add_integration_definition_account/migration.sql b/apps/server/prisma/migrations/20240309161548_add_integration_definition_account/migration.sql deleted file mode 100644 index ae178b47..00000000 --- a/apps/server/prisma/migrations/20240309161548_add_integration_definition_account/migration.sql +++ /dev/null @@ -1,36 +0,0 @@ --- CreateTable -CREATE TABLE "IntegrationDefinition" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "name" TEXT NOT NULL, - "icon" TEXT NOT NULL, - "spec" JSONB NOT NULL, - "clientId" TEXT NOT NULL, - "clientSecret" TEXT NOT NULL, - "scopes" TEXT NOT NULL, - - CONSTRAINT "IntegrationDefinition_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "IntegrationAccount" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "integrationConfiguration" JSONB NOT NULL, - "installationId" TEXT, - "settings" JSONB, - "integrationDefinitionId" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - - CONSTRAINT "IntegrationAccount_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_integrationDefinitionId_fkey" FOREIGN KEY ("integrationDefinitionId") REFERENCES "IntegrationDefinition"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240313052737_change_sequence_id_type_sync_action/migration.sql b/apps/server/prisma/migrations/20240313052737_change_sequence_id_type_sync_action/migration.sql deleted file mode 100644 index 7d6fd3f6..00000000 --- a/apps/server/prisma/migrations/20240313052737_change_sequence_id_type_sync_action/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "SyncAction" ALTER COLUMN "sequenceId" SET DATA TYPE BIGINT; diff --git a/apps/server/prisma/migrations/20240318084938_changes_for_integration/migration.sql b/apps/server/prisma/migrations/20240318084938_changes_for_integration/migration.sql deleted file mode 100644 index da86653e..00000000 --- a/apps/server/prisma/migrations/20240318084938_changes_for_integration/migration.sql +++ /dev/null @@ -1,112 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `installationId` on the `IntegrationAccount` table. All the data in the column will be lost. - - A unique constraint covering the columns `[accountId,integrationDefinitionId,workspaceId]` on the table `IntegrationAccount` will be added. If there are existing duplicate values, this will fail. - - Added the required column `integratedById` to the `IntegrationAccount` table without a default value. This is not possible if the table is not empty. - - Added the required column `workspaceId` to the `IntegrationDefinition` table without a default value. This is not possible if the table is not empty. - - Changed the type of `name` on the `IntegrationDefinition` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. - -*/ --- CreateEnum -CREATE TYPE "IntegrationName" AS ENUM ('Github', 'GithubPersonal', 'Slack'); - --- AlterEnum --- This migration adds more than one value to an enum. --- With PostgreSQL versions 11 and earlier, this is not possible --- in a single migration. This can be worked around by creating --- multiple migrations, each migration adding only one value to --- the enum. - - -ALTER TYPE "ModelName" ADD VALUE 'IntegrationDefinition'; -ALTER TYPE "ModelName" ADD VALUE 'IntegrationAccount'; -ALTER TYPE "ModelName" ADD VALUE 'LinkedIssue'; - --- AlterEnum -ALTER TYPE "WorkflowCategory" ADD VALUE 'TRIAGE'; - --- DropForeignKey -ALTER TABLE "Issue" DROP CONSTRAINT "Issue_createdById_fkey"; - --- AlterTable -ALTER TABLE "IntegrationAccount" DROP COLUMN "installationId", -ADD COLUMN "accountId" TEXT, -ADD COLUMN "integratedById" TEXT NOT NULL; - --- AlterTable -ALTER TABLE "IntegrationDefinition" ADD COLUMN "workspaceId" TEXT NOT NULL, -DROP COLUMN "name", -ADD COLUMN "name" "IntegrationName" NOT NULL; - --- AlterTable -ALTER TABLE "Issue" ADD COLUMN "isBidirectional" BOOLEAN, -ADD COLUMN "sourceMetadata" JSONB, -ALTER COLUMN "description" DROP NOT NULL, -ALTER COLUMN "sortOrder" DROP NOT NULL, -ALTER COLUMN "createdById" DROP NOT NULL; - --- AlterTable -ALTER TABLE "IssueComment" ADD COLUMN "sourceMetadata" JSONB, -ALTER COLUMN "userId" DROP NOT NULL; - --- AlterTable -ALTER TABLE "IssueHistory" ADD COLUMN "sourceMetaData" JSONB, -ALTER COLUMN "userId" DROP NOT NULL; - --- AlterTable -ALTER TABLE "UsersOnWorkspaces" ADD COLUMN "externalAccountMappings" JSONB; - --- CreateTable -CREATE TABLE "LinkedIssue" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "url" TEXT NOT NULL, - "sourceId" TEXT NOT NULL, - "source" JSONB, - "sourceData" JSONB, - "issueId" TEXT NOT NULL, - - CONSTRAINT "LinkedIssue_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "LinkedComment" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "url" TEXT NOT NULL, - "sourceId" TEXT NOT NULL, - "source" JSONB, - "sourceData" JSONB, - "commentId" TEXT NOT NULL, - - CONSTRAINT "LinkedComment_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "LinkedIssue_url_key" ON "LinkedIssue"("url"); - --- CreateIndex -CREATE UNIQUE INDEX "LinkedComment_url_key" ON "LinkedComment"("url"); - --- CreateIndex -CREATE UNIQUE INDEX "IntegrationAccount_accountId_integrationDefinitionId_worksp_key" ON "IntegrationAccount"("accountId", "integrationDefinitionId", "workspaceId"); - --- AddForeignKey -ALTER TABLE "Issue" ADD CONSTRAINT "Issue_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LinkedIssue" ADD CONSTRAINT "LinkedIssue_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "Issue"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "LinkedComment" ADD CONSTRAINT "LinkedComment_commentId_fkey" FOREIGN KEY ("commentId") REFERENCES "IssueComment"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "IntegrationDefinition" ADD CONSTRAINT "IntegrationDefinition_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_integratedById_fkey" FOREIGN KEY ("integratedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240318201339_add_is_active_integration_account/migration.sql b/apps/server/prisma/migrations/20240318201339_add_is_active_integration_account/migration.sql deleted file mode 100644 index bfdd3913..00000000 --- a/apps/server/prisma/migrations/20240318201339_add_is_active_integration_account/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "IntegrationAccount" ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT true; diff --git a/apps/server/prisma/migrations/20240319054729_change_source_id_linked_issue/migration.sql b/apps/server/prisma/migrations/20240319054729_change_source_id_linked_issue/migration.sql deleted file mode 100644 index 54446f68..00000000 --- a/apps/server/prisma/migrations/20240319054729_change_source_id_linked_issue/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "LinkedIssue" ALTER COLUMN "sourceId" DROP NOT NULL; diff --git a/apps/server/prisma/migrations/20240319114411_add_created_by_id_linked_issue_comments/migration.sql b/apps/server/prisma/migrations/20240319114411_add_created_by_id_linked_issue_comments/migration.sql deleted file mode 100644 index bc4f4432..00000000 --- a/apps/server/prisma/migrations/20240319114411_add_created_by_id_linked_issue_comments/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- AlterTable -ALTER TABLE "LinkedComment" ADD COLUMN "createdById" TEXT; - --- AlterTable -ALTER TABLE "LinkedIssue" ADD COLUMN "createdById" TEXT; diff --git a/apps/server/prisma/migrations/20240322121156_add_issue_relation/migration.sql b/apps/server/prisma/migrations/20240322121156_add_issue_relation/migration.sql deleted file mode 100644 index 27b7b805..00000000 --- a/apps/server/prisma/migrations/20240322121156_add_issue_relation/migration.sql +++ /dev/null @@ -1,29 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `relationChanges` on the `IssueHistory` table. All the data in the column will be lost. - -*/ --- CreateEnum -CREATE TYPE "IssueRelationType" AS ENUM ('BLOCKS', 'BLOCKED', 'RELATED', 'DUPLICATE', 'DUPLICATE_OF'); - --- AlterTable -ALTER TABLE "IssueHistory" DROP COLUMN "relationChanges"; - --- CreateTable -CREATE TABLE "IssueRelation" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "issueId" TEXT NOT NULL, - "relatedIssueId" TEXT NOT NULL, - "type" "IssueRelationType" NOT NULL, - "createdById" TEXT NOT NULL, - "deletedById" TEXT, - "deletedAt" TIMESTAMP(3), - - CONSTRAINT "IssueRelation_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "IssueRelation_issueId_relatedIssueId_type_key" ON "IssueRelation"("issueId", "relatedIssueId", "type"); diff --git a/apps/server/prisma/migrations/20240322122926_add_issue_to_relation/migration.sql b/apps/server/prisma/migrations/20240322122926_add_issue_to_relation/migration.sql deleted file mode 100644 index 1d62c277..00000000 --- a/apps/server/prisma/migrations/20240322122926_add_issue_to_relation/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- AlterEnum -ALTER TYPE "ModelName" ADD VALUE 'IssueRelation'; - --- AddForeignKey -ALTER TABLE "IssueRelation" ADD CONSTRAINT "IssueRelation_issueId_fkey" FOREIGN KEY ("issueId") REFERENCES "Issue"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240322191409_add_relation_changes_issue_history/migration.sql b/apps/server/prisma/migrations/20240322191409_add_relation_changes_issue_history/migration.sql deleted file mode 100644 index 4822b548..00000000 --- a/apps/server/prisma/migrations/20240322191409_add_relation_changes_issue_history/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `deletedAt` on the `IssueRelation` table. All the data in the column will be lost. - -*/ --- AlterTable -ALTER TABLE "IssueHistory" ADD COLUMN "relationChanges" JSONB; - --- AlterTable -ALTER TABLE "IssueRelation" DROP COLUMN "deletedAt", -ADD COLUMN "deleted" TIMESTAMP(3); diff --git a/apps/server/prisma/migrations/20240327070814_add_notifications/migration.sql b/apps/server/prisma/migrations/20240327070814_add_notifications/migration.sql deleted file mode 100644 index b64e3f24..00000000 --- a/apps/server/prisma/migrations/20240327070814_add_notifications/migration.sql +++ /dev/null @@ -1,20 +0,0 @@ --- CreateEnum -CREATE TYPE "NotificationActionType" AS ENUM ('IssueAssigned', 'IssueUnAssigned', 'IssueStatusChanged', 'IssuePriorityChanged', 'IssueNewComment', 'IssueBlocks'); - --- CreateTable -CREATE TABLE "Notification" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "type" "NotificationActionType" NOT NULL, - "userId" TEXT NOT NULL, - "issueId" TEXT, - "actionData" JSONB, - "createdById" TEXT, - "sourceMetadata" JSONB, - "readAt" TIMESTAMP(3), - "snoozedUntil" TIMESTAMP(3), - - CONSTRAINT "Notification_pkey" PRIMARY KEY ("id") -); diff --git a/apps/server/prisma/migrations/20240327135153_add_workspace_id_to_notifications/migration.sql b/apps/server/prisma/migrations/20240327135153_add_workspace_id_to_notifications/migration.sql deleted file mode 100644 index ceda942e..00000000 --- a/apps/server/prisma/migrations/20240327135153_add_workspace_id_to_notifications/migration.sql +++ /dev/null @@ -1,11 +0,0 @@ -/* - Warnings: - - - Added the required column `workspaceId` to the `Notification` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterEnum -ALTER TYPE "ModelName" ADD VALUE 'Notification'; - --- AlterTable -ALTER TABLE "Notification" ADD COLUMN "workspaceId" TEXT NOT NULL; diff --git a/apps/server/prisma/migrations/20240410183326_add_slack_personal/migration.sql b/apps/server/prisma/migrations/20240410183326_add_slack_personal/migration.sql deleted file mode 100644 index 41dd95d2..00000000 --- a/apps/server/prisma/migrations/20240410183326_add_slack_personal/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterEnum -ALTER TYPE "IntegrationName" ADD VALUE 'SlackPersonal'; diff --git a/apps/server/prisma/migrations/20240415132031_add_unique_label_workspace/migration.sql b/apps/server/prisma/migrations/20240415132031_add_unique_label_workspace/migration.sql deleted file mode 100644 index 473b0efe..00000000 --- a/apps/server/prisma/migrations/20240415132031_add_unique_label_workspace/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[name,workspaceId]` on the table `Label` will be added. If there are existing duplicate values, this will fail. - -*/ --- CreateIndex -CREATE UNIQUE INDEX "Label_name_workspaceId_key" ON "Label"("name", "workspaceId"); diff --git a/apps/server/prisma/migrations/20240419081525_added_views/migration.sql b/apps/server/prisma/migrations/20240419081525_added_views/migration.sql deleted file mode 100644 index 701ca6b5..00000000 --- a/apps/server/prisma/migrations/20240419081525_added_views/migration.sql +++ /dev/null @@ -1,21 +0,0 @@ --- CreateTable -CREATE TABLE "View" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "workspaceId" TEXT NOT NULL, - "teamId" TEXT, - "name" TEXT NOT NULL, - "description" TEXT NOT NULL, - "filters" JSONB NOT NULL, - "isFavorite" BOOLEAN NOT NULL, - - CONSTRAINT "View_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "View" ADD CONSTRAINT "View_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "View" ADD CONSTRAINT "View_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "Team"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240419083926_add_view_model/migration.sql b/apps/server/prisma/migrations/20240419083926_add_view_model/migration.sql deleted file mode 100644 index 4bb71021..00000000 --- a/apps/server/prisma/migrations/20240419083926_add_view_model/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- AlterEnum -ALTER TYPE "ModelName" ADD VALUE 'View'; - --- AlterTable -ALTER TABLE "View" ALTER COLUMN "isFavorite" SET DEFAULT false; diff --git a/apps/server/prisma/migrations/20240422061159_add_attachments/migration.sql b/apps/server/prisma/migrations/20240422061159_add_attachments/migration.sql deleted file mode 100644 index 1aa290c7..00000000 --- a/apps/server/prisma/migrations/20240422061159_add_attachments/migration.sql +++ /dev/null @@ -1,33 +0,0 @@ --- CreateEnum -CREATE TYPE "AttachmentStatus" AS ENUM ('Pending', 'Failed', 'Uploaded', 'Deleted'); - --- AlterTable -ALTER TABLE "Issue" ADD COLUMN "attachments" TEXT[]; - --- AlterTable -ALTER TABLE "IssueComment" ADD COLUMN "attachments" TEXT[]; - --- CreateTable -CREATE TABLE "Attachment" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "fileName" TEXT, - "originalName" TEXT NOT NULL, - "fileType" TEXT NOT NULL, - "fileExt" TEXT NOT NULL, - "size" INTEGER NOT NULL, - "status" "AttachmentStatus" NOT NULL, - "sourceMetadata" JSONB, - "uploadedById" TEXT, - "workspaceId" TEXT, - - CONSTRAINT "Attachment_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_uploadedById_fkey" FOREIGN KEY ("uploadedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "Attachment" ADD CONSTRAINT "Attachment_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240422085954_add_created_in_views/migration.sql b/apps/server/prisma/migrations/20240422085954_add_created_in_views/migration.sql deleted file mode 100644 index 4d3f15d4..00000000 --- a/apps/server/prisma/migrations/20240422085954_add_created_in_views/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `createdById` to the `View` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "View" ADD COLUMN "createdById" TEXT NOT NULL; diff --git a/apps/server/prisma/migrations/20240424030955_add_sentry_to_integration/migration.sql b/apps/server/prisma/migrations/20240424030955_add_sentry_to_integration/migration.sql deleted file mode 100644 index 061aa546..00000000 --- a/apps/server/prisma/migrations/20240424030955_add_sentry_to_integration/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterEnum -ALTER TYPE "IntegrationName" ADD VALUE 'Sentry'; diff --git a/apps/server/prisma/migrations/20240425091940_change_favourite_to_bookmarked/migration.sql b/apps/server/prisma/migrations/20240425091940_change_favourite_to_bookmarked/migration.sql deleted file mode 100644 index 27066c33..00000000 --- a/apps/server/prisma/migrations/20240425091940_change_favourite_to_bookmarked/migration.sql +++ /dev/null @@ -1,9 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `isFavorite` on the `View` table. All the data in the column will be lost. - -*/ --- AlterTable -ALTER TABLE "View" DROP COLUMN "isFavorite", -ADD COLUMN "isBookmarked" BOOLEAN NOT NULL DEFAULT false; diff --git a/apps/server/prisma/migrations/20240508105240_add_team_id_to_issue_history/migration.sql b/apps/server/prisma/migrations/20240508105240_add_team_id_to_issue_history/migration.sql deleted file mode 100644 index 0d291df0..00000000 --- a/apps/server/prisma/migrations/20240508105240_add_team_id_to_issue_history/migration.sql +++ /dev/null @@ -1,3 +0,0 @@ --- AlterTable -ALTER TABLE "IssueHistory" ADD COLUMN "fromTeamId" TEXT, -ADD COLUMN "toTeamId" TEXT; diff --git a/apps/server/prisma/migrations/20240516133332_add_url_to_attachments/migration.sql b/apps/server/prisma/migrations/20240516133332_add_url_to_attachments/migration.sql deleted file mode 100644 index a269d90e..00000000 --- a/apps/server/prisma/migrations/20240516133332_add_url_to_attachments/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- AlterEnum -ALTER TYPE "AttachmentStatus" ADD VALUE 'External'; - --- AlterTable -ALTER TABLE "Attachment" ADD COLUMN "url" TEXT; diff --git a/apps/server/prisma/migrations/20240624091517_add_issue_suggestions/migration.sql b/apps/server/prisma/migrations/20240624091517_add_issue_suggestions/migration.sql deleted file mode 100644 index 7ac4d721..00000000 --- a/apps/server/prisma/migrations/20240624091517_add_issue_suggestions/migration.sql +++ /dev/null @@ -1,38 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[issueSuggestionId]` on the table `Issue` will be added. If there are existing duplicate values, this will fail. - -*/ --- AlterEnum -ALTER TYPE "IssueRelationType" ADD VALUE 'SIMILAR'; - --- AlterTable -ALTER TABLE "Issue" ADD COLUMN "issueSuggestionId" TEXT; - --- AlterTable -ALTER TABLE "IssueRelation" ADD COLUMN "metadata" JSONB, -ALTER COLUMN "createdById" DROP NOT NULL; - --- CreateTable -CREATE TABLE "IssueSuggestion" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "issueId" TEXT NOT NULL, - "suggestedLabelIds" TEXT[], - "suggestedAssigneeId" TEXT, - "metadata" JSONB, - - CONSTRAINT "IssueSuggestion_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "IssueSuggestion_issueId_key" ON "IssueSuggestion"("issueId"); - --- CreateIndex -CREATE UNIQUE INDEX "Issue_issueSuggestionId_key" ON "Issue"("issueSuggestionId"); - --- AddForeignKey -ALTER TABLE "Issue" ADD CONSTRAINT "Issue_issueSuggestionId_fkey" FOREIGN KEY ("issueSuggestionId") REFERENCES "IssueSuggestion"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240624121440_update_model_name_enum/migration.sql b/apps/server/prisma/migrations/20240624121440_update_model_name_enum/migration.sql deleted file mode 100644 index 6a06f2fe..00000000 --- a/apps/server/prisma/migrations/20240624121440_update_model_name_enum/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterEnum -ALTER TYPE "ModelName" ADD VALUE 'IssueSuggestion'; diff --git a/apps/server/prisma/migrations/20240625062016_update_integration_name_enum/migration.sql b/apps/server/prisma/migrations/20240625062016_update_integration_name_enum/migration.sql deleted file mode 100644 index 633eb85c..00000000 --- a/apps/server/prisma/migrations/20240625062016_update_integration_name_enum/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterEnum -ALTER TYPE "IntegrationName" ADD VALUE 'Gmail'; diff --git a/apps/server/prisma/migrations/20240703130052_add_invite_model/migration.sql b/apps/server/prisma/migrations/20240703130052_add_invite_model/migration.sql deleted file mode 100644 index 40ca0cc2..00000000 --- a/apps/server/prisma/migrations/20240703130052_add_invite_model/migration.sql +++ /dev/null @@ -1,36 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `role` on the `User` table. All the data in the column will be lost. - -*/ --- CreateEnum -CREATE TYPE "InviteStatus" AS ENUM ('INVITED', 'ACCEPTED', 'DECLINED'); - --- AlterEnum -ALTER TYPE "Status" ADD VALUE 'INVITED'; - --- AlterTable -ALTER TABLE "User" DROP COLUMN "role"; - --- AlterTable -ALTER TABLE "UsersOnWorkspaces" ADD COLUMN "joinedAt" TIMESTAMP(3), -ADD COLUMN "role" "Role" NOT NULL DEFAULT 'ADMIN'; - --- CreateTable -CREATE TABLE "Invite" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "sentAt" TIMESTAMP(3) NOT NULL, - "expiresAt" TIMESTAMP(3) NOT NULL, - "emailId" TEXT NOT NULL, - "fullName" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - "status" "InviteStatus" NOT NULL, - "teamIds" TEXT[], - "role" "Role" NOT NULL, - - CONSTRAINT "Invite_pkey" PRIMARY KEY ("id") -); diff --git a/apps/server/prisma/migrations/20240721161551_add_trigger_project_details/migration.sql b/apps/server/prisma/migrations/20240721161551_add_trigger_project_details/migration.sql deleted file mode 100644 index 53f10efe..00000000 --- a/apps/server/prisma/migrations/20240721161551_add_trigger_project_details/migration.sql +++ /dev/null @@ -1,26 +0,0 @@ --- CreateTable -CREATE TABLE "TriggerProject" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "projectId" TEXT NOT NULL, - "projectSecret" TEXT NOT NULL, - "slug" TEXT NOT NULL, - "workspaceId" TEXT, - - CONSTRAINT "TriggerProject_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "WorkspaceTriggerProject" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "triggerProjectId" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - "status" BOOLEAN NOT NULL, - - CONSTRAINT "WorkspaceTriggerProject_pkey" PRIMARY KEY ("id") -); diff --git a/apps/server/prisma/migrations/20240722100224_add_ai_requests/migration.sql b/apps/server/prisma/migrations/20240722100224_add_ai_requests/migration.sql deleted file mode 100644 index 94dba25d..00000000 --- a/apps/server/prisma/migrations/20240722100224_add_ai_requests/migration.sql +++ /dev/null @@ -1,18 +0,0 @@ --- CreateTable -CREATE TABLE "AIRequest" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "modelName" TEXT NOT NULL, - "data" TEXT NOT NULL, - "response" TEXT, - "llmModel" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - "successful" BOOLEAN NOT NULL DEFAULT false, - - CONSTRAINT "AIRequest_pkey" PRIMARY KEY ("id") -); - --- AddForeignKey -ALTER TABLE "AIRequest" ADD CONSTRAINT "AIRequest_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240727073415_add_prompt_model/migration.sql b/apps/server/prisma/migrations/20240727073415_add_prompt_model/migration.sql deleted file mode 100644 index 732eaf33..00000000 --- a/apps/server/prisma/migrations/20240727073415_add_prompt_model/migration.sql +++ /dev/null @@ -1,18 +0,0 @@ --- CreateTable -CREATE TABLE "Prompt" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "name" TEXT NOT NULL, - "prompt" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - - CONSTRAINT "Prompt_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "Prompt_name_workspaceId_key" ON "Prompt"("name", "workspaceId"); - --- AddForeignKey -ALTER TABLE "Prompt" ADD CONSTRAINT "Prompt_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240727083714_add_unique_integration_definition/migration.sql b/apps/server/prisma/migrations/20240727083714_add_unique_integration_definition/migration.sql deleted file mode 100644 index 89f5381f..00000000 --- a/apps/server/prisma/migrations/20240727083714_add_unique_integration_definition/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - A unique constraint covering the columns `[workspaceId,name]` on the table `IntegrationDefinition` will be added. If there are existing duplicate values, this will fail. - -*/ --- CreateIndex -CREATE UNIQUE INDEX "IntegrationDefinition_workspaceId_name_key" ON "IntegrationDefinition"("workspaceId", "name"); diff --git a/apps/server/prisma/migrations/20240727122133_add_model_to_prompt/migration.sql b/apps/server/prisma/migrations/20240727122133_add_model_to_prompt/migration.sql deleted file mode 100644 index fb10dc1b..00000000 --- a/apps/server/prisma/migrations/20240727122133_add_model_to_prompt/migration.sql +++ /dev/null @@ -1,5 +0,0 @@ --- CreateEnum -CREATE TYPE "LLMModels" AS ENUM ('GPT35TURBO', 'GPT4TURBO', 'LLAMA3', 'CLAUDEOPUS', 'GPT4O'); - --- AlterTable -ALTER TABLE "Prompt" ADD COLUMN "model" "LLMModels" NOT NULL DEFAULT 'GPT35TURBO'; diff --git a/apps/server/prisma/migrations/20240812172843_drop_integration_account_definition/migration.sql b/apps/server/prisma/migrations/20240812172843_drop_integration_account_definition/migration.sql deleted file mode 100644 index 32d4143b..00000000 --- a/apps/server/prisma/migrations/20240812172843_drop_integration_account_definition/migration.sql +++ /dev/null @@ -1,27 +0,0 @@ -/* - Warnings: - - - You are about to drop the `IntegrationAccount` table. If the table is not empty, all the data it contains will be lost. - - You are about to drop the `IntegrationDefinition` table. If the table is not empty, all the data it contains will be lost. - -*/ --- DropForeignKey -ALTER TABLE "IntegrationAccount" DROP CONSTRAINT "IntegrationAccount_integratedById_fkey"; - --- DropForeignKey -ALTER TABLE "IntegrationAccount" DROP CONSTRAINT "IntegrationAccount_integrationDefinitionId_fkey"; - --- DropForeignKey -ALTER TABLE "IntegrationAccount" DROP CONSTRAINT "IntegrationAccount_workspaceId_fkey"; - --- DropForeignKey -ALTER TABLE "IntegrationDefinition" DROP CONSTRAINT "IntegrationDefinition_workspaceId_fkey"; - --- DropTable -DROP TABLE "IntegrationAccount"; - --- DropTable -DROP TABLE "IntegrationDefinition"; - --- DropEnum -DROP TYPE "IntegrationName"; diff --git a/apps/server/prisma/migrations/20240812172909_add_new_integration_definition/migration.sql b/apps/server/prisma/migrations/20240812172909_add_new_integration_definition/migration.sql deleted file mode 100644 index 4654ef0b..00000000 --- a/apps/server/prisma/migrations/20240812172909_add_new_integration_definition/migration.sql +++ /dev/null @@ -1,50 +0,0 @@ --- CreateTable -CREATE TABLE "IntegrationDefinitionV2" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "name" TEXT NOT NULL, - "icon" TEXT NOT NULL, - "clientId" TEXT NOT NULL, - "clientSecret" TEXT NOT NULL, - "workspaceId" TEXT, - - CONSTRAINT "IntegrationDefinitionV2_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "IntegrationAccount" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "integrationConfiguration" JSONB NOT NULL, - "accountId" TEXT, - "settings" JSONB, - "isActive" BOOLEAN NOT NULL DEFAULT true, - "personal" BOOLEAN NOT NULL DEFAULT false, - "integratedById" TEXT NOT NULL, - "integrationDefinitionId" TEXT NOT NULL, - "workspaceId" TEXT NOT NULL, - - CONSTRAINT "IntegrationAccount_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "IntegrationDefinitionV2_name_key" ON "IntegrationDefinitionV2"("name"); - --- CreateIndex -CREATE UNIQUE INDEX "IntegrationAccount_accountId_integrationDefinitionId_worksp_key" ON "IntegrationAccount"("accountId", "integrationDefinitionId", "workspaceId"); - --- AddForeignKey -ALTER TABLE "IntegrationDefinitionV2" ADD CONSTRAINT "IntegrationDefinitionV2_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_integratedById_fkey" FOREIGN KEY ("integratedById") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_integrationDefinitionId_fkey" FOREIGN KEY ("integrationDefinitionId") REFERENCES "IntegrationDefinitionV2"("id") ON DELETE RESTRICT ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "IntegrationAccount" ADD CONSTRAINT "IntegrationAccount_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240814130010_add_actions/migration.sql b/apps/server/prisma/migrations/20240814130010_add_actions/migration.sql deleted file mode 100644 index 1fe42492..00000000 --- a/apps/server/prisma/migrations/20240814130010_add_actions/migration.sql +++ /dev/null @@ -1,34 +0,0 @@ --- CreateTable -CREATE TABLE "Action" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "name" TEXT NOT NULL, - "integrations" TEXT[], - "workspaceId" TEXT, - - CONSTRAINT "Action_pkey" PRIMARY KEY ("id") -); - --- CreateTable -CREATE TABLE "ActionEntity" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "type" TEXT NOT NULL, - "entity" TEXT NOT NULL, - "actionId" TEXT NOT NULL, - - CONSTRAINT "ActionEntity_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "ActionEntity_type_entity_actionId_key" ON "ActionEntity"("type", "entity", "actionId"); - --- AddForeignKey -ALTER TABLE "Action" ADD CONSTRAINT "Action_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE SET NULL ON UPDATE CASCADE; - --- AddForeignKey -ALTER TABLE "ActionEntity" ADD CONSTRAINT "ActionEntity_actionId_fkey" FOREIGN KEY ("actionId") REFERENCES "Action"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240815121852_update_model_names/migration.sql b/apps/server/prisma/migrations/20240815121852_update_model_names/migration.sql deleted file mode 100644 index fb463b1d..00000000 --- a/apps/server/prisma/migrations/20240815121852_update_model_names/migration.sql +++ /dev/null @@ -1,22 +0,0 @@ --- AlterEnum --- This migration adds more than one value to an enum. --- With PostgreSQL versions 11 and earlier, this is not possible --- in a single migration. This can be worked around by creating --- multiple migrations, each migration adding only one value to --- the enum. - - -ALTER TYPE "ModelName" ADD VALUE 'Action'; -ALTER TYPE "ModelName" ADD VALUE 'ActionEntity'; -ALTER TYPE "ModelName" ADD VALUE 'Attachment'; -ALTER TYPE "ModelName" ADD VALUE 'AIRequest'; -ALTER TYPE "ModelName" ADD VALUE 'Emoji'; -ALTER TYPE "ModelName" ADD VALUE 'IntegrationDefinitionV2'; -ALTER TYPE "ModelName" ADD VALUE 'Invite'; -ALTER TYPE "ModelName" ADD VALUE 'LinkedComment'; -ALTER TYPE "ModelName" ADD VALUE 'Prompt'; -ALTER TYPE "ModelName" ADD VALUE 'Reaction'; -ALTER TYPE "ModelName" ADD VALUE 'SyncAction'; -ALTER TYPE "ModelName" ADD VALUE 'TriggerProject'; -ALTER TYPE "ModelName" ADD VALUE 'User'; -ALTER TYPE "ModelName" ADD VALUE 'WorkspaceTriggerProject'; diff --git a/apps/server/prisma/migrations/20240817051326_add_new_table_for_events/migration.sql b/apps/server/prisma/migrations/20240817051326_add_new_table_for_events/migration.sql deleted file mode 100644 index 9c8e8879..00000000 --- a/apps/server/prisma/migrations/20240817051326_add_new_table_for_events/migration.sql +++ /dev/null @@ -1,63 +0,0 @@ -/* - Warnings: - - - You are about to drop the `WorkspaceTriggerProject` table. If the table is not empty, all the data it contains will be lost. - - Added the required column `createdById` to the `Action` table without a default value. This is not possible if the table is not empty. - - Added the required column `updatedById` to the `Issue` table without a default value. This is not possible if the table is not empty. - - Added the required column `updatedById` to the `IssueComment` table without a default value. This is not possible if the table is not empty. - - Added the required column `updatedById` to the `LinkedIssue` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterEnum --- This migration adds more than one value to an enum. --- With PostgreSQL versions 11 and earlier, this is not possible --- in a single migration. This can be worked around by creating --- multiple migrations, each migration adding only one value to --- the enum. - - -ALTER TYPE "Role" ADD VALUE 'BOT'; -ALTER TYPE "Role" ADD VALUE 'AGENT'; - --- DropForeignKey -ALTER TABLE "Issue" DROP CONSTRAINT "Issue_createdById_fkey"; - --- AlterTable -ALTER TABLE "Action" ADD COLUMN "createdById" TEXT NOT NULL; - --- AlterTable -ALTER TABLE "Issue" ADD COLUMN "updatedById" TEXT; - --- AlterTable -ALTER TABLE "IssueComment" ADD COLUMN "updatedById" TEXT; - --- AlterTable -ALTER TABLE "LinkedIssue" ADD COLUMN "updatedById" TEXT; - --- AlterTable -ALTER TABLE "TriggerProject" ADD COLUMN "status" BOOLEAN NOT NULL DEFAULT true; - --- DropTable -DROP TABLE "WorkspaceTriggerProject"; - --- CreateTable -CREATE TABLE "ActionEvent" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "eventType" TEXT NOT NULL, - "modelName" TEXT NOT NULL, - "modelId" TEXT NOT NULL, - "eventData" JSONB, - "sequenceId" BIGINT NOT NULL, - "workspaceId" TEXT NOT NULL, - - CONSTRAINT "ActionEvent_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "ActionEvent_modelId_eventType_key" ON "ActionEvent"("modelId", "eventType"); - --- AddForeignKey -ALTER TABLE "ActionEvent" ADD CONSTRAINT "ActionEvent_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/apps/server/prisma/migrations/20240817095022_remove_unique_action_event/migration.sql b/apps/server/prisma/migrations/20240817095022_remove_unique_action_event/migration.sql deleted file mode 100644 index 1b2bd085..00000000 --- a/apps/server/prisma/migrations/20240817095022_remove_unique_action_event/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- DropIndex -DROP INDEX "ActionEvent_modelId_eventType_key"; diff --git a/apps/server/prisma/migrations/20240817102502_added_processed_info/migration.sql b/apps/server/prisma/migrations/20240817102502_added_processed_info/migration.sql deleted file mode 100644 index 52c4a339..00000000 --- a/apps/server/prisma/migrations/20240817102502_added_processed_info/migration.sql +++ /dev/null @@ -1,4 +0,0 @@ --- AlterTable -ALTER TABLE "ActionEvent" ADD COLUMN "processed" BOOLEAN NOT NULL DEFAULT false, -ADD COLUMN "processedAt" TIMESTAMP(3), -ADD COLUMN "processedIds" TEXT[]; diff --git a/apps/server/prisma/migrations/20240817181719_remove_trigger_project/migration.sql b/apps/server/prisma/migrations/20240817181719_remove_trigger_project/migration.sql deleted file mode 100644 index f4d32b95..00000000 --- a/apps/server/prisma/migrations/20240817181719_remove_trigger_project/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - You are about to drop the `TriggerProject` table. If the table is not empty, all the data it contains will be lost. - -*/ --- DropTable -DROP TABLE "TriggerProject"; diff --git a/apps/server/prisma/migrations/20240819093956_create_pat_table/migration.sql b/apps/server/prisma/migrations/20240819093956_create_pat_table/migration.sql deleted file mode 100644 index 8b35fda5..00000000 --- a/apps/server/prisma/migrations/20240819093956_create_pat_table/migration.sql +++ /dev/null @@ -1,19 +0,0 @@ --- AlterTable -ALTER TABLE "Action" ADD COLUMN "cron" TEXT; - --- CreateTable -CREATE TABLE "PersonalAccessToken" ( - "id" TEXT NOT NULL, - "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, - "updatedAt" TIMESTAMP(3) NOT NULL, - "deleted" TIMESTAMP(3), - "name" TEXT NOT NULL, - "jwt" TEXT NOT NULL, - "token" TEXT NOT NULL, - "userId" TEXT NOT NULL, - - CONSTRAINT "PersonalAccessToken_pkey" PRIMARY KEY ("id") -); - --- CreateIndex -CREATE UNIQUE INDEX "PersonalAccessToken_name_userId_token_key" ON "PersonalAccessToken"("name", "userId", "token"); diff --git a/apps/server/prisma/migrations/20240820053302_remove_source_in_linked/migration.sql b/apps/server/prisma/migrations/20240820053302_remove_source_in_linked/migration.sql deleted file mode 100644 index 0bc6ed23..00000000 --- a/apps/server/prisma/migrations/20240820053302_remove_source_in_linked/migration.sql +++ /dev/null @@ -1,12 +0,0 @@ -/* - Warnings: - - - You are about to drop the column `source` on the `LinkedComment` table. All the data in the column will be lost. - - You are about to drop the column `source` on the `LinkedIssue` table. All the data in the column will be lost. - -*/ --- AlterTable -ALTER TABLE "LinkedComment" DROP COLUMN "source"; - --- AlterTable -ALTER TABLE "LinkedIssue" DROP COLUMN "source"; diff --git a/apps/server/prisma/migrations/20240821042237_add_description_integration_definition/migration.sql b/apps/server/prisma/migrations/20240821042237_add_description_integration_definition/migration.sql deleted file mode 100644 index ca6c319b..00000000 --- a/apps/server/prisma/migrations/20240821042237_add_description_integration_definition/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `description` to the `IntegrationDefinitionV2` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "IntegrationDefinitionV2" ADD COLUMN "description" TEXT NOT NULL; diff --git a/apps/server/prisma/migrations/20240821143116_add_data_to_action/migration.sql b/apps/server/prisma/migrations/20240821143116_add_data_to_action/migration.sql deleted file mode 100644 index e9bd8cfc..00000000 --- a/apps/server/prisma/migrations/20240821143116_add_data_to_action/migration.sql +++ /dev/null @@ -1,2 +0,0 @@ --- AlterTable -ALTER TABLE "Action" ADD COLUMN "data" JSONB; diff --git a/apps/server/prisma/migrations/20240821154728_add_config_to_action/migration.sql b/apps/server/prisma/migrations/20240821154728_add_config_to_action/migration.sql deleted file mode 100644 index 9fed00e3..00000000 --- a/apps/server/prisma/migrations/20240821154728_add_config_to_action/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `config` to the `Action` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "Action" ADD COLUMN "config" JSONB NOT NULL; diff --git a/apps/server/prisma/migrations/20240822030153_add_version_status_to_actions/migration.sql b/apps/server/prisma/migrations/20240822030153_add_version_status_to_actions/migration.sql deleted file mode 100644 index df776d7c..00000000 --- a/apps/server/prisma/migrations/20240822030153_add_version_status_to_actions/migration.sql +++ /dev/null @@ -1,13 +0,0 @@ -/* - Warnings: - - - Added the required column `status` to the `Action` table without a default value. This is not possible if the table is not empty. - - Added the required column `version` to the `Action` table without a default value. This is not possible if the table is not empty. - -*/ --- CreateEnum -CREATE TYPE "ActionStatus" AS ENUM ('INSTALLED', 'NEEDS_CONFIGURATION', 'ACTIVE', 'SUSPENDED'); - --- AlterTable -ALTER TABLE "Action" ADD COLUMN "status" "ActionStatus" NOT NULL, -ADD COLUMN "version" TEXT NOT NULL; diff --git a/apps/server/prisma/migrations/20240822060743_add_status_version_to_actions/migration.sql b/apps/server/prisma/migrations/20240822060743_add_status_version_to_actions/migration.sql deleted file mode 100644 index 68bcbe08..00000000 --- a/apps/server/prisma/migrations/20240822060743_add_status_version_to_actions/migration.sql +++ /dev/null @@ -1,10 +0,0 @@ --- AlterEnum --- This migration adds more than one value to an enum. --- With PostgreSQL versions 11 and earlier, this is not possible --- in a single migration. This can be worked around by creating --- multiple migrations, each migration adding only one value to --- the enum. - - -ALTER TYPE "ActionStatus" ADD VALUE 'DEPLOYING'; -ALTER TYPE "ActionStatus" ADD VALUE 'ERRORED'; diff --git a/apps/server/prisma/migrations/20240822101743_add_slug_to_action/migration.sql b/apps/server/prisma/migrations/20240822101743_add_slug_to_action/migration.sql deleted file mode 100644 index 11623c86..00000000 --- a/apps/server/prisma/migrations/20240822101743_add_slug_to_action/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `slug` to the `Action` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "Action" ADD COLUMN "slug" TEXT NOT NULL; diff --git a/apps/server/prisma/migrations/20240826085737_add_slug_to_workspace/migration.sql b/apps/server/prisma/migrations/20240826085737_add_slug_to_workspace/migration.sql deleted file mode 100644 index d4243b41..00000000 --- a/apps/server/prisma/migrations/20240826085737_add_slug_to_workspace/migration.sql +++ /dev/null @@ -1,8 +0,0 @@ -/* - Warnings: - - - Added the required column `slug` to the `IntegrationDefinitionV2` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "IntegrationDefinitionV2" ADD COLUMN "slug" TEXT NOT NULL; diff --git a/apps/server/prisma/migrations/20240826140918_add_version_to_action/migration.sql b/apps/server/prisma/migrations/20240826140918_add_version_to_action/migration.sql deleted file mode 100644 index 5375a1e6..00000000 --- a/apps/server/prisma/migrations/20240826140918_add_version_to_action/migration.sql +++ /dev/null @@ -1,11 +0,0 @@ -/* - Warnings: - - - Added the required column `triggerVersion` to the `Action` table without a default value. This is not possible if the table is not empty. - -*/ --- AlterTable -ALTER TABLE "Action" ADD COLUMN "triggerVersion" TEXT NOT NULL; - --- AlterTable -ALTER TABLE "PersonalAccessToken" ADD COLUMN "type" TEXT NOT NULL DEFAULT 'user'; diff --git a/apps/server/prisma/migrations/20240828195801_add_unique_email_workspace_for_invite/migration.sql b/apps/server/prisma/migrations/20240828195801_add_unique_email_workspace_for_invite/migration.sql new file mode 100644 index 00000000..4457285f --- /dev/null +++ b/apps/server/prisma/migrations/20240828195801_add_unique_email_workspace_for_invite/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - A unique constraint covering the columns `[emailId,workspaceId]` on the table `Invite` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "Invite_emailId_workspaceId_key" ON "Invite"("emailId", "workspaceId"); diff --git a/apps/server/prisma/schema.prisma b/apps/server/prisma/schema.prisma index 9e11a043..5a021cd8 100644 --- a/apps/server/prisma/schema.prisma +++ b/apps/server/prisma/schema.prisma @@ -173,6 +173,8 @@ model Invite { status InviteStatus teamIds String[] role Role + + @@unique([emailId, workspaceId]) } model Issue { @@ -572,9 +574,11 @@ model Workspace { updatedAt DateTime @updatedAt deleted DateTime? - name String - slug String @unique - icon String? + name String + slug String @unique + icon String? + + actionsEnabled Boolean @default(false) usersOnWorkspaces UsersOnWorkspaces[] team Team[] diff --git a/apps/server/scripts/createUserWorkspaceTeam.js b/apps/server/scripts/createUserWorkspaceTeam.js deleted file mode 100644 index c84b9c55..00000000 --- a/apps/server/scripts/createUserWorkspaceTeam.js +++ /dev/null @@ -1,333 +0,0 @@ -/** Copyright (c) 2024, Tegon, all rights reserved. **/ - -const crypto = require('crypto'); -const readline = require('readline'); - -const axios = require('axios'); - -const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, -}); - -const host = 'http://localhost:3001'; - -function generateRandomPassword(length = 10) { - const lowercaseChars = 'abcdefghijklmnopqrstuvwxyz'; - const uppercaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - const numberChars = '0123456789'; - const specialChars = '!@#$%^&*()_+'; - - let password = ''; - - // Ensure at least one character from each required category - password += lowercaseChars[crypto.randomInt(0, lowercaseChars.length)]; - password += uppercaseChars[crypto.randomInt(0, uppercaseChars.length)]; - password += numberChars[crypto.randomInt(0, numberChars.length)]; - password += specialChars[crypto.randomInt(0, specialChars.length)]; - - // Generate remaining characters randomly - const remainingChars = length - 4; - const allChars = lowercaseChars + uppercaseChars + numberChars + specialChars; - for (let i = 0; i < remainingChars; i++) { - password += allChars[crypto.randomInt(0, allChars.length)]; - } - - // Shuffle the password characters - password = password - .split('') - .sort(() => 0.5 - Math.random()) - .join(''); - - return password; -} - -async function createUser(email, password = null) { - try { - const finalPassword = password ? password : generateRandomPassword(10); - const userResponse = await axios.post(`${host}/auth/signup`, { - formFields: [ - { - id: 'email', - value: email, - }, - { - id: 'password', - value: finalPassword, - }, - ], - }); - - if (userResponse.data.status === 'FIELD_ERROR') { - throw userResponse.data; - } - console.log('User created successfully.'); - return { email, password: finalPassword }; - } catch (error) { - console.error('Error creating user:', error); - throw error; - } -} - -let accessToken; - -async function signIn(email, password, adminUser = false) { - try { - const response = await axios.post( - `${host}/auth/signin`, - { - formFields: [ - { - id: 'email', - value: email, - }, - { - id: 'password', - value: password, - }, - ], - }, - { headers: {} }, - ); - - if (adminUser) { - accessToken = response.headers['st-access-token']; - if (!accessToken) { - throw 'Invalid Password'; - } - } - console.log('Signed in successfully. Access token:', accessToken); - return response.data; - } catch (error) { - console.error('Error signing in:', error); - throw error; - } -} - -async function createOrGetWorkspace(workspaceName) { - try { - // Check if the workspace already exists - const response = await axios.get( - `${host}/v1/workspaces/name/${workspaceName}`, - { - headers: { Authorization: `Bearer ${accessToken}` }, - }, - ); - - if (response.data) { - // Workspace already exists, return the first workspace found - return response.data; - } - // Workspace doesn't exist, create a new one - const workspaceResponse = await axios.post( - `${host}/v1/workspaces`, - { - name: workspaceName, - slug: workspaceName.toLowerCase().replace(/\s+/g, ''), - }, - { - headers: { Authorization: `Bearer ${accessToken}` }, - }, - ); - return workspaceResponse.data; - } catch (error) { - console.error('Error creating or getting workspace:', error); - throw error; - } -} - -async function getOrCreateTeam(teamName, teamIdentifier = null, workspaceId) { - try { - // Check if the workspace already exists - const response = await axios.get( - `${host}/v1/teams/name/${teamName}?workspaceId=${workspaceId}`, - { - headers: { Authorization: `Bearer ${accessToken}` }, - }, - ); - - if (response.data) { - // Workspace already exists, return the first workspace found - return response.data; - } - - if (!teamIdentifier) { - teamIdentifier = await new Promise((resolve) => { - rl.question('Enter the team identifier: ', resolve); - }); - } - // Workspace doesn't exist, create a new one - const workspaceResponse = await axios.post( - `${host}/v1/teams?workspaceId=${workspaceId}`, - { - name: teamName, - identifier: teamIdentifier, - }, - { - headers: { Authorization: `Bearer ${accessToken}` }, - }, - ); - return workspaceResponse.data; - } catch (error) { - console.error('Error creating or getting workspace:', error); - throw error; - } -} - -async function addUserWorkspaceTeam(userEmails, workspace, team) { - try { - const userPromises = userEmails.map(async (email) => { - const userResponse = await axios.get( - `${host}/v1/users/email?email=${email}`, - { - headers: { Authorization: `Bearer ${accessToken}` }, - }, - ); - - const user = userResponse.data; - await axios.post( - `${host}/v1/workspaces/${workspace.id}/add_users`, - { - userId: user.id, - }, - { - headers: { Authorization: `Bearer ${accessToken}` }, - }, - ); - - const userOnWorkspace = await axios.post( - `${host}/v1/teams/${team.id}/add_member?workspaceId=${workspace.id}`, - { - userId: user.id, - }, - { - headers: { Authorization: `Bearer ${accessToken}` }, - }, - ); - - return { user, userOnWorkspace }; - }); - - const users = await Promise.all(userPromises); - - return { users }; - } catch (error) { - console.error('Error creating user, workspace, and team:', error); - throw error; - } -} - -async function main() { - try { - console.log('Welcome to the User, Workspace, and Team Creation Script!'); - - // Prompt for initial setup - const initialSetup = await new Promise((resolve) => { - rl.question('Is this initial setup (yes/no): ', (answer) => { - resolve(answer.toLowerCase() === 'yes'); - }); - }); - - // Prompt for admin email and password - const adminEmail = await new Promise((resolve) => { - rl.question('Enter your email: ', resolve); - }); - const adminPassword = await new Promise((resolve) => { - rl.question('Enter your password: ', resolve); - }); - - // Create admin user if initial setup - if (initialSetup) { - console.log(adminEmail, adminPassword); - await createUser(adminEmail, adminPassword); - } - - // Sign in as admin - await signIn(adminEmail, adminPassword, true); - - while (true) { - // Display menu options - console.log('\nOptions:'); - console.log('1. Create Workspace'); - console.log('2. Create Team'); - console.log('3. Create Multiple Users'); - console.log('4. Add Users to Workspace and Team'); - console.log('5. Exit'); - - // Prompt for user choice - const option = await new Promise((resolve) => { - rl.question('Enter your choice (1-5): ', resolve); - }); - - if (option === '1') { - // Create workspace - const workspaceName = await new Promise((resolve) => { - rl.question('Enter the workspace name: ', resolve); - }); - await createOrGetWorkspace(workspaceName); - console.log(`Workspace ${workspaceName} created successfully.`); - } else if (option === '2') { - // Create team - const workspaceName = await new Promise((resolve) => { - rl.question('Enter the workspace name: ', resolve); - }); - const workspace = await createOrGetWorkspace(workspaceName); - - const teamName = await new Promise((resolve) => { - rl.question('Enter the team name: ', resolve); - }); - const teamIdentifier = await new Promise((resolve) => { - rl.question('Enter the team identifier: ', resolve); - }); - - await getOrCreateTeam(teamName, teamIdentifier, workspace.id); - console.log(`Team ${teamName} created successfully.`); - } else if (option === '3') { - // Create multiple users - const userEmailsInput = await new Promise((resolve) => { - rl.question('Enter user emails (comma-separated): ', resolve); - }); - const userEmails = userEmailsInput - .split(',') - .map((email) => email.trim()); - - for (const email of userEmails) { - const userDetails = await createUser(email); - console.log(userDetails); - } - - console.log('Users created successfully.'); - } else if (option === '4') { - // Add users to workspace and team - const userEmailsInput = await new Promise((resolve) => { - rl.question('Enter user emails (comma-separated): ', resolve); - }); - const userEmails = userEmailsInput - .split(',') - .map((email) => email.trim()); - const workspaceName = await new Promise((resolve) => { - rl.question('Enter the workspace name: ', resolve); - }); - const workspace = await createOrGetWorkspace(workspaceName); - const teamName = await new Promise((resolve) => { - rl.question('Enter the team name: ', resolve); - }); - const team = await getOrCreateTeam(teamName, null, workspace.id); - await addUserWorkspaceTeam(userEmails, workspace, team); - console.log('Users added to workspace and team successfully.'); - } else if (option === '5') { - // Exit the script - break; - } else { - console.log('Invalid option. Please try again.'); - } - } - - rl.close(); - } catch (error) { - console.error('Error:', error); - rl.close(); - } -} - -main(); diff --git a/apps/server/src/modules/action-event/action-event.service.ts b/apps/server/src/modules/action-event/action-event.service.ts index 17d24b2b..16050281 100644 --- a/apps/server/src/modules/action-event/action-event.service.ts +++ b/apps/server/src/modules/action-event/action-event.service.ts @@ -86,7 +86,7 @@ export default class ActionEventService { const triggerHandle = await this.triggerdevService.triggerTaskAsync( actionEvent.workspaceId, - actionEntity.action.name, + actionEntity.action.slug, { event: actionEvent.eventType, type: actionEvent.modelName, diff --git a/apps/server/src/modules/action-event/action-event.utils.ts b/apps/server/src/modules/action-event/action-event.utils.ts index 41bf4052..4b811554 100644 --- a/apps/server/src/modules/action-event/action-event.utils.ts +++ b/apps/server/src/modules/action-event/action-event.utils.ts @@ -11,7 +11,7 @@ export async function getIntegrationAccountsFromActions( const integrationAccounts = await prisma.integrationAccount.findMany({ where: { integrationDefinition: { - name: { + slug: { in: integrations, }, }, diff --git a/apps/server/src/modules/action/action.controller.ts b/apps/server/src/modules/action/action.controller.ts index f3d2304c..df4c9c55 100644 --- a/apps/server/src/modules/action/action.controller.ts +++ b/apps/server/src/modules/action/action.controller.ts @@ -18,6 +18,7 @@ import { SessionContainer } from 'supertokens-node/recipe/session'; import { AuthGuard } from 'modules/auth/auth.guard'; import { Session as SessionDecorator } from 'modules/auth/session.decorator'; +import { ActionGuard } from './action.guard'; import ActionService from './action.service'; import { getActionConfig, @@ -29,11 +30,12 @@ import { version: '1', path: 'action', }) +@UseGuards(AuthGuard) export class ActionController { constructor(private actionService: ActionService) {} @Post('create-resource') - @UseGuards(AuthGuard) + @UseGuards(ActionGuard) async createResource( @SessionDecorator() session: SessionContainer, @Body() actionCreateResource: CreateActionDto, @@ -57,6 +59,7 @@ export class ActionController { } @Get(':slug/runs') + @UseGuards(ActionGuard) async getRunsForSlug( @Param() slugDto: { slug: string }, @Query() runIdParams: { runId: string; workspaceId: string }, @@ -76,6 +79,7 @@ export class ActionController { } @Post(':slug/run') + @UseGuards(ActionGuard) // eslint-disable-next-line @typescript-eslint/no-explicit-any async run(@Param() slugDto: { slug: string }, @Body() runBody: any) { return await this.actionService.run( @@ -86,6 +90,7 @@ export class ActionController { } @Get() + @UseGuards(ActionGuard) async getActions(@Query() workspaceIdDto: WorkspaceRequestParamsDto) { return await this.actionService.getActions(workspaceIdDto.workspaceId); } diff --git a/apps/server/src/modules/action/action.guard.ts b/apps/server/src/modules/action/action.guard.ts new file mode 100644 index 00000000..36f778cb --- /dev/null +++ b/apps/server/src/modules/action/action.guard.ts @@ -0,0 +1,19 @@ +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; + +import WorkspacesService from 'modules/workspaces/workspaces.service'; +@Injectable() +export class ActionGuard implements CanActivate { + constructor(private workspaceService: WorkspacesService) {} + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const workspaceId = request.body.workspaceId || request.query.workspaceId; + + if (!workspaceId) { + return false; + } + + const workspace = await this.workspaceService.getWorkspace({ workspaceId }); + return workspace.actionsEnabled; + } +} diff --git a/apps/server/src/modules/action/action.module.ts b/apps/server/src/modules/action/action.module.ts index 0e945989..a3e83f54 100644 --- a/apps/server/src/modules/action/action.module.ts +++ b/apps/server/src/modules/action/action.module.ts @@ -3,6 +3,7 @@ import { PrismaModule, PrismaService } from 'nestjs-prisma'; import { TriggerdevService } from 'modules/triggerdev/triggerdev.service'; import { UsersService } from 'modules/users/users.service'; +import WorkspacesService from 'modules/workspaces/workspaces.service'; import { ActionController } from './action.controller'; import ActionService from './action.service'; @@ -10,7 +11,13 @@ import ActionService from './action.service'; @Module({ imports: [PrismaModule], controllers: [ActionController], - providers: [PrismaService, ActionService, UsersService, TriggerdevService], + providers: [ + PrismaService, + ActionService, + UsersService, + TriggerdevService, + WorkspacesService, + ], exports: [ActionService], }) export class ActionModule {} diff --git a/apps/server/src/modules/action/action.service.ts b/apps/server/src/modules/action/action.service.ts index da1e3624..a41f9fd1 100644 --- a/apps/server/src/modules/action/action.service.ts +++ b/apps/server/src/modules/action/action.service.ts @@ -141,12 +141,18 @@ export default class ActionService { userId: string, workspaceId: string, ) { + const teamIds = ( + await prisma.team.findMany({ + where: { workspaceId }, + }) + ).map((team) => team.id); + await prisma.usersOnWorkspaces.upsert({ where: { userId_workspaceId: { workspaceId, userId }, }, update: { role: RoleEnum.BOT }, - create: { workspaceId, userId, role: RoleEnum.BOT }, + create: { workspaceId, userId, role: RoleEnum.BOT, teamIds }, }); } diff --git a/apps/server/src/modules/ai-requests/ai-requests.controller.ts b/apps/server/src/modules/ai-requests/ai-requests.controller.ts index df24db52..7fc9436e 100644 --- a/apps/server/src/modules/ai-requests/ai-requests.controller.ts +++ b/apps/server/src/modules/ai-requests/ai-requests.controller.ts @@ -1,5 +1,5 @@ import { Body, Controller, Post, UseGuards } from '@nestjs/common'; -import { GetAIRequestDTO } from '@tegonhq/types'; +import { AIStreamResponse, GetAIRequestDTO } from '@tegonhq/types'; import { AuthGuard } from 'modules/auth/auth.guard'; @@ -14,13 +14,17 @@ export class AIRequestsController { @Post() @UseGuards(AuthGuard) - async getLLMRequest(@Body() aiRequestInput: GetAIRequestDTO) { + async getLLMRequest( + @Body() aiRequestInput: GetAIRequestDTO, + ): Promise { return await this.aiRequestsService.getLLMRequest(aiRequestInput); } @Post('stream') @UseGuards(AuthGuard) - async getLLMRequestStream(@Body() aiRequestInput: GetAIRequestDTO) { + async getLLMRequestStream( + @Body() aiRequestInput: GetAIRequestDTO, + ): Promise { return await this.aiRequestsService.getLLMRequestStream(aiRequestInput); } } diff --git a/apps/server/src/modules/ai-requests/ai-requests.services.ts b/apps/server/src/modules/ai-requests/ai-requests.services.ts index 754f8211..053b8941 100644 --- a/apps/server/src/modules/ai-requests/ai-requests.services.ts +++ b/apps/server/src/modules/ai-requests/ai-requests.services.ts @@ -1,15 +1,11 @@ import { openai } from '@ai-sdk/openai'; import { Injectable, Logger } from '@nestjs/common'; -import { GetAIRequestDTO } from '@tegonhq/types'; +import { GetAIRequestDTO, AIStreamResponse } from '@tegonhq/types'; import { streamText, generateText, CoreMessage, CoreUserMessage } from 'ai'; import { PrismaService } from 'nestjs-prisma'; import { Ollama } from 'ollama'; import { createOllama } from 'ollama-ai-provider'; -interface StreamResponse { - textStream: AsyncIterable & ReadableStream; -} - @Injectable() export default class AIRequestsService { private readonly logger: Logger = new Logger('RequestsService'); @@ -27,8 +23,10 @@ export default class AIRequestsService { return (await this.LLMRequestStream(reqBody, false)) as string; } - async getLLMRequestStream(reqBody: GetAIRequestDTO): Promise { - return (await this.LLMRequestStream(reqBody, true)) as StreamResponse; + async getLLMRequestStream( + reqBody: GetAIRequestDTO, + ): Promise { + return (await this.LLMRequestStream(reqBody, true)) as AIStreamResponse; } async LLMRequestStream(reqBody: GetAIRequestDTO, stream: boolean = true) { diff --git a/apps/server/src/modules/attachments/attachments.service.ts b/apps/server/src/modules/attachments/attachments.service.ts index be580233..e407f02f 100644 --- a/apps/server/src/modules/attachments/attachments.service.ts +++ b/apps/server/src/modules/attachments/attachments.service.ts @@ -8,7 +8,6 @@ import { AttachmentResponse, AttachmentStatusEnum } from '@tegonhq/types'; import { PrismaService } from 'nestjs-prisma'; import { AttachmentRequestParams, ExternalFile } from './attachments.interface'; - @Injectable() export class AttachmentService { private storage: Storage; diff --git a/apps/server/src/modules/auth/supertokens/supertokens.config.ts b/apps/server/src/modules/auth/supertokens/supertokens.config.ts index fb6ff5ba..902c6135 100644 --- a/apps/server/src/modules/auth/supertokens/supertokens.config.ts +++ b/apps/server/src/modules/auth/supertokens/supertokens.config.ts @@ -1,91 +1,80 @@ +import { MailerService } from '@nestjs-modules/mailer'; import jwt from 'supertokens-node/lib/build/recipe/jwt'; -import EmailPassword from 'supertokens-node/recipe/emailpassword'; +import { TypePasswordlessEmailDeliveryInput } from 'supertokens-node/lib/build/recipe/passwordless/types'; +import Passwordless from 'supertokens-node/recipe/passwordless'; import Session from 'supertokens-node/recipe/session'; -import ThirdPartyEmailPassword from 'supertokens-node/recipe/thirdpartyemailpassword'; import UserRoles from 'supertokens-node/recipe/userroles'; import { UsersService } from 'modules/users/users.service'; -export const recipeList = (usersService: UsersService) => { +export const recipeList = ( + usersService: UsersService, + mailerService: MailerService, +) => { return [ jwt.init(), UserRoles.init(), Session.init({ cookieSecure: true, }), // initializes session features - ThirdPartyEmailPassword.init({ + Passwordless.init({ + contactMethod: 'EMAIL', + flowType: 'USER_INPUT_CODE_AND_MAGIC_LINK', + emailDelivery: { + override: (originalImplementation) => { + return { + ...originalImplementation, + async sendEmail({ + email, + urlWithLinkCode, + codeLifetime, + }: TypePasswordlessEmailDeliveryInput) { + mailerService.sendMail({ + to: email, + subject: 'Login for Tegon', + template: 'loginUser', + context: { + userName: email.split('@')[0], + magicLink: urlWithLinkCode, + linkExpiresIn: Math.floor(codeLifetime / 60000), + }, + }); + }, + }; + }, + }, override: { functions: (originalImplementation) => { return { ...originalImplementation, - - // override the email password sign up function // eslint-disable-next-line @typescript-eslint/no-explicit-any - async emailPasswordSignUp(input: any) { - const response = - await originalImplementation.emailPasswordSignUp(input); - - if ( - response.status === 'OK' && - response.user.loginMethods.length === 1 && - input.session === undefined - ) { - await usersService.upsertUser( - response.user.id, - input.email, - input.email.split('@')[0], - ); - } - return response; - }, - - // override the thirdparty sign in / up function - // eslint-disable-next-line @typescript-eslint/no-explicit-any - async thirdPartySignInUp(input: any) { - const response = - await originalImplementation.thirdPartySignInUp(input); + consumeCode: async (input: any) => { + // First we call the original implementation of consumeCode. + const response = await originalImplementation.consumeCode(input); + // Post sign up response, we check if it was successful if (response.status === 'OK') { + const { id, emails } = response.user; + const email = emails[0]; + if (input.session === undefined) { if ( response.createdNewRecipeUser && response.user.loginMethods.length === 1 ) { - usersService.upsertUser( - response.user.id, - input.email, - input.email.split('@')[0], + await usersService.upsertUser( + id, + email, + email.split('@')[0], ); - } else { - // TODO: some post sign in logic } } } - return response; }, }; }, }, - providers: [ - { - config: { - thirdPartyId: 'google', - clients: [ - { - clientId: process.env.GOOGLE_LOGIN_CLIENT_ID, - clientSecret: process.env.GOOGLE_LOGIN_CLIENT_SECRET, - scope: [ - 'https://www.googleapis.com/auth/userinfo.email', - 'https://www.googleapis.com/auth/userinfo.profile', - ], - }, - ], - }, - }, - ], }), - - EmailPassword.init(), ]; }; diff --git a/apps/server/src/modules/auth/supertokens/supertokens.service.ts b/apps/server/src/modules/auth/supertokens/supertokens.service.ts index 93c4a42a..656e6391 100644 --- a/apps/server/src/modules/auth/supertokens/supertokens.service.ts +++ b/apps/server/src/modules/auth/supertokens/supertokens.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@nestjs/common'; +import { MailerService } from '@nestjs-modules/mailer'; import supertokens, { deleteUser } from 'supertokens-node'; import EmailPassword from 'supertokens-node/recipe/emailpassword'; @@ -8,7 +9,10 @@ import { recipeList } from './supertokens.config'; @Injectable() export class SupertokensService { - constructor(private usersService: UsersService) { + constructor( + private usersService: UsersService, + private mailerService: MailerService, + ) { supertokens.init({ appInfo: { appName: 'Tegon', @@ -20,7 +24,7 @@ export class SupertokensService { supertokens: { connectionURI: process.env.SUPERTOKEN_CONNECTION_URI, }, - recipeList: recipeList(this.usersService), + recipeList: recipeList(this.usersService, this.mailerService), }); } diff --git a/apps/server/src/modules/issue-comments/issue-comments.controller.ts b/apps/server/src/modules/issue-comments/issue-comments.controller.ts index 675c1916..676204cc 100644 --- a/apps/server/src/modules/issue-comments/issue-comments.controller.ts +++ b/apps/server/src/modules/issue-comments/issue-comments.controller.ts @@ -13,6 +13,7 @@ import { CreateIssueCommentRequestParamsDto, IssueComment, IssueCommentRequestParamsDto, + LinkedComment, } from '@tegonhq/types'; import { SessionContainer } from 'supertokens-node/recipe/session'; @@ -34,7 +35,9 @@ export class IssueCommentsController { @Get('linked_comment') @UseGuards(AuthGuard) - async getLinkedComment(@Query('sourceId') sourceId: string) { + async getLinkedComment( + @Query('sourceId') sourceId: string, + ): Promise { return await this.issueCommentsService.getLinkedCommentBySource(sourceId); } @@ -43,7 +46,7 @@ export class IssueCommentsController { async createLinkedComment( // eslint-disable-next-line @typescript-eslint/no-explicit-any @Body() createLinkedCommentInput: any, - ) { + ): Promise { return await this.issueCommentsService.createLinkedComment( createLinkedCommentInput, ); diff --git a/apps/server/src/modules/issue-comments/issue-comments.service.ts b/apps/server/src/modules/issue-comments/issue-comments.service.ts index 5bab1a6d..877a5fc6 100644 --- a/apps/server/src/modules/issue-comments/issue-comments.service.ts +++ b/apps/server/src/modules/issue-comments/issue-comments.service.ts @@ -4,6 +4,7 @@ import { CreateIssueCommentRequestParamsDto, IssueComment, IssueCommentRequestParamsDto, + LinkedComment, } from '@tegonhq/types'; import { PrismaService } from 'nestjs-prisma'; @@ -221,15 +222,17 @@ export default class IssueCommentsService { }); } - async getLinkedCommentBySource(sourceId: string) { + async getLinkedCommentBySource(sourceId: string): Promise { return this.prisma.linkedComment.findFirst({ where: { sourceId }, include: { comment: true }, }); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - async createLinkedComment(createLinkedCommentInput: any) { + async createLinkedComment( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + createLinkedCommentInput: any, + ): Promise { return this.prisma.linkedComment.create({ data: createLinkedCommentInput, }); diff --git a/apps/server/src/modules/issues/issues.controller.ts b/apps/server/src/modules/issues/issues.controller.ts index 5828fc4a..ecf23226 100644 --- a/apps/server/src/modules/issues/issues.controller.ts +++ b/apps/server/src/modules/issues/issues.controller.ts @@ -20,6 +20,7 @@ import { UpdateIssueDto, WorkspaceRequestParamsDto, GetIssuesByFilterDTO, + LinkedIssue, } from '@tegonhq/types'; import { Response } from 'express'; import { SessionContainer } from 'supertokens-node/recipe/session'; @@ -46,7 +47,7 @@ export class IssuesController { async createIssue( @SessionDecorator() session: SessionContainer, @Body() issueData: CreateIssueDto, - ) { + ): Promise { const userId = session.getUserId(); return await this.issuesService.createIssueAPI(issueData, userId); } @@ -91,7 +92,7 @@ export class IssuesController { @SessionDecorator() session: SessionContainer, @Param() issueParams: IssueRequestParamsDto, @Body() linkData: CreateLinkedIssueDto, - ) { + ): Promise { const userId = session.getUserId(); return await this.linkedIssueService.createLinkIssue( linkData, @@ -121,7 +122,7 @@ export class IssuesController { @SessionDecorator() session: SessionContainer, @Param() issueParams: IssueRequestParamsDto, @Body() moveData: TeamRequestParamsDto, - ) { + ): Promise { const userId = session.getUserId(); return await this.issuesService.moveIssue( userId, diff --git a/apps/server/src/modules/issues/issues.service.ts b/apps/server/src/modules/issues/issues.service.ts index 4c71df2b..ca7fd3bc 100644 --- a/apps/server/src/modules/issues/issues.service.ts +++ b/apps/server/src/modules/issues/issues.service.ts @@ -551,7 +551,11 @@ export default class IssuesService { ); } - async moveIssue(userId: string, issueId: string, teamId: string) { + async moveIssue( + userId: string, + issueId: string, + teamId: string, + ): Promise { const currentIssue = await this.prisma.issue.findUnique({ where: { id: issueId }, include: { subIssue: true, team: true }, diff --git a/apps/server/src/modules/oauth-callback/oauth-callback.service.ts b/apps/server/src/modules/oauth-callback/oauth-callback.service.ts index 89697360..e1fb5b14 100644 --- a/apps/server/src/modules/oauth-callback/oauth-callback.service.ts +++ b/apps/server/src/modules/oauth-callback/oauth-callback.service.ts @@ -23,7 +23,7 @@ import { getTemplate, } from './oauth-callback.utils'; -const CALLBACK_URL = `${process.env.PUBLIC_FRONTEND_HOST}/api/v1/oauth/callback`; +const CALLBACK_URL = `https://0d81-2406-b400-d4-169f-68a7-67c9-83d6-91cf.ngrok-free.app/api/v1/oauth/callback`; @Injectable() export class OAuthCallbackService { diff --git a/apps/server/src/modules/sync-actions/sync-actions.utils.ts b/apps/server/src/modules/sync-actions/sync-actions.utils.ts index cce33941..c0fccfd6 100644 --- a/apps/server/src/modules/sync-actions/sync-actions.utils.ts +++ b/apps/server/src/modules/sync-actions/sync-actions.utils.ts @@ -177,6 +177,7 @@ export async function getModelData( createdAt: true, updatedAt: true, deleted: true, + personal: true, workspaceId: true, integrationDefinitionId: true, }, diff --git a/apps/server/src/modules/triggerdev/triggerdev.controller.ts b/apps/server/src/modules/triggerdev/triggerdev.controller.ts index daa8a39b..5fbdc06d 100644 --- a/apps/server/src/modules/triggerdev/triggerdev.controller.ts +++ b/apps/server/src/modules/triggerdev/triggerdev.controller.ts @@ -2,6 +2,7 @@ import { Controller, Get, Query, UseGuards } from '@nestjs/common'; import { WorkspaceRequestParamsDto } from '@tegonhq/types'; import { SessionContainer } from 'supertokens-node/recipe/session'; +import { ActionGuard } from 'modules/action/action.guard'; import { AuthGuard } from 'modules/auth/auth.guard'; import { Session as SessionDecorator } from 'modules/auth/session.decorator'; @@ -15,7 +16,7 @@ export class TriggerdevController { constructor(private triggerdevService: TriggerdevService) {} @Get() - @UseGuards(AuthGuard) + @UseGuards(AuthGuard, ActionGuard) async getRequiredKeys( @SessionDecorator() session: SessionContainer, @Query() requestParams: WorkspaceRequestParamsDto, diff --git a/apps/server/src/modules/triggerdev/triggerdev.module.ts b/apps/server/src/modules/triggerdev/triggerdev.module.ts index 46133825..a0479a1f 100644 --- a/apps/server/src/modules/triggerdev/triggerdev.module.ts +++ b/apps/server/src/modules/triggerdev/triggerdev.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { PrismaModule, PrismaService } from 'nestjs-prisma'; import { UsersService } from 'modules/users/users.service'; +import WorkspacesService from 'modules/workspaces/workspaces.service'; import { TriggerdevController } from './triggerdev.controller'; import { TriggerdevService } from './triggerdev.service'; @@ -9,7 +10,12 @@ import { TriggerdevService } from './triggerdev.service'; @Module({ imports: [PrismaModule], controllers: [TriggerdevController], - providers: [TriggerdevService, UsersService, PrismaService], + providers: [ + TriggerdevService, + UsersService, + PrismaService, + WorkspacesService, + ], exports: [TriggerdevService], }) export class TriggerdevModule {} diff --git a/apps/server/src/modules/webhook/webhook.service.ts b/apps/server/src/modules/webhook/webhook.service.ts index a86a8d5a..b0c719cf 100644 --- a/apps/server/src/modules/webhook/webhook.service.ts +++ b/apps/server/src/modules/webhook/webhook.service.ts @@ -33,7 +33,8 @@ export default class WebhookService { ) { if (sourceName === 'slack') { if (eventBody.type === 'url_verification') { - return { challenge: eventBody.challenge }; + response.send({ challenge: eventBody.challenge }); + return null; } } @@ -84,13 +85,13 @@ export default class WebhookService { // TODO (actons): Send all integration accounts based on the ask actionEntities.map(async (actionEntity: ActionEntity) => { const actionUser = await this.prisma.user.findFirst({ - where: { username: actionEntity.action.name }, + where: { username: actionEntity.action.slug }, }); const accessToken = await generateKeyForUserId(actionUser.id); this.triggerDevService.triggerTaskAsync( workspaceId, - actionEntity.action.name, + actionEntity.action.slug, { event: ActionTypesEnum.SOURCE_WEBHOOK, action: actionEntity.action, diff --git a/apps/server/src/modules/workspaces/workspaces.controller.ts b/apps/server/src/modules/workspaces/workspaces.controller.ts index 554eed3d..b234461b 100644 --- a/apps/server/src/modules/workspaces/workspaces.controller.ts +++ b/apps/server/src/modules/workspaces/workspaces.controller.ts @@ -18,7 +18,7 @@ import { AuthGuard } from 'modules/auth/auth.guard'; import { Session as SessionDecorator } from 'modules/auth/session.decorator'; import { - CreateWorkspaceInput, + CreateInitialResourcesDto, InviteActionBody, InviteUsersBody, UpdateWorkspaceInput, @@ -33,14 +33,17 @@ import WorkspacesService from './workspaces.service'; export class WorkspacesController { constructor(private workspacesService: WorkspacesService) {} - @Post() + @Post('onboarding') @UseGuards(AuthGuard) - async createWorkspace( + async createIntialResources( @SessionDecorator() session: SessionContainer, - @Body() workspaceData: CreateWorkspaceInput, + @Body() workspaceData: CreateInitialResourcesDto, ): Promise { const userId = session.getUserId(); - return await this.workspacesService.createWorkspace(userId, workspaceData); + return await this.workspacesService.createInitialResources( + userId, + workspaceData, + ); } @Get() @@ -60,12 +63,6 @@ export class WorkspacesController { return await this.workspacesService.getWorkspaceByName(workspaceName); } - @Post('seed_workspaces') - async seedWorkspaces() { - await this.workspacesService.seedWorkspaces(); - return { status: 200 }; - } - @Post('invite_action') @UseGuards(AuthGuard) async inviteAction( diff --git a/apps/server/src/modules/workspaces/workspaces.interface.ts b/apps/server/src/modules/workspaces/workspaces.interface.ts index 2b924d02..306918fd 100644 --- a/apps/server/src/modules/workspaces/workspaces.interface.ts +++ b/apps/server/src/modules/workspaces/workspaces.interface.ts @@ -22,6 +22,20 @@ export class CreateWorkspaceInput { icon: string; } +export class CreateInitialResourcesDto { + @IsString() + workspaceName: string; + + @IsString() + fullname: string; + + @IsString() + teamName: string; + + @IsString() + teamIdentifier: string; +} + export class UpdateWorkspaceInput { @IsOptional() @IsString() diff --git a/apps/server/src/modules/workspaces/workspaces.service.ts b/apps/server/src/modules/workspaces/workspaces.service.ts index 7aeb31c7..32e6c51c 100644 --- a/apps/server/src/modules/workspaces/workspaces.service.ts +++ b/apps/server/src/modules/workspaces/workspaces.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { BadRequestException, Injectable, Logger } from '@nestjs/common'; import { MailerService } from '@nestjs-modules/mailer'; import { InviteStatusEnum, @@ -11,9 +11,11 @@ import { import { PrismaService } from 'nestjs-prisma'; import { SessionContainer } from 'supertokens-node/recipe/session'; +import { workflowSeedData } from 'modules/teams/teams.interface'; import { UsersService } from 'modules/users/users.service'; import { + CreateInitialResourcesDto, CreateWorkspaceInput, InviteUsersBody, UpdateWorkspaceInput, @@ -31,6 +33,64 @@ export default class WorkspacesService { private usersService: UsersService, ) {} + async createInitialResources( + userId: string, + workspaceData: CreateInitialResourcesDto, + ): Promise { + const workspace = await this.prisma.usersOnWorkspaces.findFirst({ + where: { userId }, + }); + + if (workspace) { + throw new BadRequestException('Already workspace exist'); + } + + return await this.prisma.$transaction(async (prisma) => { + await prisma.user.update({ + where: { id: userId }, + data: { + fullname: workspaceData.fullname, + }, + }); + + const workspace = await prisma.workspace.create({ + data: { + name: workspaceData.workspaceName, + slug: workspaceData.workspaceName.toLowerCase().replace(/-/g, ''), + usersOnWorkspaces: { + create: { userId }, + }, + team: { + create: { + name: workspaceData.teamName, + identifier: workspaceData.teamIdentifier, + workflow: { create: workflowSeedData }, + }, + }, + label: { create: labelSeedData }, + + prompts: { + createMany: { + data: promptsSeedData, + skipDuplicates: true, + }, + }, + }, + include: { + team: true, + usersOnWorkspaces: true, + }, + }); + + await prisma.usersOnWorkspaces.update({ + where: { userId_workspaceId: { userId, workspaceId: workspace.id } }, + data: { teamIds: [workspace.team[0].id] }, + }); + + return workspace; + }); + } + async createWorkspace( userId: string, workspaceData: CreateWorkspaceInput, @@ -116,24 +176,6 @@ export default class WorkspacesService { }); } - async seedWorkspaces(): Promise { - const workspaces = await this.prisma.workspace.findMany(); - - workspaces.map(async (workspace) => { - await this.prisma.workspace.update({ - where: { id: workspace.id }, - data: { - prompts: { - createMany: { - data: promptsSeedData, - skipDuplicates: true, - }, - }, - }, - }); - }); - } - async addUserToWorkspace( workspaceId: string, userId: string, @@ -165,8 +207,14 @@ export default class WorkspacesService { for (const e of emails) { const email = e.trim(); try { - const invite = await this.prisma.invite.create({ - data: { + await this.prisma.invite.upsert({ + where: { + emailId_workspaceId: { + emailId: email, + workspaceId, + }, + }, + create: { emailId: email, fullName: email.split('@')[0], workspaceId, @@ -176,6 +224,9 @@ export default class WorkspacesService { teamIds, role, }, + update: { + sentAt: new Date().toISOString(), + }, }); await this.mailerService.sendMail({ @@ -185,7 +236,7 @@ export default class WorkspacesService { context: { workspaceName: workspace.name, inviterName: iniviter.fullname, - invitationUrl: `${process.env.PUBLIC_FRONTEND_HOST}/auth/signup?token=${invite.id}&email=${email}`, + invitationUrl: `${process.env.PUBLIC_FRONTEND_HOST}/auth`, }, }); this.logger.log('Invite Email sent to user'); diff --git a/apps/server/templates/loginUser.hbs b/apps/server/templates/loginUser.hbs new file mode 100644 index 00000000..25294b18 --- /dev/null +++ b/apps/server/templates/loginUser.hbs @@ -0,0 +1,60 @@ + + + + Login to Your Account + + + +
+

Hey {{userName}}!

+

To log in to your account, please click the button below:

+
+ Login +
+

This link expires in {{linkExpiresIn}} minutes.

+

If you did not request this login link, please ignore this email.

+

Best regards,
Tegon Team

+
+ + \ No newline at end of file diff --git a/apps/webapp/.prod.env b/apps/webapp/.prod.env index da98a874..c6a54c8a 100644 --- a/apps/webapp/.prod.env +++ b/apps/webapp/.prod.env @@ -1,5 +1,4 @@ NEXT_PUBLIC_VERSION=0.3.0-alpha NEXT_PUBLIC_BASE_HOST=PROD_NEXT_PUBLIC_BASE_HOST NEXT_PUBLIC_BACKEND_HOST=PROD_NEXT_PUBLIC_BACKEND_HOST -NEXT_PUBLIC_SYNC_SERVER=PROD_NEXT_PUBLIC_SYNC_SERVER NEXT_PUBLIC_SENTRY_DSN=PROD_NEXT_PUBLIC_SENTRY_DSN diff --git a/apps/webapp/next.config.js b/apps/webapp/next.config.js index b4588fbb..b8bfca20 100644 --- a/apps/webapp/next.config.js +++ b/apps/webapp/next.config.js @@ -10,7 +10,7 @@ module.exports = { return [ { source: '/', - destination: '/auth/signin', + destination: '/auth', permanent: true, }, ]; @@ -44,7 +44,6 @@ module.exports = { // Will be available on both server and client NEXT_PUBLIC_BASE_HOST: process.env.NEXT_PUBLIC_BASE_HOST, NEXT_PUBLIC_BACKEND_HOST: process.env.NEXT_PUBLIC_BACKEND_HOST, - NEXT_PUBLIC_BACKEND_URL: process.env.NEXT_PUBLIC_BACKEND_URL, NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN, }, output: 'standalone', diff --git a/apps/webapp/src/common/common-utils.ts b/apps/webapp/src/common/common-utils.ts index 3e7cd827..f2a25cbb 100644 --- a/apps/webapp/src/common/common-utils.ts +++ b/apps/webapp/src/common/common-utils.ts @@ -10,3 +10,13 @@ export function convertToTitleCase(input: string): string { .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(' '); } + +export function getTiptapJSON(input: string) { + try { + const parsedInput = JSON.parse(input); + + return JSON.stringify(parsedInput.json); + } catch (e) { + return undefined; + } +} diff --git a/apps/webapp/src/common/layouts/app-layout/app-layout.tsx b/apps/webapp/src/common/layouts/app-layout/app-layout.tsx index 14c52a2f..248e66c3 100644 --- a/apps/webapp/src/common/layouts/app-layout/app-layout.tsx +++ b/apps/webapp/src/common/layouts/app-layout/app-layout.tsx @@ -10,6 +10,7 @@ import { GlobalShortcuts, IssueShortcutDialogs } from 'modules/shortcuts'; import { AllProviders } from 'common/wrappers/all-providers'; import { useCurrentTeam } from 'hooks/teams'; +import { useCurrentWorkspace } from 'hooks/workspace'; import { useContextStore } from 'store/global-context-provider'; @@ -25,6 +26,7 @@ interface LayoutProps { export const AppLayoutChild = observer(({ children }: LayoutProps) => { const { applicationStore, notificationsStore } = useContextStore(); + const workspace = useCurrentWorkspace(); const { query: { workspaceSlug }, @@ -41,6 +43,16 @@ export const AppLayoutChild = observer(({ children }: LayoutProps) => { } }, [applicationStore.sidebarCollapsed]); + const actionsLink = workspace.actionsEnabled + ? [ + { + title: 'Actions', + icon: Actions, + href: `/${workspaceSlug}/actions`, + }, + ] + : []; + return ( <>
@@ -71,11 +83,7 @@ export const AppLayoutChild = observer(({ children }: LayoutProps) => { icon: SettingsLine, href: `/${workspaceSlug}/settings/overview`, }, - { - title: 'Actions', - icon: Actions, - href: `/${workspaceSlug}/actions`, - }, + ...actionsLink, ]} /> diff --git a/apps/webapp/src/common/layouts/app-layout/workspace-dropdown.tsx b/apps/webapp/src/common/layouts/app-layout/workspace-dropdown.tsx index 186d60a0..ed355003 100644 --- a/apps/webapp/src/common/layouts/app-layout/workspace-dropdown.tsx +++ b/apps/webapp/src/common/layouts/app-layout/workspace-dropdown.tsx @@ -67,7 +67,7 @@ export const WorkspaceDropdown = observer(() => { onClick={async () => { await signOut(); - replace('/auth/signin'); + replace('/auth'); }} > Log out diff --git a/apps/webapp/src/common/lib/config.ts b/apps/webapp/src/common/lib/config.ts index 5d2bc2e4..1c359b7f 100644 --- a/apps/webapp/src/common/lib/config.ts +++ b/apps/webapp/src/common/lib/config.ts @@ -1,7 +1,7 @@ import getConfig from 'next/config'; import Router from 'next/router'; +import Passwordless from 'supertokens-auth-react/recipe/passwordless'; import SessionReact from 'supertokens-auth-react/recipe/session'; -import ThirdPartyEmailPasswordReact from 'supertokens-auth-react/recipe/thirdpartyemailpassword'; const { publicRuntimeConfig } = getConfig(); @@ -11,12 +11,17 @@ export const frontendConfig = () => { apiDomain: publicRuntimeConfig.NEXT_PUBLIC_BASE_HOST, websiteDomain: publicRuntimeConfig.NEXT_PUBLIC_BASE_HOST, apiBasePath: '/api/auth', - websiteBasePath: '/auth/signin', + websiteBasePath: '/auth', }; return { appInfo, - recipeList: [ThirdPartyEmailPasswordReact.init(), SessionReact.init()], + recipeList: [ + Passwordless.init({ + contactMethod: 'EMAIL', + }), + SessionReact.init(), + ], // eslint-disable-next-line @typescript-eslint/no-explicit-any windowHandler: (oI: any) => { return { diff --git a/apps/webapp/src/common/types/user.ts b/apps/webapp/src/common/types/user.ts index 29cb69c1..282318a9 100644 --- a/apps/webapp/src/common/types/user.ts +++ b/apps/webapp/src/common/types/user.ts @@ -3,6 +3,7 @@ interface Workspace { slug: string; icon: string; id: string; + actionsEnabled: boolean; } export interface Invite { diff --git a/apps/webapp/src/common/wrappers/action-access-guard.tsx b/apps/webapp/src/common/wrappers/action-access-guard.tsx new file mode 100644 index 00000000..7130b077 --- /dev/null +++ b/apps/webapp/src/common/wrappers/action-access-guard.tsx @@ -0,0 +1,23 @@ +import React from 'react'; + +import { useCurrentWorkspace } from 'hooks/workspace'; + +interface Props { + children: React.ReactNode; +} + +export function ActionAccessGuard(props: Props): React.ReactElement { + const { children } = props; + const workspace = useCurrentWorkspace(); + + if (workspace.actionsEnabled) { + return <>{children}; + } + + return ( +

+ Currently Actions is in beta. Reachout to support (harshith@tegon.ai) for + access +

+ ); +} diff --git a/apps/webapp/src/common/wrappers/socket-data-sync.tsx b/apps/webapp/src/common/wrappers/socket-data-sync.tsx index df218deb..ca9d7c95 100644 --- a/apps/webapp/src/common/wrappers/socket-data-sync.tsx +++ b/apps/webapp/src/common/wrappers/socket-data-sync.tsx @@ -54,7 +54,7 @@ export const SocketDataSyncWrapper: React.FC = observer( }, []); async function initSocket() { - const socket = io(publicRuntimeConfig.NEXT_PUBLIC_BACKEND_URL, { + const socket = io(publicRuntimeConfig.NEXT_PUBLIC_BACKEND_HOST, { query: { workspaceId: workspaceStore.workspace.id, userId: user.id, diff --git a/apps/webapp/src/hooks/use-triage-groups.tsx b/apps/webapp/src/hooks/use-triage-groups.tsx index f8dbf3b1..d5eb0ede 100644 --- a/apps/webapp/src/hooks/use-triage-groups.tsx +++ b/apps/webapp/src/hooks/use-triage-groups.tsx @@ -19,7 +19,7 @@ export function useTriageGroups() { ); const issues = sort( - issuesStore.getIssuesForState(triageWorkflow.id, currentTeam.id, false), + issuesStore.getIssuesForState(triageWorkflow.id, currentTeam.id, true), ).desc((issue: IssueType) => new Date(issue.updatedAt)) as IssueType[]; return React.useMemo(() => { diff --git a/apps/webapp/src/modules/actions/actions.tsx b/apps/webapp/src/modules/actions/actions.tsx index 5c019f63..d89e644a 100644 --- a/apps/webapp/src/modules/actions/actions.tsx +++ b/apps/webapp/src/modules/actions/actions.tsx @@ -10,6 +10,7 @@ import { useParams } from 'next/navigation'; import { Header } from 'modules/settings/header'; import { AppLayout } from 'common/layouts/app-layout'; +import { ActionAccessGuard } from 'common/wrappers/action-access-guard'; import { AllActionsList } from './all-actions-list'; import { Empty } from './empty'; @@ -22,30 +23,32 @@ export function Actions() {
- - -
-

Actions

- - - -
-
- - - {actionSlug ? : } - -
+ + + +
+

Actions

+ + + +
+
+ + + {actionSlug ? : } + +
+
); diff --git a/apps/webapp/src/modules/actions/components/runs-table/columns.tsx b/apps/webapp/src/modules/actions/components/runs-table/columns.tsx index 123ba9f1..40875465 100644 --- a/apps/webapp/src/modules/actions/components/runs-table/columns.tsx +++ b/apps/webapp/src/modules/actions/components/runs-table/columns.tsx @@ -53,20 +53,20 @@ function getIcon(status: Status) { } } -function getSecondsBetweenDates(createdAt: string, finishedAt: string): number { +function getSecondsBetweenDates(createdAt: string, finishedAt: string): string { // Parse the date strings into Date objects const createdDate = new Date(createdAt); const finishedDate = new Date(finishedAt); // Ensure that the parsed dates are valid if (isNaN(createdDate.getTime()) || isNaN(finishedDate.getTime())) { - throw new Error('Invalid date strings'); + return 'recent'; } // Calculate the difference in seconds between the two dates const seconds = differenceInSeconds(finishedDate, createdDate); - return seconds; + return `${seconds}s`; } export const columns: Array> = [ @@ -120,7 +120,6 @@ export const columns: Array> = [ row.original.startedAt ?? row.original.createdAt, row.original.finishedAt, )} - s
); }, diff --git a/apps/webapp/src/modules/actions/components/runs-table/expanded-row.tsx b/apps/webapp/src/modules/actions/components/runs-table/expanded-row.tsx index 475d9636..88e00587 100644 --- a/apps/webapp/src/modules/actions/components/runs-table/expanded-row.tsx +++ b/apps/webapp/src/modules/actions/components/runs-table/expanded-row.tsx @@ -22,7 +22,7 @@ export function ExpandedRow({ row }: ExpandedRowProps) { ); return ( - +
{isLoading ? ( diff --git a/apps/webapp/src/modules/actions/single-action.tsx b/apps/webapp/src/modules/actions/single-action.tsx index 12ed8543..ed3a987f 100644 --- a/apps/webapp/src/modules/actions/single-action.tsx +++ b/apps/webapp/src/modules/actions/single-action.tsx @@ -1,3 +1,5 @@ +import { ActionStatusEnum } from '@tegonhq/types'; +import { Button } from '@tegonhq/ui/components/button'; import { Loader } from '@tegonhq/ui/components/loader'; import { ScrollArea } from '@tegonhq/ui/components/scroll-area'; import { @@ -5,7 +7,6 @@ import { TooltipContent, TooltipTrigger, } from '@tegonhq/ui/components/tooltip'; -import { Button } from '@tegonhq/ui/components/ui/button'; import { Warning } from '@tegonhq/ui/icons'; import { useParams } from 'next/navigation'; @@ -35,16 +36,18 @@ export function SingleAction() {

{convertToTitleCase(action.name)}

- - - - - - This action is not configured. You can configure in settings. - - + {action.status === ActionStatusEnum.NEEDS_CONFIGURATION && ( + + + + + + This action is not configured. You can configure in settings. + + + )}

{latestAction?.description}

diff --git a/apps/webapp/src/modules/auth/auth.tsx b/apps/webapp/src/modules/auth/auth.tsx new file mode 100644 index 00000000..629b91a0 --- /dev/null +++ b/apps/webapp/src/modules/auth/auth.tsx @@ -0,0 +1,162 @@ +/* eslint-disable react/no-unescaped-entities */ +import { zodResolver } from '@hookform/resolvers/zod'; +import { RiMailFill } from '@remixicon/react'; +import { Button } from '@tegonhq/ui/components/button'; +import { + Form, + FormControl, + FormField, + FormItem, + FormMessage, +} from '@tegonhq/ui/components/form'; +import { Input } from '@tegonhq/ui/components/input'; +import { useToast } from '@tegonhq/ui/components/use-toast'; +import { ArrowLeft, Inbox } from '@tegonhq/ui/icons'; +import React from 'react'; +import { useForm } from 'react-hook-form'; +import { createCode } from 'supertokens-web-js/recipe/passwordless'; +import { z } from 'zod'; + +import { AuthLayout } from 'common/layouts/auth-layout'; +import { AuthGuard } from 'common/wrappers/auth-guard'; + +export const AuthSchema = z.object({ + email: z.string().email(), +}); + +export function Auth() { + const form = useForm>({ + resolver: zodResolver(AuthSchema), + defaultValues: { + email: '', + }, + }); + const [emailSent, setEmailSent] = React.useState(false); + const [loading, setLoading] = React.useState(false); + const { toast } = useToast(); + + const onSubmit = async ({ email }: { email: string }) => { + setLoading(true); + try { + const response = await createCode({ + email, + }); + + if (response.status === 'SIGN_IN_UP_NOT_ALLOWED') { + // the reason string is a user friendly message + // about what went wrong. It can also contain a support code which users + // can tell you so you know why their sign in / up was not allowed. + toast({ + variant: 'destructive', + title: 'Error!', + description: response.reason, + }); + } else { + setEmailSent(true); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (err: any) { + console.log(err); + if (err.isSuperTokensGeneralError === true) { + // this may be a custom error message sent from the API by you, + toast({ + variant: 'destructive', + title: 'Error!', + description: err.message, + }); + } else { + toast({ + variant: 'destructive', + title: 'Error!', + description: 'Oops! Something went wrong.', + }); + } + } + + setLoading(false); + }; + + if (emailSent) { + return ( + +
+
+

We've sent you a magic link

+ +
+ We sent you an email which contains a magic link that will log you + in to your account. +
+
+
+ +
+
+
+ ); + } + + return ( + +
+

Welcome

+
+ Create an account or login +
+ +
+
+ + ( + + + + + + + + )} + /> + +
+ +
+ + +
+ +
+ By clicking continue, you agree to our Terms of Service and Privacy + Policy. +
+
+
+ ); +} + +Auth.getLayout = function getLayout(page: React.ReactElement) { + return {page}; +}; diff --git a/apps/webapp/src/modules/auth/index.ts b/apps/webapp/src/modules/auth/index.ts index fbadf52d..021b1ce8 100644 --- a/apps/webapp/src/modules/auth/index.ts +++ b/apps/webapp/src/modules/auth/index.ts @@ -1,2 +1,2 @@ -export * from './signin'; -export * from './signup'; +export * from './auth'; +export * from './verify'; diff --git a/apps/webapp/src/modules/auth/invites/index.ts b/apps/webapp/src/modules/auth/invites/index.ts deleted file mode 100644 index 4ae4f2ed..00000000 --- a/apps/webapp/src/modules/auth/invites/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './invites'; diff --git a/apps/webapp/src/modules/auth/invites/invites.tsx b/apps/webapp/src/modules/auth/invites/invites.tsx deleted file mode 100644 index db98fe82..00000000 --- a/apps/webapp/src/modules/auth/invites/invites.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { AvatarText } from '@tegonhq/ui/components/avatar'; -import { Button } from '@tegonhq/ui/components/button'; -import { useToast } from '@tegonhq/ui/components/use-toast'; -import { useRouter } from 'next/router'; -import React from 'react'; -import { SessionAuth, signOut } from 'supertokens-auth-react/recipe/session'; - -import { AuthLayout } from 'common/layouts/auth-layout'; -import type { Invite } from 'common/types'; -import { UserDataWrapper } from 'common/wrappers/user-data-wrapper'; - -import { useInviteActionMutation } from 'services/workspace'; - -import { UserContext } from 'store/user-context'; - -export function Invites() { - const context = React.useContext(UserContext); - const { toast } = useToast(); - const router = useRouter(); - const { mutate: inviteAction, isLoading } = useInviteActionMutation({ - onSuccess: (data: Invite) => { - if (data.status === 'ACCEPTED') { - router.replace('/'); - toast({ - title: 'Invitation accepted', - description: 'Current invitation for the workspace has been accepted', - }); - } - }, - }); - - React.useEffect(() => { - if (context?.workspaces.length > 0) { - router.replace(`/${context.workspaces[0].slug}`); - } else if (context?.invites.length === 0) { - router.replace(`/waitlist`); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [context?.workspaces]); - - const onAction = (accept: boolean, inviteId: string) => { - inviteAction({ - accept, - inviteId, - }); - }; - - return ( - -
-
-

Join the workspaces

-

- You have been invited to these workspaces -

- -
- {context.invites.map((invite: Invite) => { - return ( -
-
- - {invite.workspace.name} -
- -
- - -
-
- ); - })} -
-
- -
-
- ); -} - -Invites.getLayout = function getLayout(page: React.ReactElement) { - return ( - - {page} - - ); -}; diff --git a/apps/webapp/src/modules/auth/request-forgot-password.tsx b/apps/webapp/src/modules/auth/request-forgot-password.tsx deleted file mode 100644 index 3b412073..00000000 --- a/apps/webapp/src/modules/auth/request-forgot-password.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import type { z } from 'zod'; - -import { zodResolver } from '@hookform/resolvers/zod'; -import { Button } from '@tegonhq/ui/components/button'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@tegonhq/ui/components/form'; -import { Input } from '@tegonhq/ui/components/input'; -import { useToast } from '@tegonhq/ui/components/use-toast'; -import { useForm } from 'react-hook-form'; - -import { AuthLayout } from 'common/layouts/auth-layout'; -import { AuthGuard } from 'common/wrappers/auth-guard'; - -import { - RequestForgotPasswordSchema, - useRequestForgotPasswordMutation, -} from 'services/auth'; - -export function RequestForgotPassword() { - const form = useForm>({ - resolver: zodResolver(RequestForgotPasswordSchema), - defaultValues: { - email: '', - }, - }); - const { toast } = useToast(); - const { mutate: requestForgotPassword, isLoading } = - useRequestForgotPasswordMutation({ - onSuccess: () => { - toast({ - title: 'Forgot Password', - description: - 'We have sent the details to reset yout password to your email', - }); - }, - - onError: (message: string) => { - toast({ - title: 'Forgot Password', - variant: 'destructive', - description: message, - }); - }, - }); - - function onSubmit(values: z.infer) { - requestForgotPassword({ - email: values.email, - }); - } - - return ( - -
-

Forgot password

-
- No worries! We’ll get you rolling again in no time. -
- -
- - ( - - Email - - - - - - - )} - /> - - - - -
-
- ); -} - -RequestForgotPassword.getLayout = function getLayout(page: React.ReactElement) { - return {page}; -}; diff --git a/apps/webapp/src/modules/auth/reset-password.tsx b/apps/webapp/src/modules/auth/reset-password.tsx deleted file mode 100644 index f42dc5c0..00000000 --- a/apps/webapp/src/modules/auth/reset-password.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import type { z } from 'zod'; - -import { zodResolver } from '@hookform/resolvers/zod'; -import { Button } from '@tegonhq/ui/components/button'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@tegonhq/ui/components/form'; -import { Input } from '@tegonhq/ui/components/input'; -import { useToast } from '@tegonhq/ui/components/use-toast'; -import { useRouter } from 'next/router'; -import { useForm } from 'react-hook-form'; - -import { AuthLayout } from 'common/layouts/auth-layout'; -import { AuthGuard } from 'common/wrappers/auth-guard'; - -import { ResetPasswordSchema, useResetPasswordMutation } from 'services/auth'; - -export function ResetPassword() { - const { - query: { token }, - push, - } = useRouter(); - const form = useForm>({ - resolver: zodResolver(ResetPasswordSchema), - defaultValues: { - password: '', - }, - }); - const { toast } = useToast(); - const { mutate: requestForgotPassword, isLoading } = useResetPasswordMutation( - { - onSuccess: () => { - toast({ - title: 'Reset Password', - description: 'We have reset your password.', - }); - push('/auth/signin'); - }, - onError: (message: string) => { - toast({ - title: 'Reset Password', - description: message, - variant: 'destructive', - }); - }, - }, - ); - - function onSubmit(values: z.infer) { - requestForgotPassword({ - password: values.password, - token: token as string, - }); - } - - return ( - -
-

Reset password

-
- Kindly enter the new password -
- -
- - ( - - New password - - - - - - - )} - /> - - - - -
-
- ); -} - -ResetPassword.getLayout = function getLayout(page: React.ReactElement) { - return {page}; -}; diff --git a/apps/webapp/src/modules/auth/signin-form.tsx b/apps/webapp/src/modules/auth/signin-form.tsx deleted file mode 100644 index 962dbb5f..00000000 --- a/apps/webapp/src/modules/auth/signin-form.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { zodResolver } from '@hookform/resolvers/zod'; -import { Button, buttonVariants } from '@tegonhq/ui/components/button'; -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from '@tegonhq/ui/components/form'; -import { Input } from '@tegonhq/ui/components/input'; -import { cn } from '@tegonhq/ui/lib/utils'; -import Link from 'next/link'; -import { useRouter } from 'next/router'; -import { useForm } from 'react-hook-form'; -import { z } from 'zod'; - -import { SignInSchema, useSignInMutation } from 'services/auth'; - -export function SignForm() { - const router = useRouter(); - const { - query: { redirectToPath }, - } = router; - const form = useForm>({ - resolver: zodResolver(SignInSchema), - defaultValues: { - email: '', - password: '', - }, - }); - - const { mutate: signinMutate, isLoading } = useSignInMutation({ - onSuccess: (data) => { - if (data.status !== 'OK') { - form.setError( - 'email', - { - message: 'Not valid credentials', - }, - { shouldFocus: true }, - ); - } else { - router.replace(redirectToPath ? (redirectToPath as string) : '/'); - } - }, - }); - - function onSubmit(values: z.infer) { - signinMutate(values); - } - - return ( -
- - ( - - Email - - - - - - - )} - /> - - ( - - Password - - - - - - - )} - /> - - - Forgot password? - - -
- - - - Create a new account - -
- - - ); -} diff --git a/apps/webapp/src/modules/auth/signin.tsx b/apps/webapp/src/modules/auth/signin.tsx deleted file mode 100644 index b9b73642..00000000 --- a/apps/webapp/src/modules/auth/signin.tsx +++ /dev/null @@ -1,64 +0,0 @@ -'use client'; - -import { RiGoogleFill } from '@remixicon/react'; -import { Button } from '@tegonhq/ui/components/button'; -import { Separator } from '@tegonhq/ui/components/separator'; -import getConfig from 'next/config'; -import { getAuthorisationURLWithQueryParamsAndSetState } from 'supertokens-auth-react/recipe/thirdpartyemailpassword'; - -import { AuthLayout } from 'common/layouts/auth-layout'; -import { AuthGuard } from 'common/wrappers/auth-guard'; - -import { SignForm } from './signin-form'; - -const { publicRuntimeConfig } = getConfig(); - -export function SignIn() { - async function googleSignInClicked() { - try { - const authUrl = await getAuthorisationURLWithQueryParamsAndSetState({ - thirdPartyId: 'google', - - frontendRedirectURI: `${publicRuntimeConfig.NEXT_PUBLIC_BASE_HOST}/auth/callback/google`, - }); - - window.location.assign(authUrl); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - console.error(err.message); - } else { - console.error('Oops! Something went wrong.'); - } - } - } - - return ( - -
-

Sign in

-
- to continue to Tegon -
- - - - - - - -
- By clicking continue, you agree to our Terms of Service and Privacy - Policy. -
-
-
- ); -} - -SignIn.getLayout = function getLayout(page: React.ReactElement) { - return {page}; -}; diff --git a/apps/webapp/src/modules/auth/signup.tsx b/apps/webapp/src/modules/auth/signup.tsx deleted file mode 100644 index 38e8853c..00000000 --- a/apps/webapp/src/modules/auth/signup.tsx +++ /dev/null @@ -1,57 +0,0 @@ -'use client'; - -import { RiGoogleFill } from '@remixicon/react'; -import { Button } from '@tegonhq/ui/components/button'; -import getConfig from 'next/config'; -import { getAuthorisationURLWithQueryParamsAndSetState } from 'supertokens-auth-react/recipe/thirdpartyemailpassword'; - -import { AuthLayout } from 'common/layouts/auth-layout'; -import { AuthGuard } from 'common/wrappers/auth-guard'; - -const { publicRuntimeConfig } = getConfig(); - -export function SignUp() { - async function googleSignInClicked() { - try { - const authUrl = await getAuthorisationURLWithQueryParamsAndSetState({ - thirdPartyId: 'google', - - frontendRedirectURI: `${publicRuntimeConfig.NEXT_PUBLIC_BASE_HOST}/auth/callback/google`, - }); - - window.location.assign(authUrl); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } catch (err: any) { - if (err.isSuperTokensGeneralError === true) { - // this may be a custom error message sent from the API by you. - console.error(err.message); - } else { - console.error('Oops! Something went wrong.'); - } - } - } - - return ( - -
-

Sign up

-
- to continue to Tegon -
- - - -
- By clicking continue, you agree to our Terms of Service and Privacy - Policy. -
-
-
- ); -} - -SignUp.getLayout = function getLayout(page: React.ReactElement) { - return {page}; -}; diff --git a/apps/webapp/src/modules/auth/verify.tsx b/apps/webapp/src/modules/auth/verify.tsx new file mode 100644 index 00000000..c43c095b --- /dev/null +++ b/apps/webapp/src/modules/auth/verify.tsx @@ -0,0 +1,87 @@ +import { Loader } from '@tegonhq/ui/components/loader'; +import { useToast } from '@tegonhq/ui/components/use-toast'; +import { useRouter } from 'next/router'; +import React from 'react'; +import { + consumeCode, + clearLoginAttemptInfo, +} from 'supertokens-web-js/recipe/passwordless'; + +import { AuthGuard } from 'common/wrappers/auth-guard'; + +export function Verify() { + const router = useRouter(); + const { + query: { redirectToPath }, + } = router; + const { toast } = useToast(); + + async function handleMagicLinkClicked() { + try { + const response = await consumeCode(); + + if (response.status === 'OK') { + // we clear the login attempt info that was added when the createCode function + // was called since the login was successful. + await clearLoginAttemptInfo(); + if ( + response.createdNewRecipeUser && + response.user.loginMethods.length === 1 + ) { + toast({ + title: 'Success!', + description: 'Sign up successfully!', + }); + } else { + toast({ + title: 'Success!', + description: 'Sign in successfully!', + }); + } + router.replace(redirectToPath ? (redirectToPath as string) : '/'); + } else { + // this can happen if the magic link has expired or is invalid + // or if it was denied due to security reasons in case of automatic account linking + + // we clear the login attempt info that was added when the createCode function + // was called - so that if the user does a page reload, they will now see the + // enter email / phone UI again. + await clearLoginAttemptInfo(); + toast({ + title: 'Error!', + description: 'Login failed. Please try again', + }); + router.replace('/auth'); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } catch (err: any) { + if (err.isSuperTokensGeneralError === true) { + toast({ + title: 'Error!', + description: err.message, + }); + // this may be a custom error message sent from the API by you. + } else { + toast({ + title: 'Error!', + description: 'Oops! Something went wrong.', + }); + } + } + } + + React.useEffect(() => { + handleMagicLinkClicked(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( +
+ +
+ ); +} + +Verify.getLayout = function getLayout(page: React.ReactElement) { + return {page}; +}; diff --git a/apps/webapp/src/modules/invites/invites.tsx b/apps/webapp/src/modules/invites/invites.tsx index db98fe82..d75b1c9f 100644 --- a/apps/webapp/src/modules/invites/invites.tsx +++ b/apps/webapp/src/modules/invites/invites.tsx @@ -33,7 +33,7 @@ export function Invites() { if (context?.workspaces.length > 0) { router.replace(`/${context.workspaces[0].slug}`); } else if (context?.invites.length === 0) { - router.replace(`/waitlist`); + router.replace(`/onboarding`); } // eslint-disable-next-line react-hooks/exhaustive-deps @@ -93,7 +93,7 @@ export function Invites() { onClick={async () => { await signOut(); - router.replace('/auth/signin'); + router.replace('/auth'); }} > Log out diff --git a/apps/webapp/src/modules/issues/components/issue-board-item/issue-board-item.tsx b/apps/webapp/src/modules/issues/components/issue-board-item/issue-board-item.tsx index a09a39d0..b0f49333 100644 --- a/apps/webapp/src/modules/issues/components/issue-board-item/issue-board-item.tsx +++ b/apps/webapp/src/modules/issues/components/issue-board-item/issue-board-item.tsx @@ -69,7 +69,7 @@ export const BoardIssueItem = observer( return ( { push(`/${workspaceSlug}/issue/${team.identifier}-${issue.number}`); }} diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/comments-activity.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/comments-activity.tsx index 973cd528..f8649a01 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/comments-activity.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/comments-activity.tsx @@ -1,4 +1,5 @@ import { Timeline } from '@tegonhq/ui/components/timeline'; +import { sort } from 'fast-sort'; import { observer } from 'mobx-react-lite'; import type { User } from 'common/types'; @@ -16,7 +17,10 @@ export const CommentsActivity = observer(() => { const issue = useIssueData(); const { commentsStore } = useContextStore(); - const comments = commentsStore.getComments(issue.id); + const comments = sort(commentsStore.getComments(issue.id)).asc( + (comment: IssueCommentType) => new Date(comment.createdAt), + ) as IssueCommentType[]; + const { usersData, isLoading } = useUsersData(issue.teamId); function getUserData(userId: string) { diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/generic-comment-activity.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/generic-comment-activity.tsx index 3528d879..18f62557 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/generic-comment-activity.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/generic-comment-activity.tsx @@ -24,6 +24,7 @@ import { UserContext } from 'store/user-context'; import { EditComment } from './edit-comment'; import { ReplyComment } from './reply-comment'; +import { getUserDetails } from '../issue-activity/user-activity-utils'; export interface GenericCommentActivityProps { comment: IssueCommentType; @@ -77,7 +78,9 @@ export function GenericCommentActivity(props: GenericCommentActivityProps) { >
{user ? ( - {user?.username} + + {getUserDetails(sourceMetadata, user).fullname} + ) : ( {sourceMetadata.userDisplayName} via {sourceMetadata.type} @@ -142,7 +145,8 @@ export function GenericCommentActivity(props: GenericCommentActivityProps) {
{ if (commentValue !== '') { + const parseCommentValue = getTiptapJSON(commentValue); + createIssueComment({ - body: commentValue, + body: parseCommentValue, issueId: issueData.id, }); } - setCommentValue(''); + setCommentValue(undefined); }; return ( diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/reply-comment.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/reply-comment.tsx index efa38267..066fa499 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/reply-comment.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/reply-comment.tsx @@ -8,6 +8,8 @@ import { import { SendLine } from '@tegonhq/ui/icons'; import * as React from 'react'; +import { getTiptapJSON } from 'common'; + import { useIssueData } from 'hooks/issues'; import { useCreateIssueCommentMutation } from 'services/issues'; @@ -26,12 +28,15 @@ export function ReplyComment({ issueCommentId }: ReplyCommentProps) { const [showReplyButton, setShowReplyButton] = React.useState(false); const onSubmit = () => { - createIssueComment({ - body: commentValue, - issueId: issueData.id, - parentId: issueCommentId, - }); - setCommentValue(''); + if (commentValue !== '') { + const parseCommentValue = getTiptapJSON(commentValue); + createIssueComment({ + body: parseCommentValue, + issueId: issueData.id, + parentId: issueCommentId, + }); + } + setCommentValue(undefined); }; return ( @@ -50,7 +55,7 @@ export function ReplyComment({ issueCommentId }: ReplyCommentProps) { !commentValue && setShowReplyButton(false); }} onChange={(e) => setCommentValue(e)} - className="w-full bg-transparent px-3 py-2 pt-0 grow" + className="w-full bg-transparent px-3 py-2 pt-0 grow text-foreground" > diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/sync-comment-activity.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/sync-comment-activity.tsx index d6a8eef8..7da0291c 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/sync-comment-activity.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/comments-activity/sync-comment-activity.tsx @@ -67,13 +67,14 @@ export function SyncCommentActivity({
{childComments.length > 0 && ( -
+
{childComments.map( (subComment: IssueCommentType, index: number) => (
0) { localItems.push( 0) { localItems.push( {
- {issueCreatedUser.username} + {issueCreatedUser.fullname} created the issue
diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/label-activity.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/label-activity.tsx index 7b1aeee8..47db249d 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/label-activity.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/label-activity.tsx @@ -11,13 +11,13 @@ import { useContextStore } from 'store/global-context-provider'; interface LabelActivityProps { issueHistory: IssueHistoryType; added: boolean; - username: string; + fullname: string; showTime?: boolean; } export function LabelActivity({ added, issueHistory, - username, + fullname, showTime = false, }: LabelActivityProps) { const { labelsStore } = useContextStore(); @@ -38,7 +38,7 @@ export function LabelActivity({
- {username} + {fullname} added label
@@ -67,7 +67,7 @@ export function LabelActivity({
- {username} + {fullname} removed label
diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/linked-issue-activity.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/linked-issue-activity.tsx index f4f7c94e..a4cadfb0 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/linked-issue-activity.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/linked-issue-activity.tsx @@ -50,7 +50,7 @@ export function LinkedIssueActivity({ linkedIssue }: LinkedIssueActivityProps) { { getUserDetails(sourceData, getUserData(linkedIssue.createdById)) - .username + .fullname } linked diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/priority-activity.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/priority-activity.tsx index 178f3d5e..aa8ddf23 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/priority-activity.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/priority-activity.tsx @@ -8,12 +8,12 @@ import { Priorities, type IssueHistoryType } from 'common/types'; interface PriorityActivityProps { issueHistory: IssueHistoryType; - username: string; + fullname: string; showTime?: boolean; } export function PriorityActivity({ issueHistory, - username, + fullname, showTime = false, }: PriorityActivityProps) { const priorityText = Priorities[issueHistory.toPriority]; @@ -35,7 +35,7 @@ export function PriorityActivity({ />
- {username} + {fullname} set priority to {priorityText} diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/related-activity.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/related-activity.tsx index af1165d7..ebf7c102 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/related-activity.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/related-activity.tsx @@ -13,7 +13,7 @@ import { useContextStore } from 'store/global-context-provider'; interface StatusActivityProps { issueHistory: IssueHistoryType; - username: string; + fullname: string; showTime?: boolean; } @@ -43,7 +43,7 @@ const ICON_MAP: Record = { export function RelatedActivity({ issueHistory, - username, + fullname, showTime = false, }: StatusActivityProps) { const relatedChanges = issueHistory.relationChanges; @@ -59,7 +59,7 @@ export function RelatedActivity({ if (relatedChanges.type === IssueRelationEnum.RELATED) { return (
- {username} + {fullname} {relatedChanges.isDeleted ? 'removed' : 'added'} related issue @@ -76,7 +76,7 @@ export function RelatedActivity({ if (relatedChanges.type === IssueRelationEnum.BLOCKED) { return (
- {username} + {fullname} {relatedChanges.isDeleted ? 'removed' : 'marked'} this issue as being blocked by @@ -94,7 +94,7 @@ export function RelatedActivity({ if (relatedChanges.type === IssueRelationEnum.BLOCKS) { return (
- {username} + {fullname} {relatedChanges.isDeleted ? 'removed' : 'marked'} this issue as blocking @@ -112,7 +112,7 @@ export function RelatedActivity({ if (relatedChanges.type === IssueRelationEnum.DUPLICATE_OF) { return (
- {username} + {fullname} {relatedChanges.isDeleted ? 'removed' : 'marked'} this issue as duplicate of @@ -130,7 +130,7 @@ export function RelatedActivity({ if (relatedChanges.type === IssueRelationEnum.DUPLICATE) { return (
- {username} + {fullname} {relatedChanges.isDeleted ? 'removed' : 'marked'} this issue as duplicated by diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/status-activity.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/status-activity.tsx index 106d7259..9c6308d0 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/status-activity.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/status-activity.tsx @@ -11,11 +11,11 @@ import { useTeamWorkflows } from 'hooks/workflows'; interface StatusActivityProps { issueHistory: IssueHistoryType; - username: string; + fullname: string; showTime?: boolean; } export const StatusActivity = observer( - ({ issueHistory, username, showTime = false }: StatusActivityProps) => { + ({ issueHistory, fullname, showTime = false }: StatusActivityProps) => { const currentTeam = useCurrentTeam(); const workflows = useTeamWorkflows(currentTeam.identifier); @@ -46,7 +46,7 @@ export const StatusActivity = observer( {fromWorkflow ? ( <> - {username} + {fullname} changed status from @@ -57,7 +57,7 @@ export const StatusActivity = observer( ) : ( <> - {username} + {fullname} changed status to diff --git a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/user-activity-utils.tsx b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/user-activity-utils.tsx index f947f25c..077cb757 100644 --- a/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/user-activity-utils.tsx +++ b/apps/webapp/src/modules/issues/single-issue/left-side/activity/issue-activity/user-activity-utils.tsx @@ -6,14 +6,13 @@ export function getUserDetails( user?: User, // eslint-disable-next-line @typescript-eslint/no-explicit-any ): any { - if (user) { - return user; - } - - const name = sourceMetadata?.userDisplayName ?? sourceMetadata.type; + const name = + sourceMetadata && sourceMetadata.userDisplayName + ? ` (${sourceMetadata?.userDisplayName})` + : ''; return { - fullname: name, - username: name, + fullname: `${user.fullname}${name}`, + username: user.username, }; } diff --git a/apps/webapp/src/modules/issues/triage/left-side/triage-category.tsx b/apps/webapp/src/modules/issues/triage/left-side/triage-category.tsx index 3acc2155..d9ba1e6d 100644 --- a/apps/webapp/src/modules/issues/triage/left-side/triage-category.tsx +++ b/apps/webapp/src/modules/issues/triage/left-side/triage-category.tsx @@ -83,9 +83,9 @@ export const TriageCategory = observer(
{ push( diff --git a/apps/webapp/src/modules/issues/triage/left-side/triage-other-category.tsx b/apps/webapp/src/modules/issues/triage/left-side/triage-other-category.tsx index 453ffc71..f5286617 100644 --- a/apps/webapp/src/modules/issues/triage/left-side/triage-other-category.tsx +++ b/apps/webapp/src/modules/issues/triage/left-side/triage-other-category.tsx @@ -77,9 +77,9 @@ export const TriageOtherCategory = observer(
{ push( diff --git a/apps/webapp/src/modules/onboarding/index.ts b/apps/webapp/src/modules/onboarding/index.ts new file mode 100644 index 00000000..6620955c --- /dev/null +++ b/apps/webapp/src/modules/onboarding/index.ts @@ -0,0 +1 @@ +export * from './onboarding'; diff --git a/apps/webapp/src/modules/onboarding/onboarding-form.tsx b/apps/webapp/src/modules/onboarding/onboarding-form.tsx new file mode 100644 index 00000000..378352e9 --- /dev/null +++ b/apps/webapp/src/modules/onboarding/onboarding-form.tsx @@ -0,0 +1,135 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import { Button } from '@tegonhq/ui/components/button'; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@tegonhq/ui/components/form'; +import { Input } from '@tegonhq/ui/components/input'; +import { useToast } from '@tegonhq/ui/components/use-toast'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; + +import { + useCreateInitialResourcesMutation, + type CreateInitialResourcesDto, +} from 'services/workspace'; + +export const OnboardingSchema = z.object({ + fullname: z.string(), + workspaceName: z.string(), + teamName: z.string(), + teamIdentifier: z.string(), +}); + +export function OnboardingForm() { + const { toast } = useToast(); + + const { mutate: createInitialResources, isLoading } = + useCreateInitialResourcesMutation({ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onError: (e: any) => { + toast({ + variant: 'destructive', + title: 'Error!', + description: e.message, + }); + }, + }); + + const form = useForm>({ + resolver: zodResolver(OnboardingSchema), + defaultValues: { + fullname: '', + workspaceName: '', + teamName: '', + teamIdentifier: '', + }, + }); + + const onSubmit = (values: CreateInitialResourcesDto) => { + createInitialResources(values); + }; + + return ( +
+ + ( + + Full name + + + + + + + )} + /> + ( + + Workspace name + + + + + + + )} + /> + ( + + Team name + + + + + + + )} + /> + ( + + Team identifier + + + + + + + + )} + /> + +
+ +
+ + + ); +} diff --git a/apps/webapp/src/modules/onboarding/onboarding.tsx b/apps/webapp/src/modules/onboarding/onboarding.tsx new file mode 100644 index 00000000..1a6e3865 --- /dev/null +++ b/apps/webapp/src/modules/onboarding/onboarding.tsx @@ -0,0 +1,53 @@ +/* eslint-disable react/no-unescaped-entities */ + +import { useRouter } from 'next/router'; +import React from 'react'; +import { SessionAuth } from 'supertokens-auth-react/recipe/session'; + +import { AuthLayout } from 'common/layouts/auth-layout'; +import { UserDataWrapper } from 'common/wrappers/user-data-wrapper'; + +import { UserContext } from 'store/user-context'; + +import { OnboardingForm } from './onboarding-form'; + +export function Onboarding() { + const context = React.useContext(UserContext); + const router = useRouter(); + + React.useEffect(() => { + if (context?.workspaces.length > 0) { + router.replace(`/${context.workspaces[0].slug}`); + } + + // Check if they have invites + if (context?.invites.length > 0) { + router.replace(`/invites`); + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [context?.workspaces]); + + return ( + +
+

✋ Welcome to Tegon

+
+ We just need to take couple of information before we proceed +
+ +
+ +
+
+
+ ); +} + +Onboarding.getLayout = function getLayout(page: React.ReactElement) { + return ( + + {page} + + ); +}; diff --git a/apps/webapp/src/modules/settings/workspace-settings/actions/action/action.tsx b/apps/webapp/src/modules/settings/workspace-settings/actions/action/action.tsx index a35844f8..9bcd477f 100644 --- a/apps/webapp/src/modules/settings/workspace-settings/actions/action/action.tsx +++ b/apps/webapp/src/modules/settings/workspace-settings/actions/action/action.tsx @@ -18,6 +18,7 @@ import { Header } from 'modules/settings/header'; import { SettingSection } from 'modules/settings/setting-section'; import { SettingsLayout } from 'common/layouts/settings-layout'; +import { ActionAccessGuard } from 'common/wrappers/action-access-guard'; import { useGetExternalActionDataQuery } from 'services/action'; @@ -113,7 +114,9 @@ export const Action = () => { Action.getLayout = function getLayout(page: React.ReactElement) { return ( -
{page}
+
+ {page} +
); }; diff --git a/apps/webapp/src/modules/settings/workspace-settings/actions/action/components/action.tsx b/apps/webapp/src/modules/settings/workspace-settings/actions/action/components/action.tsx index d0c56ddc..d9180b7d 100644 --- a/apps/webapp/src/modules/settings/workspace-settings/actions/action/components/action.tsx +++ b/apps/webapp/src/modules/settings/workspace-settings/actions/action/components/action.tsx @@ -23,8 +23,8 @@ export function Action({ action, noBorder }: ActionProps) {
{ push(`/${workspaceSlug}/actions/${action.slug}`); diff --git a/apps/webapp/src/modules/settings/workspace-settings/actions/action/configuration.tsx b/apps/webapp/src/modules/settings/workspace-settings/actions/action/configuration.tsx index b8a4b778..9f552ecb 100644 --- a/apps/webapp/src/modules/settings/workspace-settings/actions/action/configuration.tsx +++ b/apps/webapp/src/modules/settings/workspace-settings/actions/action/configuration.tsx @@ -2,6 +2,7 @@ import type { FieldConfig, FormSchema } from './components/types'; import { Button } from '@tegonhq/ui/components/button'; import { Form } from '@tegonhq/ui/components/form'; +import { useToast } from '@tegonhq/ui/components/use-toast'; import { useParams } from 'next/navigation'; import React from 'react'; import { useForm } from 'react-hook-form'; @@ -24,12 +25,22 @@ const getData = (action: ActionType) => { export const Configuration = ({ schema }: { schema: FormSchema }) => { const { actionSlug } = useParams(); + const { toast } = useToast(); const { actionsStore } = useContextStore(); const action = actionsStore.getAction(actionSlug); const inputs = getData(action)?.inputs; - const { mutate: updateActionInputs } = useUpdateActionInputsMutation({}); + const { mutate: updateActionInputs, isLoading } = + useUpdateActionInputsMutation({ + onSuccess: () => { + toast({ + variant: 'success', + title: 'Action updated!', + description: 'Updated the action settings successfully', + }); + }, + }); // const zodSchema = generateZodSchema(schema); const form = useForm({ defaultValues: inputs, @@ -60,7 +71,12 @@ export const Configuration = ({ schema }: { schema: FormSchema }) => {
))}
-
diff --git a/apps/webapp/src/modules/settings/workspace-settings/actions/actions.tsx b/apps/webapp/src/modules/settings/workspace-settings/actions/actions.tsx index 91977c60..b5953224 100644 --- a/apps/webapp/src/modules/settings/workspace-settings/actions/actions.tsx +++ b/apps/webapp/src/modules/settings/workspace-settings/actions/actions.tsx @@ -10,6 +10,7 @@ import { AddLine } from '@tegonhq/ui/icons'; import { Header } from 'modules/settings/header'; import { SettingsLayout } from 'common/layouts/settings-layout'; +import { ActionAccessGuard } from 'common/wrappers/action-access-guard'; import { useGetAllActionsQuery, type ActionSource } from 'services/action'; @@ -55,7 +56,9 @@ Actions.getLayout = function getLayout(page: React.ReactElement) {
-
{page}
+
+ {page} +
diff --git a/apps/webapp/src/modules/settings/workspace-settings/integrations/workspace-auth.tsx b/apps/webapp/src/modules/settings/workspace-settings/integrations/workspace-auth.tsx index c5010e31..5fb9b91e 100644 --- a/apps/webapp/src/modules/settings/workspace-settings/integrations/workspace-auth.tsx +++ b/apps/webapp/src/modules/settings/workspace-settings/integrations/workspace-auth.tsx @@ -38,7 +38,10 @@ export function WorkspaceAuth({ integrationDefinition }: WorkspaceAuthProps) { <>

Connected organization account

- Your organization {integrationDefinition.name} + Your organization{' '} + + {integrationDefinition.name} + account is connected

diff --git a/apps/webapp/src/modules/settings/workspace-settings/members/add-member-dialog.tsx b/apps/webapp/src/modules/settings/workspace-settings/members/add-member-dialog.tsx index 90d2eae2..a5319d1c 100644 --- a/apps/webapp/src/modules/settings/workspace-settings/members/add-member-dialog.tsx +++ b/apps/webapp/src/modules/settings/workspace-settings/members/add-member-dialog.tsx @@ -80,7 +80,7 @@ export function AddMemberDialog({ setDialogOpen }: AddMemberDialogProps) {
Add member
-
+
Invite member to the workspace
diff --git a/apps/webapp/src/pages/auth/forgot-password.tsx b/apps/webapp/src/pages/auth/forgot-password.tsx deleted file mode 100644 index cd56e152..00000000 --- a/apps/webapp/src/pages/auth/forgot-password.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { RequestForgotPassword } from 'modules/auth/request-forgot-password'; - -export default RequestForgotPassword; diff --git a/apps/webapp/src/pages/auth/index.tsx b/apps/webapp/src/pages/auth/index.tsx new file mode 100644 index 00000000..2db245d5 --- /dev/null +++ b/apps/webapp/src/pages/auth/index.tsx @@ -0,0 +1,3 @@ +import { Auth } from 'modules/auth'; + +export default Auth; diff --git a/apps/webapp/src/pages/auth/reset-password.tsx b/apps/webapp/src/pages/auth/reset-password.tsx deleted file mode 100644 index 09d3e403..00000000 --- a/apps/webapp/src/pages/auth/reset-password.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { ResetPassword } from 'modules/auth/reset-password'; - -export default ResetPassword; diff --git a/apps/webapp/src/pages/auth/signin.tsx b/apps/webapp/src/pages/auth/signin.tsx deleted file mode 100644 index 3c6e81c1..00000000 --- a/apps/webapp/src/pages/auth/signin.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { SignIn } from 'modules/auth'; - -export default SignIn; diff --git a/apps/webapp/src/pages/auth/signup.tsx b/apps/webapp/src/pages/auth/signup.tsx deleted file mode 100644 index 5aac017e..00000000 --- a/apps/webapp/src/pages/auth/signup.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { SignUp } from 'modules/auth'; - -export default SignUp; diff --git a/apps/webapp/src/pages/auth/verify.tsx b/apps/webapp/src/pages/auth/verify.tsx new file mode 100644 index 00000000..5625f4b8 --- /dev/null +++ b/apps/webapp/src/pages/auth/verify.tsx @@ -0,0 +1,3 @@ +import { Verify } from 'modules/auth'; + +export default Verify; diff --git a/apps/webapp/src/pages/index.tsx b/apps/webapp/src/pages/index.tsx index 275e8662..419107c4 100644 --- a/apps/webapp/src/pages/index.tsx +++ b/apps/webapp/src/pages/index.tsx @@ -23,7 +23,7 @@ export default function Home() { // Check if they have invites else { - router.replace(`/waitlist`); + router.replace(`/onboarding`); } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/apps/webapp/src/pages/onboarding.tsx b/apps/webapp/src/pages/onboarding.tsx new file mode 100644 index 00000000..8dcc5272 --- /dev/null +++ b/apps/webapp/src/pages/onboarding.tsx @@ -0,0 +1,3 @@ +import { Onboarding } from 'modules/onboarding'; + +export default Onboarding; diff --git a/apps/webapp/src/pages/waitlist.tsx b/apps/webapp/src/pages/waitlist.tsx deleted file mode 100644 index 2e962067..00000000 --- a/apps/webapp/src/pages/waitlist.tsx +++ /dev/null @@ -1,59 +0,0 @@ -/* eslint-disable @next/next/no-sync-scripts */ -import { Button } from '@tegonhq/ui/components/button'; -import Logo from '@tegonhq/ui/components/logo'; -import { Widget } from '@typeform/embed-react'; -import { useRouter } from 'next/router'; -import React from 'react'; -import { SessionAuth, signOut } from 'supertokens-auth-react/recipe/session'; - -import { UserDataWrapper } from 'common/wrappers/user-data-wrapper'; - -import { UserContext } from 'store/user-context'; - -export default function Waitlist() { - const context = React.useContext(UserContext); - const router = useRouter(); - - React.useEffect(() => { - if (context?.workspaces.length > 0) { - router.replace(`/${context.workspaces[0].slug}`); - } - - // Check if they have invites - if (context?.invites.length > 0) { - router.replace(`/invites`); - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [context?.workspaces]); - - return ( -
- -
- - -
-
- ); -} - -Waitlist.getLayout = function getLayout(page: React.ReactElement) { - return ( - - {page} - - ); -}; diff --git a/apps/webapp/src/services/auth/index.ts b/apps/webapp/src/services/auth/index.ts deleted file mode 100644 index 789c20fb..00000000 --- a/apps/webapp/src/services/auth/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './signin'; -export * from './request-forgot-password'; -export * from './reset-password'; diff --git a/apps/webapp/src/services/auth/request-forgot-password.ts b/apps/webapp/src/services/auth/request-forgot-password.ts deleted file mode 100644 index 69c00ebe..00000000 --- a/apps/webapp/src/services/auth/request-forgot-password.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { useMutation } from 'react-query'; -import { z } from 'zod'; - -import { ajaxPost } from 'services/utils'; - -interface UserInfo { - status: string; -} - -export const RequestForgotPasswordSchema = z.object({ - email: z.string().email('This is not a valid email').min(2).max(50), -}); - -export function requestForgotPassword( - params: z.infer, -) { - return ajaxPost({ - url: '/api/v1/users/forgot_password', - data: { - email: params.email, - }, - }); -} - -interface MutationParams { - onMutate?: () => void; - onSuccess?: (data: UserInfo) => void; - onError?: (error: string) => void; -} - -export function useRequestForgotPasswordMutation({ - onMutate, - onSuccess, - onError, -}: MutationParams) { - const onMutationTriggered = () => { - onMutate && onMutate(); - }; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const onMutationError = (errorResponse: any) => { - const errorText = errorResponse?.errors?.message || 'Error occured'; - - onError && onError(errorText); - }; - - const onMutationSuccess = (data: UserInfo) => { - onSuccess && onSuccess(data); - }; - - return useMutation(requestForgotPassword, { - onError: onMutationError, - onMutate: onMutationTriggered, - onSuccess: onMutationSuccess, - }); -} diff --git a/apps/webapp/src/services/auth/reset-password.ts b/apps/webapp/src/services/auth/reset-password.ts deleted file mode 100644 index f38068ba..00000000 --- a/apps/webapp/src/services/auth/reset-password.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { useMutation } from 'react-query'; -import { z } from 'zod'; - -import { ajaxPost } from 'services/utils'; - -interface UserInfo { - status: string; -} - -export const ResetPasswordSchema = z.object({ - password: z.string().min(4), -}); - -interface ResetPasswordProps extends z.infer { - token: string; -} - -export function resetPassword(params: ResetPasswordProps) { - return ajaxPost({ - url: `/api/v1/users/forgot_password/${params.token}`, - data: { - newPassword: params.password, - }, - }); -} - -interface MutationParams { - onMutate?: () => void; - onSuccess?: (data: UserInfo) => void; - onError?: (error: string) => void; -} - -export function useResetPasswordMutation({ - onMutate, - onSuccess, - onError, -}: MutationParams) { - const onMutationTriggered = () => { - onMutate && onMutate(); - }; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const onMutationError = (errorResponse: any) => { - const errorText = errorResponse?.errors?.message || 'Error occured'; - - onError && onError(errorText); - }; - - const onMutationSuccess = (data: UserInfo) => { - onSuccess && onSuccess(data); - }; - - return useMutation(resetPassword, { - onError: onMutationError, - onMutate: onMutationTriggered, - onSuccess: onMutationSuccess, - }); -} diff --git a/apps/webapp/src/services/auth/signin.ts b/apps/webapp/src/services/auth/signin.ts deleted file mode 100644 index 5ee2687b..00000000 --- a/apps/webapp/src/services/auth/signin.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { useMutation } from 'react-query'; -import { z } from 'zod'; - -import { ajaxPost } from 'services/utils'; - -export interface SignInParams { - email: string; - password: string; -} - -export interface UserInfo { - status: string; - user: User; -} - -export interface User { - email: string; - id: string; - timeJoined: number; -} - -export const SignInSchema = z.object({ - email: z.string().email('This is not a valid email').min(2).max(50), - password: z.string().min(4), -}); - -export function siginUser(params: z.infer) { - return ajaxPost({ - url: '/api/auth/signin', - data: { - formFields: [ - { - id: 'email', - value: params.email, - }, - { - id: 'password', - value: params.password, - }, - ], - }, - }); -} - -export interface MutationParams { - onMutate?: () => void; - onSuccess?: (data: UserInfo) => void; - onError?: (error: string) => void; -} - -export function useSignInMutation({ - onMutate, - onSuccess, - onError, -}: MutationParams) { - const onMutationTriggered = () => { - onMutate && onMutate(); - }; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const onMutationError = (errorResponse: any) => { - const errorText = errorResponse?.errors?.message || 'Error occured'; - - onError && onError(errorText); - }; - - const onMutationSuccess = (data: UserInfo) => { - onSuccess && onSuccess(data); - }; - - return useMutation(siginUser, { - onError: onMutationError, - onMutate: onMutationTriggered, - onSuccess: onMutationSuccess, - }); -} diff --git a/apps/webapp/src/services/auth/signup.ts b/apps/webapp/src/services/auth/signup.ts deleted file mode 100644 index 12f45f47..00000000 --- a/apps/webapp/src/services/auth/signup.ts +++ /dev/null @@ -1 +0,0 @@ -/** Copyright (c) 2024, Tegon, all rights reserved. **/ diff --git a/apps/webapp/src/services/workspace/create-initial-resources.tsx b/apps/webapp/src/services/workspace/create-initial-resources.tsx new file mode 100644 index 00000000..9697ec33 --- /dev/null +++ b/apps/webapp/src/services/workspace/create-initial-resources.tsx @@ -0,0 +1,59 @@ +import { useMutation, useQueryClient } from 'react-query'; + +import type { WorkspaceType } from 'common/types'; + +import { GetUserQuery } from 'services/users'; +import { ajaxPost } from 'services/utils'; + +export interface CreateInitialResourcesDto { + workspaceName: string; + fullname: string; + teamName: string; + teamIdentifier: string; +} + +export function createInitialResources( + createInitialResourcesDto: CreateInitialResourcesDto, +) { + return ajaxPost({ + url: `/api/v1/workspaces/onboarding`, + data: createInitialResourcesDto, + }); +} + +interface MutationParams { + onMutate?: () => void; + onSuccess?: (data: WorkspaceType) => void; + onError?: (error: string) => void; +} + +export function useCreateInitialResourcesMutation({ + onMutate, + onSuccess, + onError, +}: MutationParams) { + const queryClient = useQueryClient(); + + const onMutationTriggered = () => { + onMutate && onMutate(); + }; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const onMutationError = (errorResponse: any) => { + const errorText = errorResponse?.errors?.message || 'Error occured'; + + onError && onError(errorText); + }; + + const onMutationSuccess = (data: WorkspaceType) => { + queryClient.invalidateQueries({ queryKey: [GetUserQuery] }); + + onSuccess && onSuccess(data); + }; + + return useMutation(createInitialResources, { + onError: onMutationError, + onMutate: onMutationTriggered, + onSuccess: onMutationSuccess, + }); +} diff --git a/apps/webapp/src/services/workspace/index.ts b/apps/webapp/src/services/workspace/index.ts index 7a21b9a0..6c625bc2 100644 --- a/apps/webapp/src/services/workspace/index.ts +++ b/apps/webapp/src/services/workspace/index.ts @@ -1,3 +1,4 @@ export * from './invite-users'; export * from './invite-action'; export * from './update-workspace'; +export * from './create-initial-resources'; diff --git a/apps/webapp/src/store/integration-accounts/models.ts b/apps/webapp/src/store/integration-accounts/models.ts index 4ed2f2dc..d06e286a 100644 --- a/apps/webapp/src/store/integration-accounts/models.ts +++ b/apps/webapp/src/store/integration-accounts/models.ts @@ -7,6 +7,7 @@ export const IntegrationAccount = types.model({ accountId: types.string, settings: types.string, integratedById: types.string, + personal: types.boolean, integrationDefinitionId: types.string, workspaceId: types.string, }); diff --git a/apps/webapp/src/store/linked-issues/models.ts b/apps/webapp/src/store/linked-issues/models.ts index 2ef642d8..bff6c6b8 100644 --- a/apps/webapp/src/store/linked-issues/models.ts +++ b/apps/webapp/src/store/linked-issues/models.ts @@ -7,7 +7,6 @@ export const LinkedIssue = types.model({ url: types.string, sourceId: types.union(types.string, types.null), - source: types.string, sourceData: types.string, issueId: types.string, createdById: types.union(types.string, types.undefined, types.null), diff --git a/apps/website/.dockerignore b/apps/website/.dockerignore new file mode 100644 index 00000000..e69de29b diff --git a/apps/website/.eslintrc.js b/apps/website/.eslintrc.js new file mode 100644 index 00000000..bbfe2996 --- /dev/null +++ b/apps/website/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + root: true, + extends: ['@tegonhq/eslint-config/next.js'], + parserOptions: { + project: true, + }, +}; diff --git a/apps/website/.gitignore b/apps/website/.gitignore new file mode 100644 index 00000000..cfe21fc1 --- /dev/null +++ b/apps/website/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# Sentry Config File +.sentryclirc diff --git a/apps/website/.prettierrc.json b/apps/website/.prettierrc.json new file mode 100644 index 00000000..dcb72794 --- /dev/null +++ b/apps/website/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} \ No newline at end of file diff --git a/apps/website/next.config.js b/apps/website/next.config.js new file mode 100644 index 00000000..62eaa45c --- /dev/null +++ b/apps/website/next.config.js @@ -0,0 +1,14 @@ +/** Copyright (c) 2024, Tegon, all rights reserved. **/ + +module.exports = { + reactStrictMode: false, + experimental: { + scrollRestoration: true, + }, + transpilePackages: ['geist', '@tegonhq/ui'], + devIndicators: { + buildActivityPosition: 'bottom-right', + }, + swcMinify: true, + output: 'standalone', +}; diff --git a/apps/website/next.d.ts b/apps/website/next.d.ts new file mode 100644 index 00000000..401730b6 --- /dev/null +++ b/apps/website/next.d.ts @@ -0,0 +1,25 @@ +import type { + NextComponentType, + NextPageContext, + NextLayoutComponentType, +} from 'next'; +import type { AppProps } from 'next/app'; + +declare module 'next' { + // eslint-disable-next-line @typescript-eslint/ban-types + type NextLayoutComponentType

= NextComponentType< + NextPageContext, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + any, + P + > & { + getLayout?: (page: ReactNode) => ReactNode; + }; +} + +declare module 'next/app' { + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/ban-types + type AppLayoutProps

= AppProps & { + Component: NextLayoutComponentType; + }; +} diff --git a/apps/website/package.json b/apps/website/package.json new file mode 100644 index 00000000..fa4e8bd3 --- /dev/null +++ b/apps/website/package.json @@ -0,0 +1,54 @@ +{ + "name": "website", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint --fix" + }, + "dependencies": { + "@hello-pangea/dnd": "^16.6.0", + "@hookform/resolvers": "3.9.0", + "@radix-ui/react-icons": "^1.3.0", + "@remixicon/react": "^4.2.0", + "@tegonhq/ui": "workspace:*", + "@typeform/embed-react": "^3.17.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", + "copy-to-clipboard": "^3.3.3", + "date-fns": "^3.6.0", + "geist": "^1.3.0", + "http-proxy": "^1.18.1", + "next": "14.1.0", + "next-themes": "^0.2.1", + "qs": "^6.12.0", + "react": "^18", + "react-dom": "^18", + "react-hook-form": "7.49.3", + "ts-key-enum": "^2.0.12", + "use-debounce": "^10.0.0", + "uuid": "^10.0.0", + "zod": "3.23.8" + }, + "devDependencies": { + "@tegonhq/eslint-config": "workspace:*", + "@tegonhq/typescript-config": "workspace:*", + "@types/node": "^20.11.5", + "@types/qs": "^6.9.12", + "@types/react": "^18", + "@types/react-dom": "^18", + "@types/superagent": "^8.1.4", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "^6.19.1", + "@typescript-eslint/parser": "^6.19.1", + "autoprefixer": "^10.4.17", + "eslint": "^8.56.0", + "eslint-config-next": "14.1.0", + "postcss": "^8", + "prettier": "^3.2.4", + "tailwindcss": "^3.4.4", + "typescript": "^5.4.3" + } +} diff --git a/apps/website/postcss.config.js b/apps/website/postcss.config.js new file mode 100644 index 00000000..e973f993 --- /dev/null +++ b/apps/website/postcss.config.js @@ -0,0 +1,8 @@ +/** Copyright (c) 2024, Tegon, all rights reserved. **/ + +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/apps/website/public/favicon.ico b/apps/website/public/favicon.ico new file mode 100644 index 00000000..4d320b12 Binary files /dev/null and b/apps/website/public/favicon.ico differ diff --git a/apps/website/public/features/ai-suggestions.png b/apps/website/public/features/ai-suggestions.png new file mode 100644 index 00000000..b55c4c57 Binary files /dev/null and b/apps/website/public/features/ai-suggestions.png differ diff --git a/apps/website/public/features/grouping.png b/apps/website/public/features/grouping.png new file mode 100644 index 00000000..30cd83fc Binary files /dev/null and b/apps/website/public/features/grouping.png differ diff --git a/apps/website/public/features/triage.png b/apps/website/public/features/triage.png new file mode 100644 index 00000000..7fc369e2 Binary files /dev/null and b/apps/website/public/features/triage.png differ diff --git a/apps/website/public/home/AI.png b/apps/website/public/home/AI.png new file mode 100644 index 00000000..01b3d4c9 Binary files /dev/null and b/apps/website/public/home/AI.png differ diff --git a/apps/website/public/home/Actions.png b/apps/website/public/home/Actions.png new file mode 100644 index 00000000..67ef5402 Binary files /dev/null and b/apps/website/public/home/Actions.png differ diff --git a/apps/website/public/home/Issue tracker.png b/apps/website/public/home/Issue tracker.png new file mode 100644 index 00000000..6bd93da8 Binary files /dev/null and b/apps/website/public/home/Issue tracker.png differ diff --git a/apps/website/public/home/Triage.png b/apps/website/public/home/Triage.png new file mode 100644 index 00000000..384aea2c Binary files /dev/null and b/apps/website/public/home/Triage.png differ diff --git a/apps/website/public/logo.png b/apps/website/public/logo.png new file mode 100644 index 00000000..af8d8a02 Binary files /dev/null and b/apps/website/public/logo.png differ diff --git a/apps/website/public/logo_black.svg b/apps/website/public/logo_black.svg new file mode 100644 index 00000000..3066d3f3 --- /dev/null +++ b/apps/website/public/logo_black.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/website/public/logo_text.svg b/apps/website/public/logo_text.svg new file mode 100644 index 00000000..a856b100 --- /dev/null +++ b/apps/website/public/logo_text.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/apps/website/public/logo_white_text.svg b/apps/website/public/logo_white_text.svg new file mode 100644 index 00000000..2652108e --- /dev/null +++ b/apps/website/public/logo_white_text.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/apps/website/public/photo.jpg b/apps/website/public/photo.jpg new file mode 100644 index 00000000..4d7b54fe Binary files /dev/null and b/apps/website/public/photo.jpg differ diff --git a/apps/website/public/yc.png b/apps/website/public/yc.png new file mode 100644 index 00000000..8130e201 Binary files /dev/null and b/apps/website/public/yc.png differ diff --git a/apps/website/src/components/accouncement.tsx b/apps/website/src/components/accouncement.tsx new file mode 100644 index 00000000..d69fbc8c --- /dev/null +++ b/apps/website/src/components/accouncement.tsx @@ -0,0 +1,18 @@ +import { ArrowRightIcon } from '@radix-ui/react-icons'; +import { Button } from '@tegonhq/ui/components/button'; +import { Separator } from '@tegonhq/ui/components/separator'; +import { Actions } from '@tegonhq/ui/icons'; + +export function Announcement() { + return ( + + ); +} diff --git a/apps/website/src/components/page.tsx b/apps/website/src/components/page.tsx new file mode 100644 index 00000000..66f56ef3 --- /dev/null +++ b/apps/website/src/components/page.tsx @@ -0,0 +1,66 @@ +import { cn } from '@tegonhq/ui/lib/utils'; + +function PageHeader({ + className, + children, + ...props +}: React.HTMLAttributes) { + return ( +

+ {children} +
+ ); +} + +function PageHeaderHeading({ + className, + ...props +}: React.HTMLAttributes) { + return ( +

+ ); +} + +function PageHeaderDescription({ + className, + ...props +}: React.HTMLAttributes) { + return ( +

+ ); +} + +function PageActions({ + className, + ...props +}: React.HTMLAttributes) { + return ( +

+ ); +} + +export { PageActions, PageHeader, PageHeaderDescription, PageHeaderHeading }; diff --git a/apps/website/src/config/site.ts b/apps/website/src/config/site.ts new file mode 100644 index 00000000..0c7246a6 --- /dev/null +++ b/apps/website/src/config/site.ts @@ -0,0 +1,14 @@ +export const siteConfig = { + name: 'Tegon', + url: 'https://tegon.ai', + ogImage: 'https://ui.shadcn.com/og.jpg', + description: + 'Tegon is dev-first issue tracking tool. Open-source, customizable, and lightweight.', + links: { + twitter: 'https://twitter.com/tegonhq', + slack: 'https://slack.', + github: 'https://github.com/tegonhq/tegon', + }, +}; + +export type SiteConfig = typeof siteConfig; diff --git a/apps/website/src/icons/arrow-up.tsx b/apps/website/src/icons/arrow-up.tsx new file mode 100644 index 00000000..21dfca5e --- /dev/null +++ b/apps/website/src/icons/arrow-up.tsx @@ -0,0 +1,14 @@ +export function ArrowUp() { + return ( + + + + + + ); +} diff --git a/apps/website/src/layouts/main/command-menu.tsx b/apps/website/src/layouts/main/command-menu.tsx new file mode 100644 index 00000000..05963324 --- /dev/null +++ b/apps/website/src/layouts/main/command-menu.tsx @@ -0,0 +1,115 @@ +'use client'; + +import { + CircleIcon, + LaptopIcon, + MoonIcon, + SunIcon, +} from '@radix-ui/react-icons'; +import { Button } from '@tegonhq/ui/components/button'; +import { + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, +} from '@tegonhq/ui/components/command'; +import { cn } from '@tegonhq/ui/lib/utils'; +import { useRouter } from 'next/navigation'; +import { useTheme } from 'next-themes'; +import * as React from 'react'; + +import { docsConfig } from './docs'; + +export function CommandMenu({ ...props }: any) { + const router = useRouter(); + const [open, setOpen] = React.useState(false); + const { setTheme } = useTheme(); + + React.useEffect(() => { + const down = (e: KeyboardEvent) => { + if ((e.key === 'k' && (e.metaKey || e.ctrlKey)) || e.key === '/') { + if ( + (e.target instanceof HTMLElement && e.target.isContentEditable) || + e.target instanceof HTMLInputElement || + e.target instanceof HTMLTextAreaElement || + e.target instanceof HTMLSelectElement + ) { + return; + } + + e.preventDefault(); + setOpen((open) => !open); + } + }; + + document.addEventListener('keydown', down); + return () => document.removeEventListener('keydown', down); + }, []); + + const runCommand = React.useCallback((command: () => unknown) => { + setOpen(false); + command(); + }, []); + + return ( + <> + + + + + No results found. + + {docsConfig.sidebarNav.map((group) => ( + + {group.items.map((navItem) => ( + { + runCommand(() => router.push(navItem.href as string)); + }} + > +
+ +
+ {navItem.title} +
+ ))} +
+ ))} + + + runCommand(() => setTheme('light'))}> + + Light + + runCommand(() => setTheme('dark'))}> + + Dark + + runCommand(() => setTheme('system'))}> + + System + + +
+
+ + ); +} diff --git a/apps/website/src/layouts/main/docs.ts b/apps/website/src/layouts/main/docs.ts new file mode 100644 index 00000000..346ad4cf --- /dev/null +++ b/apps/website/src/layouts/main/docs.ts @@ -0,0 +1,44 @@ +export interface NavItem { + title: string; + href?: string; + disabled?: boolean; + external?: boolean; + icon?: React.ReactNode; + label?: string; +} + +export interface NavItemWithChildren extends NavItem { + items: NavItemWithChildren[]; +} + +export interface MainNavItem extends NavItem {} + +export interface SidebarNavItem extends NavItemWithChildren {} + +export interface DocsConfig { + mainNav: MainNavItem[]; + + sidebarNav: SidebarNavItem[]; +} + +export const docsConfig: DocsConfig = { + mainNav: [ + { + title: 'Actions', + href: '/actions', + }, + { + title: 'Documentation', + href: '/docs', + }, + { + title: 'Releases', + href: '/releases', + }, + { + title: 'Company', + href: '/company', + }, + ], + sidebarNav: [], +}; diff --git a/apps/website/src/layouts/main/index.ts b/apps/website/src/layouts/main/index.ts new file mode 100644 index 00000000..f6b4b2a4 --- /dev/null +++ b/apps/website/src/layouts/main/index.ts @@ -0,0 +1 @@ +export * from './site-header'; diff --git a/apps/website/src/layouts/main/main-nav.tsx b/apps/website/src/layouts/main/main-nav.tsx new file mode 100644 index 00000000..bc643f10 --- /dev/null +++ b/apps/website/src/layouts/main/main-nav.tsx @@ -0,0 +1,71 @@ +import { buttonVariants } from '@tegonhq/ui/components/button'; +import { cn } from '@tegonhq/ui/lib/utils'; +import Image from 'next/image'; +import Link from 'next/link'; +import { useTheme } from 'next-themes'; + +export function MainNav() { + const { theme } = useTheme(); + + return ( +
+ ); +} diff --git a/apps/website/src/layouts/main/mobile-nav.tsx b/apps/website/src/layouts/main/mobile-nav.tsx new file mode 100644 index 00000000..b5d02e86 --- /dev/null +++ b/apps/website/src/layouts/main/mobile-nav.tsx @@ -0,0 +1,145 @@ +'use client'; + +import { Button } from '@tegonhq/ui/components/button'; +import { ScrollArea } from '@tegonhq/ui/components/scroll-area'; +import { + Sheet, + SheetContent, + SheetTrigger, +} from '@tegonhq/ui/components/sheet'; +import { cn } from '@tegonhq/ui/lib/utils'; +import { useRouter } from 'next/navigation'; +import * as React from 'react'; + +import { siteConfig } from 'config/site'; + +import { docsConfig } from './docs'; + +export function MobileNav() { + const [open, setOpen] = React.useState(false); + + return ( + + + + + + + {siteConfig.name} + + +
+ {docsConfig.mainNav?.map( + (item) => + item.href && ( + + {item.title} + + ), + )} +
+
+ {docsConfig.sidebarNav.map((item, index) => ( +
+

{item.title}

+ {item?.items?.length && + item.items.map((item) => ( + + {!item.disabled && + (item.href ? ( + + {item.title} + {item.label && ( + + {item.label} + + )} + + ) : ( + item.title + ))} + + ))} +
+ ))} +
+
+
+
+ ); +} + +interface MobileLinkProps { + onOpenChange?: (open: boolean) => void; + children: React.ReactNode; + className?: string; + href: string; +} + +function MobileLink({ + href, + onOpenChange, + className, + children, + ...props +}: MobileLinkProps) { + const router = useRouter(); + return ( + { + router.push(href.toString()); + onOpenChange?.(false); + }} + className={cn(className)} + {...props} + > + {children} + + ); +} diff --git a/apps/website/src/layouts/main/mode-toggle.tsx b/apps/website/src/layouts/main/mode-toggle.tsx new file mode 100644 index 00000000..1fb0ebd5 --- /dev/null +++ b/apps/website/src/layouts/main/mode-toggle.tsx @@ -0,0 +1,39 @@ +'use client'; + +import { MoonIcon, SunIcon } from '@radix-ui/react-icons'; +import { Button } from '@tegonhq/ui/components/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@tegonhq/ui/components/dropdown-menu'; +import { useTheme } from 'next-themes'; +import * as React from 'react'; + +export function ModeToggle() { + const { setTheme } = useTheme(); + + return ( + + + + + + setTheme('light')}> + Light + + setTheme('dark')}> + Dark + + setTheme('system')}> + System + + + + ); +} diff --git a/apps/website/src/layouts/main/site-footer.tsx b/apps/website/src/layouts/main/site-footer.tsx new file mode 100644 index 00000000..3b4947b4 --- /dev/null +++ b/apps/website/src/layouts/main/site-footer.tsx @@ -0,0 +1,153 @@ +import { GitHubLogoIcon } from '@radix-ui/react-icons'; +import { RiGithubFill } from '@remixicon/react'; +import { buttonVariants } from '@tegonhq/ui/components/button'; +import { Separator } from '@tegonhq/ui/components/ui/separator'; +import { BookLine, CodingLine, SlackIcon } from '@tegonhq/ui/icons'; +import { cn } from '@tegonhq/ui/lib/utils'; +import Image from 'next/image'; +import Link from 'next/link'; +import { useTheme } from 'next-themes'; + +import { siteConfig } from 'config/site'; + +import { ModeToggle } from './mode-toggle'; + +export function SiteFooter() { + const { theme } = useTheme(); + + return ( + + ); +} diff --git a/apps/website/src/layouts/main/site-header.tsx b/apps/website/src/layouts/main/site-header.tsx new file mode 100644 index 00000000..1fd5a1d3 --- /dev/null +++ b/apps/website/src/layouts/main/site-header.tsx @@ -0,0 +1,77 @@ +import { ArrowTopRightIcon } from '@radix-ui/react-icons'; +import { RiGithubFill } from '@remixicon/react'; +import { buttonVariants } from '@tegonhq/ui/components/button'; +import { SlackIcon } from '@tegonhq/ui/icons'; +import { cn } from '@tegonhq/ui/lib/utils'; +import { useState } from 'react'; +import React from 'react'; + +import { siteConfig } from 'config/site'; +import { formatNumber } from 'utils'; + +import { MainNav } from './main-nav'; +import { MobileNav } from './mobile-nav'; +import { ModeToggle } from './mode-toggle'; + +export function SiteHeader() { + const [repoData, setRepoData] = useState(null); + + React.useEffect(() => { + const fetchRepoData = async () => { + try { + const response = await fetch( + `https://api.github.com/repos/tegonhq/tegon`, + ); + if (!response.ok) { + throw new Error(`Error: ${response.status}`); + } + const data = await response.json(); + setRepoData(data); + } catch (error) {} + }; + + fetchRepoData(); + }, []); + + return ( +
+ +
+ ); +} diff --git a/apps/website/src/modules/home/features/actions.tsx b/apps/website/src/modules/home/features/actions.tsx new file mode 100644 index 00000000..b92e2181 --- /dev/null +++ b/apps/website/src/modules/home/features/actions.tsx @@ -0,0 +1,54 @@ +import { cn } from '@tegonhq/ui/lib/utils'; + +export function Actions() { + return ( +
+

+ Write, deploy and automate anything +

+ +
+
+
+
+

General workflows

+

+ Automatically create bugs from various external sources. +

+ +
+
+
+
+ +
+
+
+

Integration based

+

+ Automatically create bugs from various external sources. +

+
+
+
+ +
+
+
+

Agentic workflows

+

+ Automatically create bugs from various external sources. +

+ +
+
+
+
+
+
+ ); +} diff --git a/apps/website/src/modules/home/features/triage.tsx b/apps/website/src/modules/home/features/triage.tsx new file mode 100644 index 00000000..0a28f78a --- /dev/null +++ b/apps/website/src/modules/home/features/triage.tsx @@ -0,0 +1,87 @@ +import { cn } from '@tegonhq/ui/lib/utils'; +import Image from 'next/image'; + +export function Triage() { + return ( +
+

+ Have omni-channel bug reporting system +

+ +
+
+
+
+

Central hub for bugs

+

+ Automatically create bugs from various external sources. +

+
+ +
+ logo +
+
+
+
+
+
+
+

Automatic grouping

+

+ Automatically create bugs from various external sources. +

+
+ +
+ logo +
+
+
+
+ +
+
+
+

AI suggestions

+

+ Automatically create bugs from various external sources. +

+ +
+
+ +
+ logo +
+
+
+
+
+ ); +} diff --git a/apps/website/src/modules/home/home.tsx b/apps/website/src/modules/home/home.tsx new file mode 100644 index 00000000..8e692263 --- /dev/null +++ b/apps/website/src/modules/home/home.tsx @@ -0,0 +1,71 @@ +import { Button } from '@tegonhq/ui/components/button'; +import Image from 'next/image'; +import { useState } from 'react'; + +import { Announcement } from 'components/accouncement'; +import { + PageActions, + PageHeader, + PageHeaderDescription, + PageHeaderHeading, +} from 'components/page'; + +import { Actions } from './features/actions'; +import { Triage } from './features/triage'; +import { Nav } from './nav'; +import { Opensource } from './opensource'; + +export function Home() { + const [tab, setTab] = useState('Issue tracker'); + + return ( +
+ + + The dev-first issue tracking tool + + Open-source, customizable, and lightweight. + + + + + + + +
+ ); +} diff --git a/apps/website/src/modules/home/index.ts b/apps/website/src/modules/home/index.ts new file mode 100644 index 00000000..e20557b3 --- /dev/null +++ b/apps/website/src/modules/home/index.ts @@ -0,0 +1 @@ +export * from './home'; diff --git a/apps/website/src/modules/home/nav.tsx b/apps/website/src/modules/home/nav.tsx new file mode 100644 index 00000000..a844ddc7 --- /dev/null +++ b/apps/website/src/modules/home/nav.tsx @@ -0,0 +1,68 @@ +'use client'; + +import { Button } from '@tegonhq/ui/components/button'; +import { ScrollArea, ScrollBar } from '@tegonhq/ui/components/scroll-area'; +import { Actions, AI, IssuesLine, TriageFill } from '@tegonhq/ui/icons'; +import { cn } from '@tegonhq/ui/lib/utils'; + +const tabs = [ + { + name: 'Issue tracker', + Icon: IssuesLine, + }, + { + name: 'Triage', + Icon: TriageFill, + color: 'var(--status-icon-0)', + }, + { + name: 'Actions', + Icon: Actions, + }, + { + name: 'AI', + Icon: AI, + }, +]; + +interface NavProps extends React.HTMLAttributes { + tab: string; + setTab: (tab: string) => void; +} + +export function Nav({ + className, + tab: currentTab, + setTab, + ...props +}: NavProps) { + return ( +
+ +
+ {tabs.map((tab) => { + const Icon = tab.Icon; + + return ( + + ); + })} +
+ +
+
+ ); +} diff --git a/apps/website/src/modules/home/opensource.tsx b/apps/website/src/modules/home/opensource.tsx new file mode 100644 index 00000000..d3aac0cd --- /dev/null +++ b/apps/website/src/modules/home/opensource.tsx @@ -0,0 +1,74 @@ +import { ArrowTopRightIcon, StarFilledIcon } from '@radix-ui/react-icons'; +import { RiGithubFill } from '@remixicon/react'; +import { buttonVariants } from '@tegonhq/ui/components/button'; +import { CodingLine } from '@tegonhq/ui/icons'; +import { cn } from '@tegonhq/ui/lib/utils'; +import Link from 'next/link'; +import React from 'react'; + +import { siteConfig } from 'config/site'; +import { formatNumber } from 'utils'; + +export function Opensource() { + const [repoData, setRepoData] = React.useState(null); + + React.useEffect(() => { + const fetchRepoData = async () => { + try { + const response = await fetch( + `https://api.github.com/repos/tegonhq/tegon`, + ); + if (!response.ok) { + throw new Error(`Error: ${response.status}`); + } + const data = await response.json(); + setRepoData(data); + } catch (error) {} + }; + + fetchRepoData(); + }, []); + + return ( +
+
+
+
+ +
+
+ We love opensource. Tegon is AGPL-3.0 licensed so you can view + source code, contribute and self host +
+
+ + + {repoData && formatNumber(repoData.stargazers_count)} + + + + + Contribute + +
+
+
+
+ ); +} diff --git a/apps/website/src/pages/_app.tsx b/apps/website/src/pages/_app.tsx new file mode 100644 index 00000000..d3a35c6d --- /dev/null +++ b/apps/website/src/pages/_app.tsx @@ -0,0 +1,53 @@ +import './global.css'; +import '@tegonhq/ui/index.css'; +import '@tegonhq/ui/global.css'; +import type { NextComponentType } from 'next'; +import type { AppContext, AppInitialProps, AppLayoutProps } from 'next/app'; + +import { ThemeProvider } from '@tegonhq/ui/components/theme-provider'; +import { Toaster } from '@tegonhq/ui/components/toaster'; +import { TooltipProvider } from '@tegonhq/ui/components/tooltip'; +import { cn } from '@tegonhq/ui/lib/utils'; +import { GeistMono } from 'geist/font/mono'; +import { GeistSans } from 'geist/font/sans'; +import React from 'react'; + +import { SiteHeader } from 'layouts/main'; +import { SiteFooter } from 'layouts/main/site-footer'; + +export const MyApp: NextComponentType< + AppContext, + AppInitialProps, + AppLayoutProps +> = ({ Component, pageProps }: AppLayoutProps) => { + const getLayout = Component.getLayout || ((page: React.ReactNode) => page); + + return ( + + +
+ +
+ {getLayout()} +
+ +
+ + +
+
+ ); +}; + +export default MyApp; diff --git a/apps/website/src/pages/_document.tsx b/apps/website/src/pages/_document.tsx new file mode 100644 index 00000000..2b4a3d35 --- /dev/null +++ b/apps/website/src/pages/_document.tsx @@ -0,0 +1,15 @@ +import { GeistMono } from 'geist/font/mono'; +import { GeistSans } from 'geist/font/sans'; +import { Html, Head, Main, NextScript } from 'next/document'; + +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/apps/website/src/pages/_error.tsx b/apps/website/src/pages/_error.tsx new file mode 100644 index 00000000..28f9b8e9 --- /dev/null +++ b/apps/website/src/pages/_error.tsx @@ -0,0 +1,14 @@ +import Error from 'next/error'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const CustomErrorComponent = (props: any) => { + return ; +}; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +CustomErrorComponent.getInitialProps = async (contextData: any) => { + // This will contain the status code of the response + return Error.getInitialProps(contextData); +}; + +export default CustomErrorComponent; diff --git a/apps/website/src/pages/company/index.tsx b/apps/website/src/pages/company/index.tsx new file mode 100644 index 00000000..52d0eebb --- /dev/null +++ b/apps/website/src/pages/company/index.tsx @@ -0,0 +1,62 @@ +/* eslint-disable react/no-unescaped-entities */ +import { + PageHeader, + PageHeaderDescription, + PageHeaderHeading, +} from 'components/page'; + +/* eslint-disable @next/next/no-img-element */ +export default function Company() { + return ( +
+ + Our story + + We're building a new type of Project management platform, for + developers. + + + +
+
+

+ We're Harshith, Manoj, and Manik - friends, co-founders, and + passionate open-source believers. For the past 5 years, we've + been working together, and last year, our journey took an exciting + turn when we were accepted into Y Combinator. While we entered Y + Combinator with a different open-source project, the experience was + invaluable. We learned a lot, iterated on our ideas, and ultimately + decided to pivot towards Tegon. +

+
+
+ +
+ {''} +
+ +
+
+

Why Project Management?

+ +

+ Our experience with existing tools that have been there for decades + haven't been great. Being such an important tool which is + central to how you work, these tools are bloated, complex and often + act as a burden for engineers. With the advent of AI - we thought + what project management and issue tracking will look like 5-10 years + down the line, the current tools were nowhere close to our + imagination which got us excited and began the journey of Tegon. We + want to reimagine project management, by taking an AI-first approach + and starting with a simplified issue tracker built by and for + engineers. Be open-source, be community-driven. That's Tegon. +

+
+
+
+ ); +} diff --git a/apps/website/src/pages/global.css b/apps/website/src/pages/global.css new file mode 100644 index 00000000..b118b150 --- /dev/null +++ b/apps/website/src/pages/global.css @@ -0,0 +1,53 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground text-base; + @apply antialiased; + + /* shape-rendering: auto; */ + /* --webkit-font-smoothing: antialiased; */ + /* -webkit-font-smoothing: subpixel-antialiased; */ + } + + @supports (scrollbar-width: auto) { + .overflow-y-auto, + .overflow-x-auto, + .overflow-auto { + overflow-anchor: none; + scrollbar-color: var(--gray-500) transparent; + scrollbar-width: thin; + } + } + + /* Legacy browsers with `::-webkit-scrollbar-*` support */ + @supports selector(::-webkit-scrollbar) { + .overflow-y-auto::-webkit-scrollbar-thumb, + .overflow-x-auto::-webkit-scrollbar-thumb, + .overflow-auto::-webkit-scrollbar-thumb { + background: transparent; + } + .overflow-y-auto::-webkit-scrollbar-track, + .overflow-x-auto::-webkit-scrollbar-track, + .overflow-auto::-webkit-scrollbar-track { + background: var(--gray-600); + } + + .overflow-y-auto::-webkit-scrollbar, + .overflow-x-auto::-webkit-scrollbar, + .overflow-auto::-webkit-scrollbar { + max-width: 5px; + } + } +} + +@layer utilities { + .text-balance { + text-wrap: balance; + } +} diff --git a/apps/website/src/pages/index.tsx b/apps/website/src/pages/index.tsx new file mode 100644 index 00000000..9ea171ea --- /dev/null +++ b/apps/website/src/pages/index.tsx @@ -0,0 +1,3 @@ +import { Home } from 'modules/home'; + +export default Home; diff --git a/apps/website/src/utils.ts b/apps/website/src/utils.ts new file mode 100644 index 00000000..f8f4a41d --- /dev/null +++ b/apps/website/src/utils.ts @@ -0,0 +1,8 @@ +export function formatNumber(num: number): string { + if (num >= 1_000_000) { + return `${(num / 1_000_000).toFixed(1).replace(/\.0$/, '')}M`; + } else if (num >= 1_000) { + return `${(num / 1_000).toFixed(1).replace(/\.0$/, '')}k`; + } + return num.toString(); +} diff --git a/apps/website/tailwind.config.ts b/apps/website/tailwind.config.ts new file mode 100644 index 00000000..8c939e1b --- /dev/null +++ b/apps/website/tailwind.config.ts @@ -0,0 +1 @@ +export * from '@tegonhq/ui/tailwind.config'; diff --git a/apps/website/tsconfig.json b/apps/website/tsconfig.json new file mode 100644 index 00000000..4b29da1a --- /dev/null +++ b/apps/website/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@tegonhq/typescript-config/next.json", + "compilerOptions": { + "baseUrl": "src", + "plugins": [ + { + "name": "next" + } + ] + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/docs/mint.json b/docs/mint.json index 9871b16f..6464a8bf 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -23,7 +23,7 @@ ], "topbarCtaButton": { "name": "Dashboard", - "url": "https://app.tegon.ai/auth/signin" + "url": "https://app.tegon.ai/auth" }, "anchors": [ diff --git a/package.json b/package.json index c58d3ffb..fcfecbd4 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "author": "Tegon ", "private": true, "scripts": { - "dev": "dotenv -- turbo run dev --parallel", + "dev-website": "dotenv -- turbo run dev --filter=website", + "dev": "dotenv -- turbo run dev --parallel --filter=!website", "build": "dotenv -- turbo run build", "lint": "turbo run lint", "generate": "turbo run generate", diff --git a/packages/cli/package.json b/packages/cli/package.json index a5715541..893fa83c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@tegonhq/cli", - "version": "0.1.3", + "version": "0.1.4", "description": "A Command-Line Deploying actions", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/services/apiSpec.yml b/packages/services/apiSpec.yml new file mode 100644 index 00000000..d8274cf9 --- /dev/null +++ b/packages/services/apiSpec.yml @@ -0,0 +1,2062 @@ +openapi: 3.0.0 +info: + title: Tegon + description: AI First Project Management Tool + version: 0.3.0 + +servers: + - url: https://app.tegon.ai + +paths: + /api/v1/action/{slug}/run: + post: + summary: Run an action + description: Runs an action with the specified slug and payload + parameters: + - name: slug + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RunAction' + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + + /api/v1/action/{slug}/inputs: + post: + summary: Update action inputs + description: Updates the inputs of an action with the specified slug + parameters: + - name: slug + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateActionInputsDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + + /api/v1/ai_requests: + post: + summary: Get AI request + description: Sends a request to the AI system and returns the response + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GetAIRequestDTO' + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: string + + /api/v1/ai_requests/stream: + post: + summary: Get AI request stream + description: Sends a request to the AI system and returns a stream of responses + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GetAIRequestDTO' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/AIStreamResponse' + + /api/v1/integration_account/{integrationAccountId}: + get: + summary: Get integration accounts by integration account ID + parameters: + - name: integrationAccountId + in: path + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/IntegrationAccount' + + /api/v1/integration_account/accountId: + get: + summary: Get integration accounts by account ID + parameters: + - name: accountId + in: query + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/IntegrationAccount' + + /api/v1/integration_definition/{integrationDefinitionId}: + get: + summary: Get integration definition by ID + parameters: + - name: integrationDefinitionId + in: path + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/IntegrationDefinition' + + /api/v1/integration_definition: + get: + summary: Get integration definitions by workspace ID + parameters: + - name: workspaceId + in: query + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/IntegrationDefinition' + + /api/v1/issue_comments: + post: + summary: Create an issue comment + parameters: + - name: issueId + in: query + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateIssueCommentDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/IssueComment' + + /api/v1/issue_comments/linked_comment: + post: + summary: Create a linked comment + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateLinkedIssueCommentDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/LinkedComment' + + /api/v1/issue_comments/linked_comment/: + get: + summary: Get linked comment + parameters: + - in: query + name: sourceId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/LinkedComment' + + /api/v1/issue_comments/{issueCommentId}: + get: + summary: Get issue comment + parameters: + - in: path + name: issueCommentId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/IssueComment' + + post: + summary: Update issue comment + parameters: + - in: path + name: issueCommentId + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateIssueCommentDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/IssueComment' + + /api/v1/issue_relation/{issueRelationId}: + delete: + summary: Delete issue relation + parameters: + - in: path + name: issueRelationId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/IssueRelation' + + /api/v1/issues: + post: + summary: Create issue + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateIssueDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/Issue' + + /api/v1/issues/{issueId}: + post: + summary: Update issue + parameters: + - in: path + name: issueId + required: true + schema: + type: string + - in: query + name: teamId + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateIssueDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/Issue' + delete: + summary: Delete issue + parameters: + - in: path + name: issueId + required: true + schema: + type: string + - in: query + name: teamId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/Issue' + + /api/v1/issues/filter: + post: + summary: Get issues by filter + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GetIssuesByFilterDTO' + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Issue' + + /api/v1/issues/{issueId}/move: + post: + summary: Move issue to team + parameters: + - in: path + name: issueId + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TeamRequestParamsDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/Issue' + + /api/v1/labels: + get: + summary: Get labels + parameters: + - in: query + name: workspaceId + required: true + schema: + type: string + - in: query + name: teamId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Label' + + post: + summary: Create label + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateLabelDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/Label' + + /api/v1/labels/{labelId}: + post: + summary: Update label + parameters: + - in: path + name: labelId + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateLabelDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/Label' + + delete: + summary: Delete label + parameters: + - in: path + name: labelId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/Label' + + /api/v1/issues/{issueId}/link: + post: + summary: Create linked issue + parameters: + - in: path + name: issueId + required: true + schema: + type: string + - in: query + name: teamId + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateLinkedIssueDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/LinkedIssue' + + /api/v1/linked_issues/{linkedIssueId}: + get: + summary: Get linked issue by ID + parameters: + - in: path + name: linkedIssueId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/LinkedIssue' + + post: + summary: Update linked issue by ID + parameters: + - in: path + name: linkedIssueId + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateLinkedIssueDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/LinkedIssue' + + delete: + summary: Delete linked issue + parameters: + - in: path + name: linkedIssueId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/LinkedIssue' + + /api/v1/linked_issues/source: + get: + summary: Get linked issue by source ID + parameters: + - in: query + name: sourceId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/LinkedIssue' + + /api/v1/linked_issues/source/{sourceId}: + get: + summary: Get personal access tokens (PATs) + parameters: + - in: path + name: sourceId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pat' + + post: + summary: Update linked issue by source ID + parameters: + - in: path + name: sourceId + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateLinkedIssueDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/LinkedIssue' + + /api/v1/users/pat: + post: + summary: Create personal access token (PAT) + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreatePatDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + + /api/v1/users/pats/{patId}: + delete: + summary: Delete personal access token (PAT) + parameters: + - in: path + name: patId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + + /api/v1/users: + get: + summary: Get user + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + + post: + summary: Get users + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/GetUsersDto' + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/PublicUser' + + /api/v1/views/{viewId}: + get: + summary: Get view + parameters: + - in: path + name: viewId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + $ref: '#/components/schemas/View' + + /api/v1/{teamId}/workflows: + get: + summary: Get workflows + parameters: + - in: path + name: teamId + required: true + schema: + type: string + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Workflow' + +components: + schemas: + RunAction: + type: object + properties: + workspaceId: + type: string + payload: + type: object + required: + - workspaceId + - payload + + UpdateActionInputsDto: + type: object + properties: + inputs: + type: object + # Define the inputs schema if applicable + required: + - inputs + + GetAIRequestDTO: + type: object + properties: + messages: + type: array + items: + type: object + model: + type: string + workspaceId: + type: string + llmModel: + type: string + required: + - messages + - model + - workspaceId + - llmModel + + AIStreamResponse: + type: object + properties: + textStream: + type: string + format: binary + description: AsyncIterable & ReadableStream + + IntegrationAccount: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + integrationConfiguration: + type: object + nullable: true + accountId: + type: string + nullable: true + settings: + type: object + nullable: true + personal: + type: boolean + isActive: + type: boolean + integratedBy: + $ref: '#/components/schemas/User' + integratedById: + type: string + integrationDefinition: + $ref: '#/components/schemas/IntegrationDefinition' + integrationDefinitionId: + type: string + workspace: + $ref: '#/components/schemas/Workspace' + workspaceId: + type: string + + IntegrationDefinition: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + name: + type: string + slug: + type: string + description: + type: string + icon: + type: string + spec: + $ref: '#/components/schemas/Spec' + clientId: + type: string + clientSecret: + type: string + workspace: + $ref: '#/components/schemas/Workspace' + workspaceId: + type: string + nullable: true + IntegrationAccount: + type: array + items: + $ref: '#/components/schemas/IntegrationAccount' + + Spec: + type: object + properties: + workspace_auth: + type: object + properties: + OAuth2: + $ref: '#/components/schemas/OAuth2Params' + personal_auth: + type: object + properties: + OAuth2: + $ref: '#/components/schemas/OAuth2Params' + other_data: + type: object + # Define properties based on the actual JsonObject type + + OAuth2Params: + type: object + properties: + authorization_url: + type: string + authorization_params: + type: object + # Define properties based on the actual Record type + default_scopes: + type: array + items: + type: string + scope_separator: + type: string + token_url: + type: string + token_params: + type: object + # Define properties based on the actual Record type + redirect_uri_metadata: + type: array + items: + type: string + token_response_metadata: + type: array + items: + type: string + token_expiration_buffer: + type: integer + scopes: + type: array + items: + type: string + + Workspace: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + name: + type: string + slug: + type: string + icon: + type: string + nullable: true + actionsEnabled: + type: boolean + usersOnWorkspaces: + type: array + items: + $ref: '#/components/schemas/UsersOnWorkspaces' + team: + type: array + items: + $ref: '#/components/schemas/Team' + label: + type: array + items: + $ref: '#/components/schemas/Label' + template: + type: array + items: + $ref: '#/components/schemas/Template' + syncAction: + type: array + items: + $ref: '#/components/schemas/SyncAction' + integrationAccount: + type: array + items: + $ref: '#/components/schemas/IntegrationAccount' + integrationDefinition: + type: array + items: + $ref: '#/components/schemas/IntegrationDefinition' + View: + type: array + items: + $ref: '#/components/schemas/View' + aiRequests: + type: array + items: + $ref: '#/components/schemas/AIRequest' + prompts: + type: array + items: + $ref: '#/components/schemas/Prompt' + + UsersOnWorkspaces: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + user: + $ref: '#/components/schemas/User' + workspace: + $ref: '#/components/schemas/Workspace' + userId: + type: string + workspaceId: + type: string + teamIds: + type: array + items: + type: string + status: + type: string + enum: [ACTIVE, INACTIVE, INVITED] + externalAccountMappings: + type: object + nullable: true + # Define properties based on the actual JsonValue type + role: + type: string + enum: [ADMIN, MEMBER, GUEST] + joinedAt: + type: string + format: date-time + nullable: true + + Team: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + name: + type: string + identifier: + type: string + icon: + type: string + nullable: true + workspace: + $ref: '#/components/schemas/Workspace' + workspaceId: + type: string + issue: + type: array + items: + $ref: '#/components/schemas/Issue' + label: + type: array + items: + $ref: '#/components/schemas/Label' + template: + type: array + items: + $ref: '#/components/schemas/Template' + workflow: + type: array + items: + $ref: '#/components/schemas/Workflow' + teamPreference: + type: array + items: + $ref: '#/components/schemas/TeamPreference' + View: + type: array + items: + $ref: '#/components/schemas/View' + + Template: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + name: + type: string + category: + type: string + enum: [ISSUE, COMMENT] + templateData: + type: object + # Define properties based on the actual JsonValue type + createdBy: + $ref: '#/components/schemas/User' + createdById: + type: string + workspace: + $ref: '#/components/schemas/Workspace' + workspaceId: + type: string + team: + $ref: '#/components/schemas/Team' + nullable: true + teamId: + type: string + nullable: true + + SyncAction: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + modelName: + type: string + enum: + [ + ISSUE, + ISSUE_COMMENT, + ISSUE_RELATION, + LABEL, + LINKED_ISSUE, + TEAM, + TEMPLATE, + USER, + VIEW, + WORKFLOW, + WORKSPACE, + ] + modelId: + type: string + action: + type: string + enum: [CREATE, UPDATE, DELETE] + sequenceId: + type: integer + format: int64 + workspace: + $ref: '#/components/schemas/Workspace' + workspaceId: + type: string + + AIRequest: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + modelName: + type: string + data: + type: string + response: + type: string + nullable: true + llmModel: + type: string + workspace: + $ref: '#/components/schemas/Workspace' + workspaceId: + type: string + successful: + type: boolean + + Prompt: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + name: + type: string + prompt: + type: string + model: + type: string + enum: [GPT35TURBO, GPT4TURBO, LLAMA3, CLAUDEOPUS, GPT4O] + workspace: + $ref: '#/components/schemas/Workspace' + workspaceId: + type: string + + User: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + email: + type: string + fullname: + type: string + nullable: true + username: + type: string + initialSetupComplete: + type: boolean + anonymousDataCollection: + type: boolean + usersOnWorkspaces: + type: array + items: + $ref: '#/components/schemas/UsersOnWorkspaces' + template: + type: array + items: + $ref: '#/components/schemas/Template' + createdBy: + type: array + items: + $ref: '#/components/schemas/Issue' + integrationAccount: + type: array + items: + $ref: '#/components/schemas/IntegrationAccount' + attachment: + type: array + items: + $ref: '#/components/schemas/Attachment' + + IntegrationAccountIdDto: + type: object + properties: + integrationAccountId: + type: string + required: + - integrationAccountId + + AccountIdDto: + type: object + properties: + accountId: + type: string + required: + - accountId + + IntegrationDefinitionIdDto: + type: object + properties: + integrationDefinitionId: + type: string + required: + - integrationDefinitionId + + WorkspaceRequestParamsDto: + type: object + properties: + workspaceId: + type: string + required: + - workspaceId + + CreateIssueCommentDto: + type: object + properties: + body: + type: string + parentId: + type: string + linkCommentMetadata: + type: object + sourceMetadata: + type: object + + IssueComment: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + body: + type: string + userId: + type: string + nullable: true + updatedById: + type: string + sourceMetadata: + type: object + nullable: true + reactionsData: + type: array + items: + type: object + issueId: + type: string + parentId: + type: string + nullable: true + attachments: + type: array + items: + type: string + + Issue: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + title: + type: string + number: + type: integer + description: + type: string + nullable: true + priority: + type: integer + nullable: true + dueDate: + type: string + format: date-time + nullable: true + sortOrder: + type: integer + nullable: true + subIssueSortOrder: + type: integer + nullable: true + estimate: + type: integer + nullable: true + sourceMetadata: + type: object + nullable: true + isBidirectional: + type: boolean + nullable: true + teamId: + type: string + createdById: + type: string + nullable: true + updatedById: + type: string + subscriberIds: + type: array + items: + type: string + assigneeId: + type: string + nullable: true + labelIds: + type: array + items: + type: string + stateId: + type: string + parentId: + type: string + nullable: true + attachments: + type: array + items: + type: string + issueSuggestionId: + type: string + nullable: true + + LinkedComment: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + url: + type: string + sourceId: + type: string + sourceData: + type: object + nullable: true + createdById: + type: string + nullable: true + commentId: + type: string + + CreateLinkedIssueCommentDto: + type: object + properties: + url: + type: string + sourceId: + type: string + commentId: + type: string + sourceData: + type: object + + GetLinkedCommentDto: + type: object + required: + - sourceId + properties: + sourceId: + type: string + + IssueCommentRequestParamsDto: + type: object + required: + - issueCommentId + properties: + issueCommentId: + type: string + + UpdateIssueCommentDto: + type: object + properties: + body: + type: string + parentId: + type: string + linkCommentMetadata: + type: object + sourceMetadata: + type: object + + IssueRelationIdRequestDto: + type: object + required: + - issueRelationId + properties: + issueRelationId: + type: string + + IssueRelation: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + issue: + $ref: '#/components/schemas/Issue' + issueId: + type: string + relatedIssueId: + type: string + type: + type: string + metadata: + type: object + createdById: + type: string + deletedById: + type: string + deleted: + type: string + format: date-time + + CreateIssueDto: + type: object + required: + - title + - description + - stateId + - teamId + properties: + title: + type: string + description: + type: string + priority: + type: number + dueDate: + type: string + sortOrder: + type: number + estimate: + type: number + subIssueSortOrder: + type: number + labelIds: + type: array + items: + type: string + assigneeId: + type: string + stateId: + type: string + parentId: + type: string + subscriberIds: + type: array + items: + type: string + teamId: + type: string + linkIssue: + $ref: '#/components/schemas/LinkIssueDto' + issueRelation: + $ref: '#/components/schemas/CreateIssueRelationDto' + attachments: + type: array + items: + type: string + subIssues: + type: array + items: + $ref: '#/components/schemas/CreateIssueDto' + linkIssueData: + $ref: '#/components/schemas/CreateLinkedIssueDto' + sourceMetadata: + type: object + additionalProperties: + type: string + + LinkIssueDto: + type: object + properties: + url: + type: string + title: + type: string + + CreateLinkedIssueDto: + type: object + properties: + url: + type: string + sourceId: + type: string + sourceData: + type: object + additionalProperties: + type: string + + CreateIssueRelationDto: + type: object + required: + - type + - issueId + - relatedIssueId + properties: + type: + type: string + issueId: + type: string + relatedIssueId: + type: string + + IssueRequestParamsDto: + type: object + required: + - issueId + properties: + issueId: + type: string + + TeamRequestParamsDto: + type: object + required: + - teamId + properties: + teamId: + type: string + + GetIssuesByFilterDTO: + type: object + required: + - filters + - workspaceId + properties: + filters: + type: object + additionalProperties: + $ref: '#/components/schemas/FilterValue' + workspaceId: + type: string + + FilterValue: + type: object + required: + - filterType + properties: + value: + oneOf: + - type: string + - type: array + items: + type: string + filterType: + $ref: '#/components/schemas/FilterTypeEnum' + + FilterTypeEnum: + type: string + enum: + - IS + - IS_NOT + - INCLUDES + - EXCLUDES + - UNDEFINED + - LTE + - LT + - GTE + - GT + + FilterKeyEnum: + type: string + enum: + - label + - status + - assignee + - priority + - dueDate + - updatedAt + - createdAt + + BooleanFilterKeyEnum: + type: string + enum: + - isBlocked + - isBlocking + - isDuplicate + - isDuplicateOf + - isRelated + - isParent + - isSubIssue + + UpdateIssueDto: + type: object + properties: + title: + type: string + description: + type: string + priority: + type: number + dueDate: + type: string + sortOrder: + type: number + subIssueSortOrder: + type: number + estimate: + type: number + labelIds: + type: array + items: + type: string + assigneeId: + type: string + stateId: + type: string + parentId: + type: string + isBidirectional: + type: boolean + subscriberIds: + type: array + items: + type: string + issueRelation: + $ref: '#/components/schemas/CreateIssueRelationDto' + attachments: + type: array + items: + type: string + userId: + type: string + linkIssueData: + $ref: '#/components/schemas/CreateLinkedIssueDto' + sourceMetadata: + type: object + additionalProperties: + type: string + + CreateLabelDto: + type: object + required: + - name + - color + - workspaceId + properties: + name: + type: string + color: + type: string + description: + type: string + groupId: + type: string + workspaceId: + type: string + teamId: + type: string + + Label: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + name: + type: string + color: + type: string + description: + type: string + nullable: true + workspaceId: + type: string + teamId: + type: string + nullable: true + groupId: + type: string + nullable: true + + LabelRequestParamsDto: + type: object + required: + - labelId + properties: + labelId: + type: string + + GetLabelsDTO: + type: object + required: + - workspaceId + - teamId + properties: + workspaceId: + type: string + teamId: + type: string + + UpdateLabelDto: + type: object + properties: + name: + type: string + color: + type: string + description: + type: string + groupId: + type: string + + LinkedIssue: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + url: + type: string + sourceId: + type: string + nullable: true + sourceData: + type: object + additionalProperties: true + createdById: + type: string + nullable: true + updatedById: + type: string + issueId: + type: string + + UpdateLinkedIssueDto: + type: object + properties: + url: + type: string + sourceId: + type: string + title: + type: string + sourceData: + type: object + additionalProperties: + type: string + createdById: + type: string + + CreatePatDto: + type: object + required: + - name + properties: + name: + type: string + + Pat: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + name: + type: string + jwt: + type: string + token: + type: string + userId: + type: string + + GetUsersDto: + type: object + required: + - userIds + properties: + userIds: + type: array + items: + type: string + workspaceId: + type: string + + PublicUser: + type: object + properties: + id: + type: string + username: + type: string + fullname: + type: string + email: + type: string + role: + type: string + enum: [ADMIN, MEMBER, GUEST] + + View: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + workspaceId: + type: string + workspace: + type: object + # Define properties based on the actual Workspace type + teamId: + type: string + nullable: true + team: + type: object + nullable: true + # Define properties based on the actual Team type + name: + type: string + description: + type: string + filters: + type: object + # Define properties based on the actual filters type + isBookmarked: + type: boolean + createdById: + type: string + + Workflow: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + name: + type: string + position: + type: integer + color: + type: string + category: + type: string + enum: [TRIAGE, BACKLOG, UNSTARTED, STARTED, COMPLETED, CANCELED] + team: + type: object + nullable: true + # Define properties based on the actual Team type + teamId: + type: string + nullable: true + + TeamPreference: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + team: + $ref: '#/components/schemas/Team' + nullable: true + teamId: + type: string + nullable: true + preference: + type: string + enum: [ISSUE_ESTIMATES, PRIORITIES] + value: + type: string + + Attachment: + type: object + properties: + id: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + deleted: + type: string + format: date-time + nullable: true + fileName: + type: string + nullable: true + originalName: + type: string + fileType: + type: string + fileExt: + type: string + size: + type: integer + url: + type: string + nullable: true + status: + type: string + enum: [Pending, Failed, Uploaded, Deleted, External] + sourceMetadata: + type: object + nullable: true + # Define properties based on the actual JsonValue type + uploadedBy: + $ref: '#/components/schemas/User' + nullable: true + uploadedById: + type: string + nullable: true + workspace: + $ref: '#/components/schemas/Workspace' + nullable: true + workspaceId: + type: string + nullable: true + + responses: + ErrorResponse: + description: Error response + content: + application/json: + schema: + type: object + properties: + error: + type: string + + UnauthorizedResponse: + description: Unauthorized response + content: + application/json: + schema: + type: object + properties: + error: + type: string + example: Unauthorized + + securitySchemes: + BearerAuth: + type: http + scheme: bearer + +security: + - BearerAuth: [] diff --git a/packages/services/package.json b/packages/services/package.json index 44218e0c..e79d2016 100644 --- a/packages/services/package.json +++ b/packages/services/package.json @@ -39,7 +39,6 @@ "devDependencies": { "@tegonhq/eslint-config": "workspace:*", "@tegonhq/typescript-config": "workspace:*", - "@types/node": "^20", "@types/superagent": "^8.1.4", "rimraf": "^3.0.2", "tsup": "^8.0.1", @@ -54,4 +53,4 @@ "engines": { "node": ">=18.0.0" } -} \ No newline at end of file +} diff --git a/packages/services/src/ai-request/get-ai-request.ts b/packages/services/src/ai-request/get-ai-request.ts index f36424d3..3927a643 100644 --- a/packages/services/src/ai-request/get-ai-request.ts +++ b/packages/services/src/ai-request/get-ai-request.ts @@ -1,14 +1,16 @@ -import type { GetAIRequestDTO } from '@tegonhq/types'; +import type { AIStreamResponse, GetAIRequestDTO } from '@tegonhq/types'; import axios from 'axios'; -export async function getAIRequest(data: GetAIRequestDTO) { +export async function getAIRequest(data: GetAIRequestDTO): Promise { const response = await axios.post(`/api/v1/ai_requests`, data); return response.data; } -export async function getAIRequestStream(data: GetAIRequestDTO) { +export async function getAIRequestStream( + data: GetAIRequestDTO, +): Promise { const response = await axios.post(`/api/v1/ai_requests/stream`, data); return response.data; diff --git a/packages/services/src/attachment/index.ts b/packages/services/src/attachment/index.ts new file mode 100644 index 00000000..072c8aed --- /dev/null +++ b/packages/services/src/attachment/index.ts @@ -0,0 +1 @@ +export * from './upload-attachment'; diff --git a/packages/services/src/attachment/upload-attachment.ts b/packages/services/src/attachment/upload-attachment.ts new file mode 100644 index 00000000..3cbc8c2c --- /dev/null +++ b/packages/services/src/attachment/upload-attachment.ts @@ -0,0 +1,17 @@ +import { AttachmentResponse } from '@tegonhq/types'; +import axios from 'axios'; + +export async function uploadAttachment( + workspaceId: string, + formData: any, +): Promise { + const response = await axios.post( + `/api/v1/attachment/upload?workspaceId=${workspaceId}`, + formData, + { + headers: { ...formData.getHeaders() }, + }, + ); + + return response.data; +} diff --git a/packages/services/src/index.ts b/packages/services/src/index.ts index 2bcc197b..1368ad59 100644 --- a/packages/services/src/index.ts +++ b/packages/services/src/index.ts @@ -8,3 +8,4 @@ export * from './user'; export * from './workflow'; export * from './action'; export * from './view'; +export * from './attachment'; diff --git a/packages/services/src/integration-account/get-integration-accounts.ts b/packages/services/src/integration-account/get-integration-accounts.ts index 3c72782e..9f2a0d66 100644 --- a/packages/services/src/integration-account/get-integration-accounts.ts +++ b/packages/services/src/integration-account/get-integration-accounts.ts @@ -19,7 +19,7 @@ export async function getIntegrationAccountByAccountId({ accountId, }: AccountIdDto): Promise { const response = await axios.get( - `/v1/integration_account/accountId?accountId=${accountId}`, + `api/v1/integration_account/accountId?accountId=${accountId}`, ); return response.data; diff --git a/packages/services/src/issue-comment/create-issue-comment.ts b/packages/services/src/issue-comment/create-issue-comment.ts index 8fd5a672..b508bc27 100644 --- a/packages/services/src/issue-comment/create-issue-comment.ts +++ b/packages/services/src/issue-comment/create-issue-comment.ts @@ -1,4 +1,4 @@ -import { CreateIssueCommentDto } from '@tegonhq/types'; +import { CreateIssueCommentDto, IssueComment } from '@tegonhq/types'; import axios from 'axios'; export class CreateIssueCommentProps extends CreateIssueCommentDto { @@ -8,7 +8,7 @@ export class CreateIssueCommentProps extends CreateIssueCommentDto { export async function createIssueComment({ issueId, ...data -}: CreateIssueCommentProps) { +}: CreateIssueCommentProps): Promise { const response = await axios.post( `/api/v1/issue_comments?issueId=${issueId}`, data, diff --git a/packages/services/src/issue-comment/create-linked-comment.ts b/packages/services/src/issue-comment/create-linked-comment.ts index 1b7c3212..384311d1 100644 --- a/packages/services/src/issue-comment/create-linked-comment.ts +++ b/packages/services/src/issue-comment/create-linked-comment.ts @@ -1,9 +1,9 @@ -import { CreateLinkedIssueCommentDto } from '@tegonhq/types'; +import { CreateLinkedIssueCommentDto, LinkedComment } from '@tegonhq/types'; import axios from 'axios'; export async function createLinkedIssueComment( createLinkedIssueDto: CreateLinkedIssueCommentDto, -) { +): Promise { const response = await axios.post( `/api/v1/issue_comments/linked_comment`, createLinkedIssueDto, diff --git a/packages/services/src/issue-comment/get-linked-comment.ts b/packages/services/src/issue-comment/get-linked-comment.ts index ebe545da..c775fb1a 100644 --- a/packages/services/src/issue-comment/get-linked-comment.ts +++ b/packages/services/src/issue-comment/get-linked-comment.ts @@ -1,7 +1,9 @@ -import { GetLinkedCommentDto } from '@tegonhq/types'; +import { GetLinkedCommentDto, LinkedComment } from '@tegonhq/types'; import axios from 'axios'; -export async function getLinkedComment({ sourceId }: GetLinkedCommentDto) { +export async function getLinkedComment({ + sourceId, +}: GetLinkedCommentDto): Promise { const response = await axios.get( `/api/v1/issue_comments/linked_comment/?sourceId=${sourceId}`, ); diff --git a/packages/services/src/issue-comment/update-issue-comment.ts b/packages/services/src/issue-comment/update-issue-comment.ts index 89aac8d0..1aab834c 100644 --- a/packages/services/src/issue-comment/update-issue-comment.ts +++ b/packages/services/src/issue-comment/update-issue-comment.ts @@ -1,4 +1,4 @@ -import type { UpdateIssueCommentDto } from '@tegonhq/types'; +import type { IssueComment, UpdateIssueCommentDto } from '@tegonhq/types'; import axios from 'axios'; @@ -9,7 +9,7 @@ export interface UpdateIssueCommentProps extends UpdateIssueCommentDto { export async function updateIssueComment({ issueCommentId, ...data -}: UpdateIssueCommentProps) { +}: UpdateIssueCommentProps): Promise { const response = await axios.post( `/api/v1/issue_comments/${issueCommentId}`, data, diff --git a/packages/services/src/issue-relation/delete-issue-relation.ts b/packages/services/src/issue-relation/delete-issue-relation.ts index aa860028..781dced8 100644 --- a/packages/services/src/issue-relation/delete-issue-relation.ts +++ b/packages/services/src/issue-relation/delete-issue-relation.ts @@ -1,10 +1,10 @@ -import type { IssueRelationIdRequestDto } from '@tegonhq/types'; +import type { IssueRelation, IssueRelationIdRequestDto } from '@tegonhq/types'; import axios from 'axios'; export async function deleteIssueRelation({ issueRelationId, -}: IssueRelationIdRequestDto) { +}: IssueRelationIdRequestDto): Promise { const response = await axios.delete( `/api/v1/issue_relation/${issueRelationId}`, ); diff --git a/packages/services/src/issues/create-issue.ts b/packages/services/src/issues/create-issue.ts index 52de5ba0..7b740311 100644 --- a/packages/services/src/issues/create-issue.ts +++ b/packages/services/src/issues/create-issue.ts @@ -1,8 +1,11 @@ -import type { CreateIssueDto } from '@tegonhq/types'; +import type { CreateIssueDto, Issue } from '@tegonhq/types'; import axios from 'axios'; -export async function createIssue({ teamId, ...otherParams }: CreateIssueDto) { +export async function createIssue({ + teamId, + ...otherParams +}: CreateIssueDto): Promise { const response = await axios.post(`/api/v1/issues`, { ...otherParams, teamId, diff --git a/packages/services/src/issues/delete-issue.ts b/packages/services/src/issues/delete-issue.ts index 555c8c1a..2c806523 100644 --- a/packages/services/src/issues/delete-issue.ts +++ b/packages/services/src/issues/delete-issue.ts @@ -1,4 +1,5 @@ import type { + Issue, IssueRequestParamsDto, TeamRequestParamsDto, } from '@tegonhq/types'; @@ -7,7 +8,10 @@ import axios from 'axios'; export type DeleteIssueParams = IssueRequestParamsDto & TeamRequestParamsDto; -export async function deleteIssue({ issueId, teamId }: DeleteIssueParams) { +export async function deleteIssue({ + issueId, + teamId, +}: DeleteIssueParams): Promise { const response = await axios.delete( `/api/v1/issues/${issueId}?teamId=${teamId}`, ); diff --git a/packages/services/src/issues/get-issue.ts b/packages/services/src/issues/get-issue.ts index a4189fe6..395be539 100644 --- a/packages/services/src/issues/get-issue.ts +++ b/packages/services/src/issues/get-issue.ts @@ -1,8 +1,10 @@ -import type { GetIssuesByFilterDTO } from '@tegonhq/types'; +import type { GetIssuesByFilterDTO, Issue } from '@tegonhq/types'; import axios from 'axios'; -export async function getIssuesByFilter(data: GetIssuesByFilterDTO) { +export async function getIssuesByFilter( + data: GetIssuesByFilterDTO, +): Promise { const response = await axios.post(`/api/v1/issues/filter`, data); return response.data; diff --git a/packages/services/src/issues/move-issue-to-team.ts b/packages/services/src/issues/move-issue-to-team.ts index cc44cfa1..950d50c4 100644 --- a/packages/services/src/issues/move-issue-to-team.ts +++ b/packages/services/src/issues/move-issue-to-team.ts @@ -1,4 +1,5 @@ import type { + Issue, IssueRequestParamsDto, TeamRequestParamsDto, } from '@tegonhq/types'; @@ -11,7 +12,7 @@ export type MoveIssueToTeamParams = IssueRequestParamsDto & export async function moveIssueToTeam({ issueId, teamId, -}: MoveIssueToTeamParams) { +}: MoveIssueToTeamParams): Promise { const response = await axios.post(`/api/v1/issues/${issueId}/move`, { teamId, }); diff --git a/packages/services/src/issues/update-issue.ts b/packages/services/src/issues/update-issue.ts index aaa641e4..9e3c3048 100644 --- a/packages/services/src/issues/update-issue.ts +++ b/packages/services/src/issues/update-issue.ts @@ -2,6 +2,7 @@ import type { UpdateIssueDto, IssueRequestParamsDto, TeamRequestParamsDto, + Issue, } from '@tegonhq/types'; import axios from 'axios'; @@ -14,7 +15,7 @@ export async function updateIssue({ issueId, teamId, ...otherParams -}: UpdateIssueParams) { +}: UpdateIssueParams): Promise { const response = await axios.post( `/api/v1/issues/${issueId}?teamId=${teamId}`, otherParams, diff --git a/packages/services/src/labels/create-label.ts b/packages/services/src/labels/create-label.ts index de3db9e5..ce2e5721 100644 --- a/packages/services/src/labels/create-label.ts +++ b/packages/services/src/labels/create-label.ts @@ -1,8 +1,8 @@ -import type { CreateLabelDto } from '@tegonhq/types'; +import type { CreateLabelDto, Label } from '@tegonhq/types'; import axios from 'axios'; -export async function createLabel(params: CreateLabelDto) { +export async function createLabel(params: CreateLabelDto): Promise