Compare commits
1 commit
develop
...
feat/multi
Author | SHA1 | Date | |
---|---|---|---|
|
5a122706e5 |
9 changed files with 214 additions and 197 deletions
|
@ -15,4 +15,6 @@ NGINX_PORT_SSL=443
|
|||
POSTGRES_PASSWORD=postgres
|
||||
DOMAIN=tipi.localhost
|
||||
STORAGE_PATH=/Users/nicolas/Projects/runtipi
|
||||
REDIS_HOST=tipi-redis
|
||||
REDIS_HOST=tipi-redis
|
||||
|
||||
DATABASE_URL=postgres://tipi:postgres@localhost:5432/tipi
|
||||
|
|
|
@ -19,7 +19,7 @@ COPY ./prisma/schema.prisma ./prisma/
|
|||
|
||||
RUN pnpm install -r --prefer-offline
|
||||
|
||||
COPY ./src ./src
|
||||
# COPY ./src ./src
|
||||
COPY ./esbuild.js ./esbuild.js
|
||||
COPY ./tsconfig.json ./tsconfig.json
|
||||
COPY ./next.config.mjs ./next.config.mjs
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^2.9.10",
|
||||
"@prisma/client": "^4.8.0",
|
||||
"@prisma/client": "^4.11.0",
|
||||
"@runtipi/postgres-migrations": "^5.3.0",
|
||||
"@tabler/core": "1.0.0-beta16",
|
||||
"@tabler/icons": "^1.109.0",
|
||||
|
@ -40,6 +40,7 @@
|
|||
"@trpc/react-query": "^10.11.1",
|
||||
"@trpc/server": "^10.11.1",
|
||||
"argon2": "^0.29.1",
|
||||
"chokidar": "^3.5.3",
|
||||
"clsx": "^1.1.1",
|
||||
"express": "^4.17.3",
|
||||
"fs-extra": "^10.1.0",
|
||||
|
@ -112,7 +113,7 @@
|
|||
"msw": "^1.0.0",
|
||||
"next-router-mock": "^0.8.0",
|
||||
"prettier": "^2.8.4",
|
||||
"prisma": "^4.10.1",
|
||||
"prisma": "^4.11.0",
|
||||
"ts-jest": "^29.0.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "4.9.4",
|
||||
|
|
|
@ -4,7 +4,7 @@ specifiers:
|
|||
'@babel/core': ^7.0.0
|
||||
'@faker-js/faker': ^7.6.0
|
||||
'@hookform/resolvers': ^2.9.10
|
||||
'@prisma/client': ^4.8.0
|
||||
'@prisma/client': ^4.11.0
|
||||
'@runtipi/postgres-migrations': ^5.3.0
|
||||
'@tabler/core': 1.0.0-beta16
|
||||
'@tabler/icons': ^1.109.0
|
||||
|
@ -34,6 +34,7 @@ specifiers:
|
|||
'@typescript-eslint/eslint-plugin': ^5.47.1
|
||||
'@typescript-eslint/parser': ^5.47.1
|
||||
argon2: ^0.29.1
|
||||
chokidar: ^3.5.3
|
||||
clsx: ^1.1.1
|
||||
dotenv-cli: ^6.0.0
|
||||
esbuild: ^0.16.17
|
||||
|
@ -63,7 +64,7 @@ specifiers:
|
|||
node-fetch-commonjs: ^3.2.4
|
||||
pg: ^8.7.3
|
||||
prettier: ^2.8.4
|
||||
prisma: ^4.10.1
|
||||
prisma: ^4.11.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0
|
||||
react-hook-form: ^7.38.0
|
||||
|
@ -91,7 +92,7 @@ specifiers:
|
|||
|
||||
dependencies:
|
||||
'@hookform/resolvers': 2.9.11_react-hook-form@7.43.1
|
||||
'@prisma/client': 4.10.1_prisma@4.10.1
|
||||
'@prisma/client': 4.11.0_prisma@4.11.0
|
||||
'@runtipi/postgres-migrations': 5.3.0
|
||||
'@tabler/core': 1.0.0-beta16_biqbaboplfbrettd7655fr4n2y
|
||||
'@tabler/icons': 1.119.0_biqbaboplfbrettd7655fr4n2y
|
||||
|
@ -101,6 +102,7 @@ dependencies:
|
|||
'@trpc/react-query': 10.11.1_2pugaexxlcekgcbbhj75jqmiqi
|
||||
'@trpc/server': 10.11.1
|
||||
argon2: 0.29.1
|
||||
chokidar: 3.5.3
|
||||
clsx: 1.2.1
|
||||
express: 4.18.2
|
||||
fs-extra: 10.1.0
|
||||
|
@ -173,7 +175,7 @@ devDependencies:
|
|||
msw: 1.0.1_typescript@4.9.4
|
||||
next-router-mock: 0.8.0_next@13.1.6+react@18.2.0
|
||||
prettier: 2.8.4
|
||||
prisma: 4.10.1
|
||||
prisma: 4.11.0
|
||||
ts-jest: 29.0.5_q5pvvsha5rrowzfbt33h5w23u4
|
||||
ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq
|
||||
typescript: 4.9.4
|
||||
|
@ -192,6 +194,7 @@ packages:
|
|||
dependencies:
|
||||
'@jridgewell/gen-mapping': 0.1.1
|
||||
'@jridgewell/trace-mapping': 0.3.17
|
||||
dev: true
|
||||
|
||||
/@babel/code-frame/7.18.6:
|
||||
resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
|
||||
|
@ -202,6 +205,7 @@ packages:
|
|||
/@babel/compat-data/7.20.14:
|
||||
resolution: {integrity: sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/core/7.20.12:
|
||||
resolution: {integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==}
|
||||
|
@ -233,6 +237,7 @@ packages:
|
|||
'@babel/types': 7.20.7
|
||||
'@jridgewell/gen-mapping': 0.3.2
|
||||
jsesc: 2.5.2
|
||||
dev: true
|
||||
|
||||
/@babel/helper-compilation-targets/7.20.7_@babel+core@7.20.12:
|
||||
resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==}
|
||||
|
@ -251,6 +256,7 @@ packages:
|
|||
/@babel/helper-environment-visitor/7.18.9:
|
||||
resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/helper-function-name/7.19.0:
|
||||
resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==}
|
||||
|
@ -258,12 +264,14 @@ packages:
|
|||
dependencies:
|
||||
'@babel/template': 7.20.7
|
||||
'@babel/types': 7.20.7
|
||||
dev: true
|
||||
|
||||
/@babel/helper-hoist-variables/7.18.6:
|
||||
resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.20.7
|
||||
dev: true
|
||||
|
||||
/@babel/helper-module-imports/7.18.6:
|
||||
resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
|
||||
|
@ -285,6 +293,7 @@ packages:
|
|||
'@babel/types': 7.20.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@babel/helper-plugin-utils/7.20.2:
|
||||
resolution: {integrity: sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==}
|
||||
|
@ -296,12 +305,14 @@ packages:
|
|||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.20.7
|
||||
dev: true
|
||||
|
||||
/@babel/helper-split-export-declaration/7.18.6:
|
||||
resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.20.7
|
||||
dev: true
|
||||
|
||||
/@babel/helper-string-parser/7.19.4:
|
||||
resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==}
|
||||
|
@ -314,6 +325,7 @@ packages:
|
|||
/@babel/helper-validator-option/7.18.6:
|
||||
resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/helpers/7.20.13:
|
||||
resolution: {integrity: sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==}
|
||||
|
@ -324,6 +336,7 @@ packages:
|
|||
'@babel/types': 7.20.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@babel/highlight/7.18.6:
|
||||
resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
|
||||
|
@ -339,6 +352,7 @@ packages:
|
|||
hasBin: true
|
||||
dependencies:
|
||||
'@babel/types': 7.20.7
|
||||
dev: true
|
||||
|
||||
/@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.20.12:
|
||||
resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
|
||||
|
@ -482,6 +496,7 @@ packages:
|
|||
'@babel/code-frame': 7.18.6
|
||||
'@babel/parser': 7.20.15
|
||||
'@babel/types': 7.20.7
|
||||
dev: true
|
||||
|
||||
/@babel/traverse/7.20.13:
|
||||
resolution: {integrity: sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==}
|
||||
|
@ -499,6 +514,7 @@ packages:
|
|||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@babel/types/7.20.7:
|
||||
resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==}
|
||||
|
@ -1123,6 +1139,7 @@ packages:
|
|||
dependencies:
|
||||
'@jridgewell/set-array': 1.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
dev: true
|
||||
|
||||
/@jridgewell/gen-mapping/0.3.2:
|
||||
resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
|
||||
|
@ -1131,6 +1148,7 @@ packages:
|
|||
'@jridgewell/set-array': 1.1.2
|
||||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
'@jridgewell/trace-mapping': 0.3.17
|
||||
dev: true
|
||||
|
||||
/@jridgewell/resolve-uri/3.1.0:
|
||||
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
|
||||
|
@ -1140,15 +1158,18 @@ packages:
|
|||
/@jridgewell/set-array/1.1.2:
|
||||
resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
dev: true
|
||||
|
||||
/@jridgewell/sourcemap-codec/1.4.14:
|
||||
resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
|
||||
dev: true
|
||||
|
||||
/@jridgewell/trace-mapping/0.3.17:
|
||||
resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==}
|
||||
dependencies:
|
||||
'@jridgewell/resolve-uri': 3.1.0
|
||||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
dev: true
|
||||
|
||||
/@jridgewell/trace-mapping/0.3.9:
|
||||
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
|
||||
|
@ -1201,6 +1222,7 @@ packages:
|
|||
|
||||
/@next/env/13.1.6:
|
||||
resolution: {integrity: sha512-s+W9Fdqh5MFk6ECrbnVmmAOwxKQuhGMT7xXHrkYIBMBcTiOqNWhv5KbJIboKR5STXxNXl32hllnvKaffzFaWQg==}
|
||||
dev: false
|
||||
|
||||
/@next/eslint-plugin-next/13.1.1:
|
||||
resolution: {integrity: sha512-SBrOFS8PC3nQ5aeZmawJkjKkWjwK9RoxvBSv/86nZp0ubdoVQoko8r8htALd9ufp16NhacCdqhu9bzZLDWtALQ==}
|
||||
|
@ -1371,8 +1393,8 @@ packages:
|
|||
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
|
||||
dev: false
|
||||
|
||||
/@prisma/client/4.10.1_prisma@4.10.1:
|
||||
resolution: {integrity: sha512-VonXLJZybdt8e5XZH5vnIGCRNnIh6OMX1FS3H/yzMGLT3STj5TJ/OkMcednrvELgk8PK89Vo3aSh51MWNO0axA==}
|
||||
/@prisma/client/4.11.0_prisma@4.11.0:
|
||||
resolution: {integrity: sha512-0INHYkQIqgAjrt7NzhYpeDQi8x3Nvylc2uDngKyFDDj1tTRQ4uV1HnVmd1sQEraeVAN63SOK0dgCKQHlvjL0KA==}
|
||||
engines: {node: '>=14.17'}
|
||||
requiresBuild: true
|
||||
peerDependencies:
|
||||
|
@ -1381,17 +1403,18 @@ packages:
|
|||
prisma:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@prisma/engines-version': 4.10.1-2.aead147aa326ccb985dcfed5b065b4fdabd44b19
|
||||
prisma: 4.10.1
|
||||
'@prisma/engines-version': 4.11.0-57.8fde8fef4033376662cad983758335009d522acb
|
||||
prisma: 4.11.0
|
||||
dev: false
|
||||
|
||||
/@prisma/engines-version/4.10.1-2.aead147aa326ccb985dcfed5b065b4fdabd44b19:
|
||||
resolution: {integrity: sha512-tsjTho7laDhf9EJ9EnDxAPEf7yrigSMDhniXeU4YoWc7azHAs4GPxRi2P9LTFonmHkJLMOLjR77J1oIP8Ife1w==}
|
||||
/@prisma/engines-version/4.11.0-57.8fde8fef4033376662cad983758335009d522acb:
|
||||
resolution: {integrity: sha512-3Vd8Qq06d5xD8Ch5WauWcUUrsVPdMC6Ge8ILji8RFfyhUpqon6qSyGM0apvr1O8n8qH8cKkEFqRPsYjuz5r83g==}
|
||||
dev: false
|
||||
|
||||
/@prisma/engines/4.10.1:
|
||||
resolution: {integrity: sha512-B3tcTxjx196nuAu1GOTKO9cGPUgTFHYRdkPkTS4m5ptb2cejyBlH9X7GOfSt3xlI7p4zAJDshJP4JJivCg9ouA==}
|
||||
/@prisma/engines/4.11.0:
|
||||
resolution: {integrity: sha512-0AEBi2HXGV02cf6ASsBPhfsVIbVSDC9nbQed4iiY5eHttW9ZtMxHThuKZE1pnESbr8HRdgmFSa/Kn4OSNYuibg==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
|
||||
/@redis/bloom/1.2.0_@redis+client@1.5.5:
|
||||
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
|
||||
|
@ -1477,6 +1500,7 @@ packages:
|
|||
resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@tabler/core/1.0.0-beta16_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-jg/IiGLGHeQive1b+DfOR8JA0DB/ihc/wIEMohLkVHplC/R66uYF/8zg5Ptk5OeV2XAkn+UaPwsfcdmmJR4utw==}
|
||||
|
@ -2476,6 +2500,7 @@ packages:
|
|||
electron-to-chromium: 1.4.301
|
||||
node-releases: 2.0.10
|
||||
update-browserslist-db: 1.0.10_browserslist@4.21.5
|
||||
dev: true
|
||||
|
||||
/bs-logger/0.2.6:
|
||||
resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
|
||||
|
@ -3078,6 +3103,7 @@ packages:
|
|||
|
||||
/electron-to-chromium/1.4.301:
|
||||
resolution: {integrity: sha512-bz00ASIIDjcgszZKuEA1JEFhbDjqUNbQ/PEhNEl1wbixzYpeTp2H2QWjsQvAL2T1wJBdOwCF5hE896BoMwYKrA==}
|
||||
dev: true
|
||||
|
||||
/emittery/0.13.1:
|
||||
resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
|
||||
|
@ -3234,6 +3260,7 @@ packages:
|
|||
/escalade/3.1.1:
|
||||
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/escape-html/1.0.3:
|
||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||
|
@ -4333,6 +4360,7 @@ packages:
|
|||
|
||||
/immutable/4.2.4:
|
||||
resolution: {integrity: sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==}
|
||||
dev: false
|
||||
|
||||
/import-fresh/3.3.0:
|
||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||
|
@ -5206,6 +5234,7 @@ packages:
|
|||
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/json-parse-even-better-errors/2.3.1:
|
||||
resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
|
||||
|
@ -5378,6 +5407,7 @@ packages:
|
|||
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
|
||||
dependencies:
|
||||
yallist: 3.1.1
|
||||
dev: true
|
||||
|
||||
/lru-cache/6.0.0:
|
||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||
|
@ -6075,6 +6105,7 @@ packages:
|
|||
|
||||
/node-releases/2.0.10:
|
||||
resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
|
||||
dev: true
|
||||
|
||||
/nopt/5.0.0:
|
||||
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
|
||||
|
@ -6498,13 +6529,14 @@ packages:
|
|||
react-is: 18.2.0
|
||||
dev: true
|
||||
|
||||
/prisma/4.10.1:
|
||||
resolution: {integrity: sha512-0jDxgg+DruB1kHVNlcspXQB9au62IFfVg9drkhzXudszHNUAQn0lVuu+T8np0uC2z1nKD5S3qPeCyR8u5YFLnA==}
|
||||
/prisma/4.11.0:
|
||||
resolution: {integrity: sha512-4zZmBXssPUEiX+GeL0MUq/Yyie4ltiKmGu7jCJFnYMamNrrulTBc+D+QwAQSJ01tyzeGHlD13kOnqPwRipnlNw==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@prisma/engines': 4.10.1
|
||||
'@prisma/engines': 4.11.0
|
||||
dev: true
|
||||
|
||||
/prompts/2.4.2:
|
||||
resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
|
||||
|
@ -6706,6 +6738,7 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
dev: false
|
||||
|
||||
/readable-stream/3.6.0:
|
||||
resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
|
||||
|
@ -6912,6 +6945,7 @@ packages:
|
|||
chokidar: 3.5.3
|
||||
immutable: 4.2.4
|
||||
source-map-js: 1.0.2
|
||||
dev: false
|
||||
|
||||
/saxes/6.0.0:
|
||||
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
|
||||
|
@ -6924,6 +6958,7 @@ packages:
|
|||
resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
dev: false
|
||||
|
||||
/semver/6.3.0:
|
||||
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
|
||||
|
@ -7248,6 +7283,7 @@ packages:
|
|||
'@babel/core': 7.20.12
|
||||
client-only: 0.0.1
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/stylis/4.1.3:
|
||||
resolution: {integrity: sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==}
|
||||
|
@ -7653,6 +7689,7 @@ packages:
|
|||
browserslist: 4.21.5
|
||||
escalade: 3.1.1
|
||||
picocolors: 1.0.0
|
||||
dev: true
|
||||
|
||||
/uri-js/4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
@ -7973,6 +8010,7 @@ packages:
|
|||
|
||||
/yallist/3.1.1:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
dev: true
|
||||
|
||||
/yallist/4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
|
|
|
@ -52,6 +52,16 @@ model User {
|
|||
@@map("user")
|
||||
}
|
||||
|
||||
model event {
|
||||
id Int @id @default(autoincrement())
|
||||
status event_status_enum
|
||||
message String @db.VarChar
|
||||
type String @db.VarChar
|
||||
args String[] @db.VarChar
|
||||
createdAt DateTime @default(now()) @db.Timestamp(6)
|
||||
updatedAt DateTime @default(now()) @db.Timestamp(6)
|
||||
}
|
||||
|
||||
enum app_status_enum {
|
||||
running
|
||||
stopped
|
||||
|
@ -67,3 +77,10 @@ enum update_status_enum {
|
|||
FAILED
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
enum event_status_enum {
|
||||
running
|
||||
success
|
||||
error
|
||||
waiting
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ source "${BASH_SOURCE%/*}/common.sh"
|
|||
|
||||
ROOT_FOLDER="${PWD}"
|
||||
WATCH_FILE="${ROOT_FOLDER}/state/events"
|
||||
WATCH_FOLDER="${ROOT_FOLDER}/state/test-events"
|
||||
|
||||
function clean_events() {
|
||||
# Create the file if it doesn't exist
|
||||
|
@ -24,9 +25,9 @@ function set_status() {
|
|||
|
||||
# Update the status of the event
|
||||
if [[ "$(uname)" != "Linux" ]]; then
|
||||
sed -i '' "s/${id} [a-z]*/${id} ${status}/g" "${WATCH_FILE}"
|
||||
sed -i '' "s/${id} [a-z]*/${id} ${status}/g" "${WATCH_FOLDER}/${id}"
|
||||
else
|
||||
sed -i "s/${id}.*$/$(echo "${id} ${status}" | sed 's/\//\\\//g')/" "$WATCH_FILE"
|
||||
sed -i "s/${id}.*$/$(echo "${id} ${status}" | sed 's/\//\\\//g')/" "${WATCH_FOLDER}/${id}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -107,14 +108,31 @@ function select_command() {
|
|||
write_log "Listening for events in ${WATCH_FILE}..."
|
||||
clean_events
|
||||
# Listen in for changes in the WATCH_FILE
|
||||
fswatch -0 "${WATCH_FILE}" | while read -d ""; do
|
||||
# Read the command from the last line of the file
|
||||
command=$(tail -n 1 "${WATCH_FILE}")
|
||||
# fswatch -0 "${WATCH_FILE}" | while read -d ""; do
|
||||
# # Read the command from the last line of the file
|
||||
# command=$(tail -n 1 "${WATCH_FILE}")
|
||||
# status=$(echo "$command" | cut -d ' ' -f 3)
|
||||
|
||||
# if [ -z "$command" ] || [ "$status" != "waiting" ]; then
|
||||
# continue
|
||||
# else
|
||||
# select_command "$command"
|
||||
# fi
|
||||
# done
|
||||
|
||||
|
||||
# Listen for new files in the folder
|
||||
fswatch -0 "${WATCH_FOLDER}" | while read -d ""; do
|
||||
# print the path
|
||||
path="$REPLY"
|
||||
|
||||
command=$(tail -n 1 "${path}")
|
||||
status=$(echo "$command" | cut -d ' ' -f 3)
|
||||
|
||||
if [ -z "$command" ] || [ "$status" != "waiting" ]; then
|
||||
continue
|
||||
else
|
||||
select_command "$command"
|
||||
select_command "$command"
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
/* eslint-disable vars-on-top */
|
||||
import cron from 'node-cron';
|
||||
import fs from 'fs-extra';
|
||||
import chokidar from 'chokidar';
|
||||
import { event_status_enum } from '@prisma/client';
|
||||
import { Logger } from '../Logger';
|
||||
import { getConfig } from '../TipiConfig';
|
||||
import { prisma } from '../../db/client';
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var EventDispatcher: EventDispatcher | undefined;
|
||||
var EventDispatcher: EventDispatcherClass | undefined;
|
||||
}
|
||||
|
||||
export const EVENT_TYPES = {
|
||||
|
@ -18,149 +21,59 @@ export const EVENT_TYPES = {
|
|||
APP: 'app',
|
||||
SYSTEM_INFO: 'system_info',
|
||||
} as const;
|
||||
|
||||
export type EventType = (typeof EVENT_TYPES)[keyof typeof EVENT_TYPES];
|
||||
|
||||
type SystemEvent = {
|
||||
id: string;
|
||||
type: EventType;
|
||||
args: string[];
|
||||
creationDate: Date;
|
||||
const WATCH_FOLDER = '/runtipi/state/test-events';
|
||||
|
||||
const getInfoFromFile = (path: string) => {
|
||||
const file = fs.readFileSync(path, 'utf8');
|
||||
|
||||
const [type, id, status] = file.split(' ');
|
||||
|
||||
return { type, id, status };
|
||||
};
|
||||
|
||||
const EVENT_STATUS = {
|
||||
RUNNING: 'running',
|
||||
SUCCESS: 'success',
|
||||
ERROR: 'error',
|
||||
WAITING: 'waiting',
|
||||
} as const;
|
||||
|
||||
type EventStatus = (typeof EVENT_STATUS)[keyof typeof EVENT_STATUS];
|
||||
|
||||
const WATCH_FILE = '/runtipi/state/events';
|
||||
|
||||
// File state example:
|
||||
// restart 1631231231231 running "arg1 arg2"
|
||||
class EventDispatcher {
|
||||
private static instance: EventDispatcher | null;
|
||||
|
||||
private dispatcherId = EventDispatcher.generateId();
|
||||
|
||||
private queue: SystemEvent[] = [];
|
||||
|
||||
private lock: SystemEvent | null = null;
|
||||
|
||||
private interval: NodeJS.Timer;
|
||||
export class EventDispatcherClass {
|
||||
private static instance: EventDispatcherClass | null;
|
||||
|
||||
private intervals: NodeJS.Timer[] = [];
|
||||
|
||||
private watcher = chokidar.watch(WATCH_FOLDER, {});
|
||||
|
||||
private prisma = prisma;
|
||||
|
||||
constructor() {
|
||||
const timer = this.pollQueue();
|
||||
this.interval = timer;
|
||||
this.watcher.on('change', this.onFileChange);
|
||||
}
|
||||
|
||||
public static getInstance(): EventDispatcher {
|
||||
if (!EventDispatcher.instance) {
|
||||
EventDispatcher.instance = new EventDispatcher();
|
||||
private async onFileChange(path: string) {
|
||||
Logger.info(`File ${path} has been changed`);
|
||||
const { type, id, status } = getInfoFromFile(path);
|
||||
|
||||
Logger.info(`Event ${type} ${id} has status ${status}`);
|
||||
|
||||
if (!type || !id || !status) return;
|
||||
|
||||
if (status === 'success' || status === 'error') {
|
||||
Logger.info(`Deleting event ${type} ${id} as it has status ${status}`);
|
||||
console.log(prisma.event);
|
||||
await this.prisma.event.delete({ where: { id: Number(id) } });
|
||||
}
|
||||
return EventDispatcher.instance;
|
||||
|
||||
Logger.info(`Updating event ${type} ${id} with status ${status}`);
|
||||
await this.prisma.event.update({
|
||||
where: { id: Number(id) },
|
||||
data: { status: status as event_status_enum },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random task id
|
||||
*
|
||||
* @returns {string} id - Randomly generated id
|
||||
*/
|
||||
static generateId() {
|
||||
return Math.random().toString(36).substring(2, 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect lock status and clean queue if event is done
|
||||
*/
|
||||
private collectLockStatusAndClean() {
|
||||
if (!this.lock) {
|
||||
return;
|
||||
public static getInstance() {
|
||||
if (!EventDispatcherClass.instance) {
|
||||
EventDispatcherClass.instance = new EventDispatcherClass();
|
||||
}
|
||||
|
||||
const status = this.getEventStatus(this.lock.id);
|
||||
|
||||
if (status === 'running' || status === 'waiting') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.clearEvent(this.lock, status);
|
||||
this.lock = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll queue and run events
|
||||
*/
|
||||
private pollQueue() {
|
||||
Logger.info(`EventDispatcher(${this.dispatcherId}): Polling queue...`);
|
||||
|
||||
if (!this.interval) {
|
||||
const id = setInterval(() => {
|
||||
this.runEvent();
|
||||
this.collectLockStatusAndClean();
|
||||
}, 1000);
|
||||
this.intervals.push(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
return this.interval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run event from the queue if there is no lock
|
||||
*/
|
||||
private async runEvent() {
|
||||
if (this.lock) {
|
||||
return;
|
||||
}
|
||||
|
||||
const event = this.queue[0];
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lock = event;
|
||||
|
||||
// Write event to state file
|
||||
const args = event.args.join(' ');
|
||||
const line = `${event.type} ${event.id} waiting ${args}`;
|
||||
fs.writeFileSync(WATCH_FILE, `${line}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check event status
|
||||
*
|
||||
* @param {string} id - Event id
|
||||
* @returns {EventStatus} - Event status
|
||||
*/
|
||||
private getEventStatus(id: string): EventStatus {
|
||||
const event = this.queue.find((e) => e.id === id);
|
||||
|
||||
if (!event) {
|
||||
return 'success';
|
||||
}
|
||||
|
||||
// if event was created more than 3 minutes ago, it's an error
|
||||
if (new Date().getTime() - event.creationDate.getTime() > 5 * 60 * 1000) {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
const file = fs.readFileSync(WATCH_FILE, 'utf8');
|
||||
const lines = file?.split('\n') || [];
|
||||
const line = lines.find((l) => l.startsWith(`${event.type} ${event.id}`));
|
||||
|
||||
if (!line) {
|
||||
return 'waiting';
|
||||
}
|
||||
|
||||
const status = line.split(' ')[2] as EventStatus;
|
||||
|
||||
return status;
|
||||
return EventDispatcherClass.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,19 +81,16 @@ class EventDispatcher {
|
|||
*
|
||||
* @param {EventType} type - Event type
|
||||
* @param {[string]} args - Event arguments
|
||||
* @returns {SystemEvent} event - Event object
|
||||
* @returns {event} - The event created
|
||||
*/
|
||||
public dispatchEvent(type: EventType, args?: string[]): SystemEvent {
|
||||
const event: SystemEvent = {
|
||||
id: EventDispatcher.generateId(),
|
||||
type,
|
||||
args: args || [],
|
||||
creationDate: new Date(),
|
||||
};
|
||||
public async dispatchEvent(type: EventType, args?: string[]) {
|
||||
const newEvent = await this.prisma.event.create({
|
||||
data: { type, status: 'waiting', message: '', args: args ? args.join(' ') : '' },
|
||||
});
|
||||
const line = `${newEvent.type} ${newEvent.id} waiting ${args}`;
|
||||
fs.writeFileSync(`${WATCH_FOLDER}/${newEvent.id}`, `${line}`);
|
||||
|
||||
this.queue.push(event);
|
||||
|
||||
return event;
|
||||
return newEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -189,19 +99,19 @@ class EventDispatcher {
|
|||
* @param {SystemEvent} event - The event to clear
|
||||
* @param {EventStatus} status - The status to consider the event to
|
||||
*/
|
||||
private clearEvent(event: SystemEvent, status: EventStatus = 'success') {
|
||||
this.queue = this.queue.filter((e) => e.id !== event.id);
|
||||
if (fs.existsSync(`/app/logs/${event.id}.log`)) {
|
||||
const log = fs.readFileSync(`/app/logs/${event.id}.log`, 'utf8');
|
||||
if (log && status === 'error') {
|
||||
Logger.error(`EventDispatcher: ${event.type} ${event.id} failed with error: ${log}`);
|
||||
} else if (log) {
|
||||
Logger.info(`EventDispatcher: ${event.type} ${event.id} finished with message: ${log}`);
|
||||
}
|
||||
fs.unlinkSync(`/app/logs/${event.id}.log`);
|
||||
}
|
||||
fs.writeFileSync(WATCH_FILE, '');
|
||||
}
|
||||
// private clearEvent(event: SystemEvent, status: EventStatus = 'success') {
|
||||
// this.queue = this.queue.filter((e) => e.id !== event.id);
|
||||
// if (fs.existsSync(`/app/logs/${event.id}.log`)) {
|
||||
// const log = fs.readFileSync(`/app/logs/${event.id}.log`, 'utf8');
|
||||
// if (log && status === 'error') {
|
||||
// Logger.error(`EventDispatcher: ${event.type} ${event.id} failed with error: ${log}`);
|
||||
// } else if (log) {
|
||||
// Logger.info(`EventDispatcher: ${event.type} ${event.id} finished with message: ${log}`);
|
||||
// }
|
||||
// fs.unlinkSync(`/app/logs/${event.id}.log`);
|
||||
// }
|
||||
// fs.writeFileSync(WATCH_FILE, '');
|
||||
// }
|
||||
|
||||
/**
|
||||
* Dispatch an event to the queue and wait for it to finish
|
||||
|
@ -211,12 +121,14 @@ class EventDispatcher {
|
|||
* @returns - Promise that resolves when the event is done
|
||||
*/
|
||||
public async dispatchEventAsync(type: EventType, args?: string[]): Promise<{ success: boolean; stdout?: string }> {
|
||||
const event = this.dispatchEvent(type, args);
|
||||
const event = await this.dispatchEvent(type, args);
|
||||
const path = `${WATCH_FOLDER}/${event.id}`;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const interval = setInterval(() => {
|
||||
this.intervals.push(interval);
|
||||
const status = this.getEventStatus(event.id);
|
||||
let { status } = event;
|
||||
|
||||
do {
|
||||
status = getInfoFromFile(path).status as event_status_enum;
|
||||
|
||||
let log = '';
|
||||
if (fs.existsSync(`/app/logs/${event.id}.log`)) {
|
||||
|
@ -224,26 +136,20 @@ class EventDispatcher {
|
|||
}
|
||||
|
||||
if (status === 'success') {
|
||||
clearInterval(interval);
|
||||
resolve({ success: true, stdout: log });
|
||||
} else if (status === 'error') {
|
||||
clearInterval(interval);
|
||||
resolve({ success: false, stdout: log });
|
||||
}
|
||||
}, 100);
|
||||
} while (status !== 'success' && status !== 'error');
|
||||
});
|
||||
}
|
||||
|
||||
public clearInterval() {
|
||||
clearInterval(this.interval);
|
||||
this.intervals.forEach((i) => clearInterval(i));
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.queue = [];
|
||||
this.lock = null;
|
||||
EventDispatcher.instance = null;
|
||||
fs.writeFileSync(WATCH_FILE, '');
|
||||
public static clear() {
|
||||
EventDispatcherClass.instance = null;
|
||||
// Detlete all events from watch folder
|
||||
fs.readdirSync(WATCH_FOLDER).forEach((file) => {
|
||||
fs.unlinkSync(`${WATCH_FOLDER}/${file}`);
|
||||
});
|
||||
}
|
||||
|
||||
public scheduleEvent(params: { type: EventType; args?: string[]; cronExpression: string }) {
|
||||
|
@ -255,7 +161,7 @@ class EventDispatcher {
|
|||
}
|
||||
}
|
||||
|
||||
export const EventDispatcherInstance = global.EventDispatcher || EventDispatcher.getInstance();
|
||||
export const EventDispatcherInstance = global.EventDispatcher || EventDispatcherClass.getInstance();
|
||||
|
||||
if (getConfig().NODE_ENV !== 'production') {
|
||||
global.EventDispatcher = EventDispatcherInstance;
|
||||
|
|
|
@ -9,6 +9,7 @@ import { Logger } from './core/Logger';
|
|||
import { runPostgresMigrations } from './run-migration';
|
||||
import { AppServiceClass } from './services/apps/apps.service';
|
||||
import { prisma } from './db/client';
|
||||
import { EventDispatcherClass } from './core/EventDispatcher/EventDispatcher';
|
||||
|
||||
let conf = {};
|
||||
let nextApp: NextServer;
|
||||
|
@ -43,7 +44,7 @@ nextApp.prepare().then(async () => {
|
|||
|
||||
app.listen(port, async () => {
|
||||
const appService = new AppServiceClass(prisma);
|
||||
EventDispatcher.clear();
|
||||
EventDispatcherClass.clear();
|
||||
|
||||
// Run database migrations
|
||||
await runPostgresMigrations();
|
||||
|
@ -55,7 +56,10 @@ nextApp.prepare().then(async () => {
|
|||
|
||||
// Scheduled events
|
||||
EventDispatcher.scheduleEvent({ type: 'update_repo', args: [getConfig().appsRepoUrl], cronExpression: '*/30 * * * *' });
|
||||
EventDispatcher.scheduleEvent({ type: 'system_info', args: [], cronExpression: '* * * * *' });
|
||||
EventDispatcher.scheduleEvent({ type: 'system_info', args: [], cronExpression: '*/5 * * * * *' });
|
||||
|
||||
// Every 5 sec
|
||||
// EventDispatcher.scheduleEvent({ type: 'system_info', args: [], cronExpression: '*/5 * * * * *' });
|
||||
|
||||
appService.startAllApps();
|
||||
|
||||
|
|
31
src/server/migrations/00006-add-event-table.sql
Normal file
31
src/server/migrations/00006-add-event-table.sql
Normal file
|
@ -0,0 +1,31 @@
|
|||
-- Create enum for event type running, success, error, waiting if not exists
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
pg_type
|
||||
WHERE
|
||||
typname = 'event_status_enum') THEN
|
||||
CREATE TYPE "public"."event_status_enum" AS ENUM (
|
||||
'running',
|
||||
'success',
|
||||
'error',
|
||||
'waiting'
|
||||
);
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- Create event table
|
||||
CREATE TABLE IF NOT EXISTS "event" (
|
||||
"id" serial NOT NULL,
|
||||
"status" "public"."event_status_enum" NOT NULL,
|
||||
"message" character varying NOT NULL,
|
||||
"type" character varying NOT NULL,
|
||||
"args" character varying[] NOT NULL,
|
||||
"createdAt" timestamp NOT NULL DEFAULT now(),
|
||||
"updatedAt" timestamp NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY ("id")
|
||||
);
|
Loading…
Reference in a new issue