wip: advanced deployment settings

This commit is contained in:
Derock 2024-01-20 12:49:53 -05:00
parent 0c7526f506
commit 6dc69ce517
No known key found for this signature in database
11 changed files with 616 additions and 100 deletions

View file

@ -26,6 +26,7 @@
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
@ -88,7 +89,7 @@
"@typescript-eslint/eslint-plugin": "^6.17.0",
"@typescript-eslint/parser": "^6.17.0",
"autoprefixer": "^10.4.16",
"drizzle-kit": "^0.20.9",
"drizzle-kit": "^0.20.13",
"eslint": "^8.56.0",
"eslint-config-next": "^14.0.4",
"json-schema-to-typescript": "^13.1.1",

View file

@ -16,7 +16,7 @@ dependencies:
version: 0.0.3
'@prisma/migrate':
specifier: ^5.7.1
version: 5.7.1(@prisma/generator-helper@5.7.1)(@prisma/internals@5.7.1)
version: 5.7.1(@prisma/generator-helper@5.8.1)(@prisma/internals@5.8.1)
'@radix-ui/react-checkbox':
specifier: ^1.0.4
version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
@ -32,6 +32,9 @@ dependencies:
'@radix-ui/react-label':
specifier: ^2.0.2
version: 2.0.2(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-select':
specifier: ^2.0.0
version: 2.0.0(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-separator':
specifier: ^1.0.3
version: 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
@ -61,10 +64,10 @@ dependencies:
version: 11.0.0-next-alpha.150
'@uiw/codemirror-extensions-langs':
specifier: ^4.21.21
version: 4.21.21(@codemirror/autocomplete@6.11.1)(@codemirror/language-data@6.3.1)(@codemirror/language@6.10.0)(@codemirror/legacy-modes@6.3.3)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.12)(@lezer/lr@1.3.14)
version: 4.21.21(@codemirror/autocomplete@6.12.0)(@codemirror/language-data@6.3.1)(@codemirror/language@6.10.0)(@codemirror/legacy-modes@6.3.3)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.13)(@lezer/lr@1.3.14)
'@uiw/react-codemirror':
specifier: ^4.21.21
version: 4.21.21(@babel/runtime@7.23.7)(@codemirror/autocomplete@6.11.1)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.23.0)(codemirror@6.0.1)(react-dom@18.2.0)(react@18.2.0)
version: 4.21.21(@babel/runtime@7.23.8)(@codemirror/autocomplete@6.12.0)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.23.0)(codemirror@6.0.1)(react-dom@18.2.0)(react@18.2.0)
argon2:
specifier: ^0.31.2
version: 0.31.2
@ -215,8 +218,8 @@ devDependencies:
specifier: ^10.4.16
version: 10.4.16(postcss@8.4.32)
drizzle-kit:
specifier: ^0.20.9
version: 0.20.9
specifier: ^0.20.13
version: 0.20.13
eslint:
specifier: ^8.56.0
version: 8.56.0
@ -274,6 +277,13 @@ packages:
dependencies:
regenerator-runtime: 0.14.1
/@babel/runtime@7.23.8:
resolution: {integrity: sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==}
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.14.1
dev: false
/@balena/dockerignore@1.0.2:
resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==}
dev: false
@ -302,6 +312,34 @@ packages:
'@lezer/common': 1.2.0
dev: false
/@codemirror/autocomplete@6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1):
resolution: {integrity: sha512-L5UInv8Ffd6BPw0P3EF7JLYAMeEbclY7+6Q11REt8vhih8RuLreKtPy/xk8wPxs4EQgYqzI7cdgpiYwWlbS/ow==}
peerDependencies:
'@codemirror/language': ^6.0.0
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
'@lezer/common': ^1.0.0
dependencies:
'@codemirror/language': 6.10.0
'@codemirror/state': 6.4.0
'@codemirror/view': 6.23.0
'@lezer/common': 1.2.1
dev: false
/@codemirror/autocomplete@6.12.0(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1):
resolution: {integrity: sha512-r4IjdYFthwbCQyvqnSlx0WBHRHi8nBvU+WjJxFUij81qsBfhNudf/XKKmmC2j3m0LaOYUQTf3qiEK1J8lO1sdg==}
peerDependencies:
'@codemirror/language': ^6.0.0
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
'@lezer/common': ^1.0.0
dependencies:
'@codemirror/language': 6.10.0
'@codemirror/state': 6.4.0
'@codemirror/view': 6.23.0
'@lezer/common': 1.2.1
dev: false
/@codemirror/commands@6.3.3:
resolution: {integrity: sha512-dO4hcF0fGT9tu1Pj1D2PvGvxjeGkbC6RGcZw6Qs74TH+Ed1gw98jmUgd2axWvIZEqTeTuFrg1lEB1KV6cK9h1A==}
dependencies:
@ -424,6 +462,18 @@ packages:
'@lezer/markdown': 1.2.0
dev: false
/@codemirror/lang-markdown@6.2.4:
resolution: {integrity: sha512-UghkA1vSMs8bT7RSZM6vsIocigyah2bV00eRQuZy76401UmFZdsTsbQNBGdyxRQDOLeEvF5iFwap0BM8LKyd+g==}
dependencies:
'@codemirror/autocomplete': 6.12.0(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/lang-html': 6.4.7
'@codemirror/language': 6.10.0
'@codemirror/state': 6.4.0
'@codemirror/view': 6.23.0
'@lezer/common': 1.2.1
'@lezer/markdown': 1.2.0
dev: false
/@codemirror/lang-php@6.0.1:
resolution: {integrity: sha512-ublojMdw/PNWa7qdN5TMsjmqkNuTBD3k6ndZ4Z0S25SBAiweFGyY68AS3xNcIOlb6DDFDvKlinLQ40vSLqf8xA==}
dependencies:
@ -434,10 +484,10 @@ packages:
'@lezer/php': 1.0.2
dev: false
/@codemirror/lang-python@6.1.3(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0):
/@codemirror/lang-python@6.1.3(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1):
resolution: {integrity: sha512-S9w2Jl74hFlD5nqtUMIaXAq9t5WlM0acCkyuQWUUSvZclk1sV+UfnpFiZzuZSG+hfEaOmxKR5UxY/Uxswn7EhQ==}
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/language': 6.10.0
'@lezer/python': 1.1.10
transitivePeerDependencies:
@ -510,7 +560,7 @@ packages:
- '@codemirror/view'
dev: false
/@codemirror/language-data@6.3.1(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0):
/@codemirror/language-data@6.3.1(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1):
resolution: {integrity: sha512-p6jhJmvhGe1TG1EGNhwH7nFWWFSTJ8NDKnB2fVx5g3t+PpO0+63R7GJNxjS0TmmH3cdMxZbzejsik+rlEh1EyQ==}
dependencies:
'@codemirror/lang-angular': 0.1.3
@ -521,9 +571,9 @@ packages:
'@codemirror/lang-javascript': 6.2.1
'@codemirror/lang-json': 6.0.1
'@codemirror/lang-less': 6.0.2(@codemirror/view@6.23.0)
'@codemirror/lang-markdown': 6.2.3
'@codemirror/lang-markdown': 6.2.4
'@codemirror/lang-php': 6.0.1
'@codemirror/lang-python': 6.1.3(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/lang-python': 6.1.3(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/lang-rust': 6.0.1
'@codemirror/lang-sass': 6.0.2(@codemirror/view@6.23.0)
'@codemirror/lang-sql': 6.5.5(@codemirror/view@6.23.0)
@ -605,8 +655,8 @@ packages:
kuler: 2.0.0
dev: false
/@drizzle-team/studio@0.0.37:
resolution: {integrity: sha512-LZyAPGJBX43jsrVZh7+w1Jig/BC6PJx63ReHUYK+GRQYNY9UJNlPXmn1uC/LMRX+A7JwYM4Sr4Fg/hnJSqlfgA==}
/@drizzle-team/studio@0.0.39:
resolution: {integrity: sha512-c5Hkm7MmQC2n5qAsKShjQrHoqlfGslB8+qWzsGGZ+2dHMRTNG60UuzalF0h0rvBax5uzPXuGkYLGaQ+TUX3yMw==}
dependencies:
superjson: 2.2.1
dev: true
@ -1186,6 +1236,10 @@ packages:
resolution: {integrity: sha512-Wmvlm4q6tRpwiy20TnB3yyLTZim38Tkc50dPY8biQRwqE+ati/wD84rm3N15hikvdT4uSg9phs9ubjvcLmkpKg==}
dev: false
/@lezer/common@1.2.1:
resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==}
dev: false
/@lezer/cpp@1.1.2:
resolution: {integrity: sha512-macwKtyeUO0EW86r3xWQCzOV9/CF8imJLpJlPv3sDY57cPGeUZ8gXWOWNlJr52TVByMV3PayFQCA5SHEERDmVQ==}
dependencies:
@ -1237,6 +1291,14 @@ packages:
'@lezer/lr': 1.3.14
dev: false
/@lezer/javascript@1.4.13:
resolution: {integrity: sha512-5IBr8LIO3xJdJH1e9aj/ZNLE4LSbdsx25wFmGRAZsj2zSmwAYjx26JyU/BYOCpRQlu1jcv1z3vy4NB9+UkfRow==}
dependencies:
'@lezer/common': 1.2.1
'@lezer/highlight': 1.2.0
'@lezer/lr': 1.3.14
dev: false
/@lezer/json@1.0.2:
resolution: {integrity: sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==}
dependencies:
@ -1498,32 +1560,40 @@ packages:
resolution: {integrity: sha512-yrVSO/YZOxdeIxcBtZ5BaNqUfPrZkNsAKQIQg36cJKMxj/VYK3Vk5jMKkI+gQLl0KReo1YvX8GWKfV788SELjw==}
dev: false
/@prisma/debug@5.8.1:
resolution: {integrity: sha512-tjuw7eA0Us3T42jx9AmAgL58rzwzpFGYc3R7Y4Ip75EBYrKMBA1YihuWMcBC92ILmjlQ/u3p8VxcIE0hr+fZfg==}
dev: false
/@prisma/engines-version@5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5:
resolution: {integrity: sha512-dIR5IQK/ZxEoWRBDOHF87r1Jy+m2ih3Joi4vzJRP+FOj5yxCwS2pS5SBR3TWoVnEK1zxtLI/3N7BjHyGF84fgw==}
dev: false
/@prisma/engines@5.7.1:
resolution: {integrity: sha512-R+Pqbra8tpLP2cvyiUpx+SIKglav3nTCpA+rn6826CThviQ8yvbNG0s8jNpo51vS9FuZO3pOkARqG062vKX7uA==}
/@prisma/engines-version@5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2:
resolution: {integrity: sha512-f5C3JM3l9yhGr3cr4FMqWloFaSCpNpMi58Om22rjD2DOz3owci2mFdFXMgnAGazFPKrCbbEhcxdsRfspEYRoFQ==}
dev: false
/@prisma/engines@5.8.1:
resolution: {integrity: sha512-TJgYLRrZr56uhqcXO4GmP5be+zjCIHtLDK20Cnfg+o9d905hsN065QOL+3Z0zQAy6YD31Ol4u2kzSfRmbJv/uA==}
requiresBuild: true
dependencies:
'@prisma/debug': 5.7.1
'@prisma/engines-version': 5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5
'@prisma/fetch-engine': 5.7.1
'@prisma/get-platform': 5.7.1
'@prisma/debug': 5.8.1
'@prisma/engines-version': 5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2
'@prisma/fetch-engine': 5.8.1
'@prisma/get-platform': 5.8.1
dev: false
/@prisma/fetch-engine@5.7.1:
resolution: {integrity: sha512-9ELauIEBkIaEUpMIYPRlh5QELfoC6pyHolHVQgbNxglaINikZ9w9X7r1TIePAcm05pCNp2XPY1ObQIJW5nYfBQ==}
/@prisma/fetch-engine@5.8.1:
resolution: {integrity: sha512-+bgjjoSFa6uYEbAPlklfoVSStOEfcpheOjoBoNsNNSQdSzcwE2nM4Q0prun0+P8/0sCHo18JZ9xqa8gObvgOUw==}
dependencies:
'@prisma/debug': 5.7.1
'@prisma/engines-version': 5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5
'@prisma/get-platform': 5.7.1
'@prisma/debug': 5.8.1
'@prisma/engines-version': 5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2
'@prisma/get-platform': 5.8.1
dev: false
/@prisma/generator-helper@5.7.1:
resolution: {integrity: sha512-BiaCt3YtMnjAoqJ51rVSkvlPk0p7ErjmgFOjRUmAE/m75E9tJmFtgT6NWzXiX6KWs2OvnVuAqNY7imK6ZwlExA==}
/@prisma/generator-helper@5.8.1:
resolution: {integrity: sha512-2EDd0o+GHfbX1dtw5BnfOz3hQB7AtYrwe4YNiKfo2UDBvB/ne/ChZa3b/vBm/GKpjW2Xaymct8D9oIHev3juzQ==}
dependencies:
'@prisma/debug': 5.7.1
'@prisma/debug': 5.8.1
dev: false
/@prisma/get-platform@5.7.1:
@ -1532,20 +1602,26 @@ packages:
'@prisma/debug': 5.7.1
dev: false
/@prisma/internals@5.7.1:
resolution: {integrity: sha512-kOKzfPYcOh25h48H/WLNnQzrcV54U4/0ORsagF7ude28RziB4mvlwGtjcEaQVhzGV1eFV5Ir8jtDtNUPAKuikA==}
/@prisma/get-platform@5.8.1:
resolution: {integrity: sha512-wnA+6HTFcY+tkykMokix9GiAkaauPC5W/gg0O5JB0J8tCTNWrqpnQ7AsaGRfkYUbeOIioh6woDjQrGTTRf1Zag==}
dependencies:
'@prisma/debug': 5.7.1
'@prisma/engines': 5.7.1
'@prisma/fetch-engine': 5.7.1
'@prisma/generator-helper': 5.7.1
'@prisma/get-platform': 5.7.1
'@prisma/prisma-schema-wasm': 5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5
'@prisma/debug': 5.8.1
dev: false
/@prisma/internals@5.8.1:
resolution: {integrity: sha512-9okoCgLeMqql58IbEG3YmzgNLRUQdN+qZUYp2DojWC7VAmL9TSOKQ5Dcc0588cKAsCBBDUQ2jfdflorYkzeFKw==}
dependencies:
'@prisma/debug': 5.8.1
'@prisma/engines': 5.8.1
'@prisma/fetch-engine': 5.8.1
'@prisma/generator-helper': 5.8.1
'@prisma/get-platform': 5.8.1
'@prisma/prisma-schema-wasm': 5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2
arg: 5.0.2
prompts: 2.4.2
dev: false
/@prisma/migrate@5.7.1(@prisma/generator-helper@5.7.1)(@prisma/internals@5.7.1):
/@prisma/migrate@5.7.1(@prisma/generator-helper@5.8.1)(@prisma/internals@5.8.1):
resolution: {integrity: sha512-wcb+HaWs+KSbjDUw09UXNfExMspzVhVz5Tg+bU2VdskModaueOfHeckfGIuIYlMWSveweV4Evv0NsMmZSrhp0w==}
peerDependencies:
'@prisma/generator-helper': '*'
@ -1553,14 +1629,20 @@ packages:
dependencies:
'@prisma/debug': 5.7.1
'@prisma/engines-version': 5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5
'@prisma/generator-helper': 5.7.1
'@prisma/generator-helper': 5.8.1
'@prisma/get-platform': 5.7.1
'@prisma/internals': 5.7.1
'@prisma/internals': 5.8.1
prompts: 2.4.2
dev: false
/@prisma/prisma-schema-wasm@5.7.1-1.0ca5ccbcfa6bdc81c003cf549abe4269f59c41e5:
resolution: {integrity: sha512-woHCFsEQ8DyYT9mTlO++iWSw9WP7cVtH2d3P4VQ521qQlPCUpozEbFszyCLkRJPXcGi4ci9J6v4mw/v5RsdDzA==}
/@prisma/prisma-schema-wasm@5.8.1-1.78caf6feeaed953168c64e15a249c3e9a033ebe2:
resolution: {integrity: sha512-UAJANliORe2V/s7yDMx5EKOCj2PIbwX7yusKckxMBDb+ozaQF31c3CBwnZW/ZEdhBoZjrKw8bQlqwZudWXmiKA==}
dev: false
/@radix-ui/number@1.0.1:
resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==}
dependencies:
'@babel/runtime': 7.23.7
dev: false
/@radix-ui/primitive@1.0.1:
@ -2012,6 +2094,47 @@ packages:
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-select@2.0.0(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-RH5b7af4oHtkcHS7pG6Sgv5rk5Wxa7XI8W5gvB1N/yiuDGZxko1ynvOiVhFM7Cis2A8zxF9bTOUVbRDzPepe6w==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.23.7
'@radix-ui/number': 1.0.1
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-id': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.46)(react@18.2.0)
'@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.46
'@types/react-dom': 18.2.18
aria-hidden: 1.2.3
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-remove-scroll: 2.5.5(@types/react@18.2.46)(react@18.2.0)
dev: false
/@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
peerDependencies:
@ -2178,13 +2301,34 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.23.7
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.46
'@types/react-dom': 18.2.18
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/rect@1.0.1:
resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
dependencies:
'@babel/runtime': 7.23.7
dev: false
/@replit/codemirror-lang-csharp@6.2.0(@codemirror/autocomplete@6.11.1)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14):
/@replit/codemirror-lang-csharp@6.2.0(@codemirror/autocomplete@6.12.0)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14):
resolution: {integrity: sha512-6utbaWkoymhoAXj051mkRp+VIJlpwUgCX9Toevz3YatiZsz512fw3OVCedXQx+WcR0wb6zVHjChnuxqfCLtFVQ==}
peerDependencies:
'@codemirror/autocomplete': ^6.0.0
@ -2195,16 +2339,16 @@ packages:
'@lezer/highlight': ^1.0.0
'@lezer/lr': ^1.0.0
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/autocomplete': 6.12.0(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/language': 6.10.0
'@codemirror/state': 6.4.0
'@codemirror/view': 6.23.0
'@lezer/common': 1.2.0
'@lezer/common': 1.2.1
'@lezer/highlight': 1.2.0
'@lezer/lr': 1.3.14
dev: false
/@replit/codemirror-lang-nix@6.0.1(@codemirror/autocomplete@6.11.1)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14):
/@replit/codemirror-lang-nix@6.0.1(@codemirror/autocomplete@6.12.0)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14):
resolution: {integrity: sha512-lvzjoYn9nfJzBD5qdm3Ut6G3+Or2wEacYIDJ49h9+19WSChVnxv4ojf+rNmQ78ncuxIt/bfbMvDLMeMP0xze6g==}
peerDependencies:
'@codemirror/autocomplete': ^6.0.0
@ -2215,11 +2359,11 @@ packages:
'@lezer/highlight': ^1.0.0
'@lezer/lr': ^1.0.0
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/autocomplete': 6.12.0(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/language': 6.10.0
'@codemirror/state': 6.4.0
'@codemirror/view': 6.23.0
'@lezer/common': 1.2.0
'@lezer/common': 1.2.1
'@lezer/highlight': 1.2.0
'@lezer/lr': 1.3.14
dev: false
@ -2232,7 +2376,7 @@ packages:
'@codemirror/language': 6.10.0
dev: false
/@replit/codemirror-lang-svelte@6.0.0(@codemirror/autocomplete@6.11.1)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.7)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.12)(@lezer/lr@1.3.14):
/@replit/codemirror-lang-svelte@6.0.0(@codemirror/autocomplete@6.12.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.7)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.13)(@lezer/lr@1.3.14):
resolution: {integrity: sha512-U2OqqgMM6jKelL0GNWbAmqlu1S078zZNoBqlJBW+retTc5M4Mha6/Y2cf4SVg6ddgloJvmcSpt4hHrVoM4ePRA==}
peerDependencies:
'@codemirror/autocomplete': ^6.0.0
@ -2247,16 +2391,16 @@ packages:
'@lezer/javascript': ^1.2.0
'@lezer/lr': ^1.0.0
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/autocomplete': 6.12.0(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/lang-css': 6.2.1(@codemirror/view@6.23.0)
'@codemirror/lang-html': 6.4.7
'@codemirror/lang-javascript': 6.2.1
'@codemirror/language': 6.10.0
'@codemirror/state': 6.4.0
'@codemirror/view': 6.23.0
'@lezer/common': 1.2.0
'@lezer/common': 1.2.1
'@lezer/highlight': 1.2.0
'@lezer/javascript': 1.4.12
'@lezer/javascript': 1.4.13
'@lezer/lr': 1.3.14
dev: false
@ -2841,7 +2985,7 @@ packages:
eslint-visitor-keys: 3.4.3
dev: true
/@uiw/codemirror-extensions-basic-setup@4.21.21(@codemirror/autocomplete@6.11.1)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0):
/@uiw/codemirror-extensions-basic-setup@4.21.21(@codemirror/autocomplete@6.12.0)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0):
resolution: {integrity: sha512-+0i9dPrRSa8Mf0CvyrMvnAhajnqwsP3IMRRlaHDRgsSGL8igc4z7MhvUPn+7cWFAAqWzQRhMdMSWzo6/TEa3EA==}
peerDependencies:
'@codemirror/autocomplete': '>=6.0.0'
@ -2852,7 +2996,7 @@ packages:
'@codemirror/state': '>=6.0.0'
'@codemirror/view': '>=6.0.0'
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/autocomplete': 6.12.0(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/commands': 6.3.3
'@codemirror/language': 6.10.0
'@codemirror/lint': 6.4.2
@ -2861,7 +3005,7 @@ packages:
'@codemirror/view': 6.23.0
dev: false
/@uiw/codemirror-extensions-langs@4.21.21(@codemirror/autocomplete@6.11.1)(@codemirror/language-data@6.3.1)(@codemirror/language@6.10.0)(@codemirror/legacy-modes@6.3.3)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.12)(@lezer/lr@1.3.14):
/@uiw/codemirror-extensions-langs@4.21.21(@codemirror/autocomplete@6.12.0)(@codemirror/language-data@6.3.1)(@codemirror/language@6.10.0)(@codemirror/legacy-modes@6.3.3)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.13)(@lezer/lr@1.3.14):
resolution: {integrity: sha512-h08pw2NeGLDgBiY8Ju5GNjfVzq1f6+wc0uPdqN5tkYBaKmByyKI10l5Gds7wBPzFH0uZlevP+Jyf9oSTcula5Q==}
peerDependencies:
'@codemirror/language-data': '>=6.0.0'
@ -2879,20 +3023,20 @@ packages:
'@codemirror/lang-liquid': 6.2.0
'@codemirror/lang-markdown': 6.2.3
'@codemirror/lang-php': 6.0.1
'@codemirror/lang-python': 6.1.3(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/lang-python': 6.1.3(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/lang-rust': 6.0.1
'@codemirror/lang-sass': 6.0.2(@codemirror/view@6.23.0)
'@codemirror/lang-sql': 6.5.5(@codemirror/view@6.23.0)
'@codemirror/lang-vue': 0.1.3
'@codemirror/lang-wast': 6.0.2
'@codemirror/lang-xml': 6.0.2(@codemirror/view@6.23.0)
'@codemirror/language-data': 6.3.1(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/language-data': 6.3.1(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/legacy-modes': 6.3.3
'@nextjournal/lang-clojure': 1.0.0
'@replit/codemirror-lang-csharp': 6.2.0(@codemirror/autocomplete@6.11.1)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14)
'@replit/codemirror-lang-nix': 6.0.1(@codemirror/autocomplete@6.11.1)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14)
'@replit/codemirror-lang-csharp': 6.2.0(@codemirror/autocomplete@6.12.0)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14)
'@replit/codemirror-lang-nix': 6.0.1(@codemirror/autocomplete@6.12.0)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/lr@1.3.14)
'@replit/codemirror-lang-solidity': 6.0.1(@codemirror/language@6.10.0)
'@replit/codemirror-lang-svelte': 6.0.0(@codemirror/autocomplete@6.11.1)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.7)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.12)(@lezer/lr@1.3.14)
'@replit/codemirror-lang-svelte': 6.0.0(@codemirror/autocomplete@6.12.0)(@codemirror/lang-css@6.2.1)(@codemirror/lang-html@6.4.7)(@codemirror/lang-javascript@6.2.1)(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)(@lezer/highlight@1.2.0)(@lezer/javascript@1.4.13)(@lezer/lr@1.3.14)
codemirror-lang-mermaid: 0.5.0
transitivePeerDependencies:
- '@codemirror/autocomplete'
@ -2905,7 +3049,7 @@ packages:
- '@lezer/lr'
dev: false
/@uiw/react-codemirror@4.21.21(@babel/runtime@7.23.7)(@codemirror/autocomplete@6.11.1)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.23.0)(codemirror@6.0.1)(react-dom@18.2.0)(react@18.2.0):
/@uiw/react-codemirror@4.21.21(@babel/runtime@7.23.8)(@codemirror/autocomplete@6.12.0)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.23.0)(codemirror@6.0.1)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-PaxBMarufMWoR0qc5zuvBSt76rJ9POm9qoOaJbqRmnNL2viaF+d+Paf2blPSlm1JSnqn7hlRjio+40nZJ9TKzw==}
peerDependencies:
'@babel/runtime': '>=7.11.0'
@ -2916,13 +3060,13 @@ packages:
react: '>=16.8.0'
react-dom: '>=16.8.0'
dependencies:
'@babel/runtime': 7.23.7
'@babel/runtime': 7.23.8
'@codemirror/commands': 6.3.3
'@codemirror/state': 6.4.0
'@codemirror/theme-one-dark': 6.1.2
'@codemirror/view': 6.23.0
'@uiw/codemirror-extensions-basic-setup': 4.21.21(@codemirror/autocomplete@6.11.1)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)
codemirror: 6.0.1(@lezer/common@1.2.0)
'@uiw/codemirror-extensions-basic-setup': 4.21.21(@codemirror/autocomplete@6.12.0)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)
codemirror: 6.0.1(@lezer/common@1.2.1)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
transitivePeerDependencies:
@ -3536,10 +3680,10 @@ packages:
'@lezer/lr': 1.3.14
dev: false
/codemirror@6.0.1(@lezer/common@1.2.0):
/codemirror@6.0.1(@lezer/common@1.2.1):
resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==}
dependencies:
'@codemirror/autocomplete': 6.11.1(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.0)
'@codemirror/autocomplete': 6.12.0(@codemirror/language@6.10.0)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)(@lezer/common@1.2.1)
'@codemirror/commands': 6.3.3
'@codemirror/language': 6.10.0
'@codemirror/lint': 6.4.2
@ -4014,11 +4158,11 @@ packages:
wordwrap: 1.0.0
dev: true
/drizzle-kit@0.20.9:
resolution: {integrity: sha512-5oIbPFdfEEfzVSOB3MWGt70VSHv6W7qMAWCJ5xc6W1BxgGASipxuAuyXD59fx9S6QYTNNnuSuQFoIdnNTRWY2A==}
/drizzle-kit@0.20.13:
resolution: {integrity: sha512-j9oZSQXNWG+KBJm0Sg3S/zJpncHGKnpqNfFuM4NUxUMGTcihDHhP9SW6Jncqwb5vsP1Xm0a8JLm3PZUIspC/oA==}
hasBin: true
dependencies:
'@drizzle-team/studio': 0.0.37
'@drizzle-team/studio': 0.0.39
'@esbuild-kit/esm-loader': 2.6.5
camelcase: 7.0.1
chalk: 5.3.0

View file

@ -17,7 +17,7 @@ import {
} from "~/components/ui/dialog";
import { Form } from "~/components/ui/form";
import { Input } from "~/components/ui/input";
import { FormField, useForm } from "~/hooks/forms";
import { SimpleFormField, useForm } from "~/hooks/forms";
import { zDockerName } from "~/server/utils/zod";
import { api } from "~/trpc/react";
import { useProject } from "../_context/ProjectContext";
@ -73,7 +73,7 @@ export function CreateService() {
}),
)}
>
<FormField
<SimpleFormField
control={form.control}
name="name"
friendlyName="Service Name"

View file

@ -0,0 +1,21 @@
"use client";
import { api } from "~/trpc/react";
import { useProject } from "../../../_context/ProjectContext";
/**
* Returns detailed information about a service (or the one currently navigated to)
*/
export function useService(serviceId?: string) {
const project = useProject();
serviceId ??= project?.selectedService?.id;
if (!serviceId) {
throw new Error("No service ID provided");
}
return api.projects.services.get.useQuery({
projectId: project.id,
serviceId,
});
}

View file

@ -0,0 +1,136 @@
"use client";
import { z } from "zod";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "~/components/ui/form";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "~/components/ui/select";
import { FormSubmit, SimpleFormField, useForm } from "~/hooks/forms";
import { DOCKER_DEPLOY_MODE_MAP, DockerDeployMode } from "~/server/db/types";
import { useService } from "../_hooks/service";
const formValidator = z.object({
replicas: z.number().int().positive(),
maxReplicasPerNode: z.number().int().positive().nullable(),
deployMode: z.enum(["replicated", "global"]).nullable(),
zeroDowntime: z.boolean().nullable(),
entrypoint: z.string().optional().nullable(),
command: z.string().optional().nullable(),
});
export default function DeploymentSettings() {
const { data: service } = useService();
const form = useForm(formValidator, {
defaultValues: {
replicas: service?.replicas,
maxReplicasPerNode: service?.maxReplicasPerNode,
deployMode: service?.deployMode,
zeroDowntime: service?.zeroDowntime,
entrypoint: service?.entrypoint,
command: service?.command,
},
});
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(async (data) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log(data);
})}
className="grid grid-cols-2 gap-4"
>
<h1 className="col-span-2">Deployment</h1>
<SimpleFormField
control={form.control}
name="entrypoint"
friendlyName="Entrypoint"
description="The entrypoint dictates what command is run inside the container on boot. By default, on most images, this is /bin/sh -c"
className="col-span-2"
/>
<SimpleFormField
control={form.control}
name="command"
friendlyName="Command"
description="This field dictates the arguments that are fed into the entrypoint."
className="col-span-2"
/>
<SimpleFormField
control={form.control}
name="replicas"
friendlyName="Replicas"
description="The number of containers to run for this service."
/>
<SimpleFormField
control={form.control}
name="maxReplicasPerNode"
friendlyName="Max Replicas Per Node"
description="The maximum number of containers to run for this service on a single node."
/>
<FormField
control={form.control}
name="deployMode"
render={({ field }) => (
<FormItem>
<FormLabel>Deploy Mode</FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value?.toString() ?? "replicated"}
>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem
value={DOCKER_DEPLOY_MODE_MAP[DockerDeployMode.Global]}
>
Global
</SelectItem>
<SelectItem
value={DOCKER_DEPLOY_MODE_MAP[DockerDeployMode.Replicated]}
>
Replicated
</SelectItem>
</SelectContent>
</Select>
<FormDescription>
Global mode will ensure that only one container runs per node.
Replicated mode will run the specified number of containers, but
it is up to the swarm manager to decide which nodes.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<SimpleFormField
control={form.control}
name="zeroDowntime"
friendlyName="Zero Downtime"
description="When enabled, old containers will stay running until the new containers are online, alowing for zero-downtime deployments."
/>
<FormSubmit form={form} className="col-span-2" />
</form>
</Form>
);
}

View file

@ -1,28 +1,9 @@
"use client";
import { Form } from "react-hook-form";
import { z } from "zod";
import { Input } from "~/components/ui/input";
import { FormField, useForm } from "~/hooks/forms";
import DeploymentSettings from "./DeploymentSettings";
export default function AdvancedSettings() {
const form = useForm(
z.object({
test: z.string(),
}),
);
return (
<Form {...form}>
<form onSubmit={form.handleSubmit((data) => console.log(data))}>
<FormField
control={form.control}
name="test"
friendlyName="Test"
required
render={({ field }) => <Input {...field} />}
/>
</form>
</Form>
<div>
<DeploymentSettings />
</div>
);
}

View file

@ -0,0 +1,164 @@
"use client"
import * as React from "react"
import {
CaretSortIcon,
CheckIcon,
ChevronDownIcon,
ChevronUpIcon,
} from "@radix-ui/react-icons"
import * as SelectPrimitive from "@radix-ui/react-select"
import { cn } from "~/utils/utils.ts"
const Select = SelectPrimitive.Root
const SelectGroup = SelectPrimitive.Group
const SelectValue = SelectPrimitive.Value
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<CaretSortIcon className="h-4 w-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
const SelectScrollUpButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollUpButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<ChevronUpIcon />
</SelectPrimitive.ScrollUpButton>
))
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
const SelectScrollDownButton = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
>(({ className, ...props }, ref) => (
<SelectPrimitive.ScrollDownButton
ref={ref}
className={cn(
"flex cursor-default items-center justify-center py-1",
className
)}
{...props}
>
<ChevronDownIcon />
</SelectPrimitive.ScrollDownButton>
))
SelectScrollDownButton.displayName =
SelectPrimitive.ScrollDownButton.displayName
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = "popper", ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"p-1",
position === "popper" &&
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn("px-2 py-1.5 text-sm font-semibold", className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<CheckIcon className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator,
SelectScrollUpButton,
SelectScrollDownButton,
}

View file

@ -8,8 +8,10 @@ import {
type FieldValues,
type Path,
type UseFormProps,
type UseFormReturn,
} from "react-hook-form";
import { type z } from "zod";
import { Button } from "~/components/ui/button";
import {
FormControl,
FormDescription,
@ -18,7 +20,9 @@ import {
FormMessage,
FormField as UIFormField,
} from "~/components/ui/form";
import { Input } from "~/components/ui/input";
import { Required } from "~/components/ui/required";
import { cn } from "~/utils/utils";
// type UseFormData<TFieldValues, TContext> = UseFormProps<TFieldValues
@ -60,7 +64,7 @@ export function useForm<TSchema extends z.Schema<any>, TContext = any>(
* @param props
* @returns
*/
export function FormField<
export function SimpleFormField<
TFieldValues extends FieldValues = FieldValues,
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
TContext extends Path<TFieldValues> = Path<unknown>,
@ -70,20 +74,23 @@ export function FormField<
friendlyName: string | ReactNode;
description?: string | ReactNode;
required?: boolean;
render: ControllerProps<TFieldValues, TContext>["render"];
render?: ControllerProps<TFieldValues, TContext>["render"];
className?: string;
}) {
const render = props.render ?? (({ field }) => <Input {...field} />);
return (
<UIFormField
control={props.control}
name={props.name}
render={({ field }) => (
<FormItem>
<FormItem className={props.className}>
<FormLabel>
{props.friendlyName}
{props.required && <Required />}
</FormLabel>
<FormControl>
{props.render({
{render({
//@ts-expect-error i cant type this any better
field,
formState: props.control._formState,
@ -102,3 +109,28 @@ export function FormField<
/>
);
}
export function FormSubmit({
form,
className,
}: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
form: UseFormReturn<z.infer<any>>;
className?: string;
}) {
return (
<div className={cn("flex flex-row items-center gap-2", className)}>
<Button type="submit" isLoading={form.formState.isSubmitting}>
Save
</Button>
{/* unsaved changes indicator */}
<p
className={`text-sm text-red-500 duration-200 animate-in fade-in ${
form.formState.isDirty ? "opacity-100" : "invisible opacity-0"
}`}
>
You have unsaved changes!
</p>
</div>
);
}

View file

@ -4,15 +4,49 @@ import { eq } from "drizzle-orm";
import { z } from "zod";
import { env } from "~/env";
import { projectMiddleware } from "~/server/api/middleware/project";
import { serviceMiddleware } from "~/server/api/middleware/service";
import { authenticatedProcedure, createTRPCRouter } from "~/server/api/trpc";
import { service } from "~/server/db/schema";
import { ServiceSource } from "~/server/db/types";
import { DOCKER_DEPLOY_MODE_MAP, ServiceSource } from "~/server/db/types";
import { zDockerName } from "~/server/utils/zod";
import { getServiceContainers } from "./containers";
export const serviceRouter = createTRPCRouter({
containers: getServiceContainers,
get: authenticatedProcedure
.meta({
openapi: {
method: "GET",
path: "/api/projects/:projectId/services/:serviceId",
summary: "Get service",
},
})
.input(z.object({ projectId: z.string(), serviceId: z.string() }))
.use(projectMiddleware)
.use(serviceMiddleware)
.query(async ({ ctx }) => {
const fullServiceData = await ctx.db.query.service.findFirst({
where: eq(service.id, ctx.service.id),
with: {
domains: true,
ports: true,
volumes: true,
project: true,
sysctls: true,
ulimits: true,
},
});
assert(fullServiceData);
return {
...fullServiceData,
zeroDowntime: fullServiceData.zeroDowntime === 1,
deployMode: DOCKER_DEPLOY_MODE_MAP[fullServiceData.deployMode],
};
}),
create: authenticatedProcedure
.meta({
openapi: {

View file

@ -9,7 +9,7 @@ import {
unique,
} from "drizzle-orm/sqlite-core";
import {
type DockerDeployMode,
DockerDeployMode,
type DockerRestartCondition,
type DockerVolumeType,
type ServiceBuildMethod,
@ -163,7 +163,10 @@ export const service = sqliteTable(
entrypoint: text("entrypoint"),
replicas: integer("replicas").default(1).notNull(),
maxReplicasPerNode: integer("max_replicas_per_node"),
deployMode: integer("deploy_mode").$type<DockerDeployMode>(),
deployMode: integer("deploy_mode")
.$type<DockerDeployMode>()
.default(DockerDeployMode.Replicated)
.notNull(),
zeroDowntime: integer("zero_downtime").default(0).notNull(),
// deployment usage limits

View file

@ -82,7 +82,7 @@ export enum DockerDeployMode {
export const DOCKER_DEPLOY_MODE_MAP = {
[DockerDeployMode.Global]: "global",
[DockerDeployMode.Replicated]: "replicated",
};
} as const;
export enum DockerRestartCondition {
/**