diff --git a/airflow/ui/package.json b/airflow/ui/package.json index c54c9af5bb203..3e7cafa2a982c 100644 --- a/airflow/ui/package.json +++ b/airflow/ui/package.json @@ -18,15 +18,21 @@ "dependencies": { "@chakra-ui/anatomy": "^2.2.2", "@chakra-ui/react": "^2.8.2", + "@codemirror/lang-json": "^6.0.1", + "@codemirror/language": "^6.10.3", + "@codemirror/lint": "^6.8.2", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", + "@replit/codemirror-indentation-markers": "^6.5.3", "@tanstack/react-query": "^5.52.1", "@tanstack/react-table": "^8.20.1", + "@uiw/react-codemirror": "^4.23.5", "axios": "^1.7.7", "chakra-react-select": "^4.9.2", "framer-motion": "^11.3.29", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-hook-form": "^7.53.0", "react-icons": "^5.3.0", "react-router-dom": "^6.26.2", "use-debounce": "^10.0.3" diff --git a/airflow/ui/pnpm-lock.yaml b/airflow/ui/pnpm-lock.yaml index 3b73df0fa8049..b4b38493d1e6a 100644 --- a/airflow/ui/pnpm-lock.yaml +++ b/airflow/ui/pnpm-lock.yaml @@ -14,18 +14,33 @@ importers: '@chakra-ui/react': specifier: ^2.8.2 version: 2.8.2(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(framer-motion@11.3.29(@emotion/is-prop-valid@1.3.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@codemirror/lang-json': + specifier: ^6.0.1 + version: 6.0.1 + '@codemirror/language': + specifier: ^6.10.3 + version: 6.10.3 + '@codemirror/lint': + specifier: ^6.8.2 + version: 6.8.2 '@emotion/react': specifier: ^11.13.3 version: 11.13.3(@types/react@18.3.5)(react@18.3.1) '@emotion/styled': specifier: ^11.13.0 version: 11.13.0(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react@18.3.1) + '@replit/codemirror-indentation-markers': + specifier: ^6.5.3 + version: 6.5.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1) '@tanstack/react-query': specifier: ^5.52.1 version: 5.52.1(react@18.3.1) '@tanstack/react-table': specifier: ^8.20.1 version: 8.20.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@uiw/react-codemirror': + specifier: ^4.23.5 + version: 4.23.5(@babel/runtime@7.25.6)(@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.2))(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.34.1)(codemirror@6.0.1(@lezer/common@1.2.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) axios: specifier: ^1.7.7 version: 1.7.7 @@ -41,6 +56,9 @@ importers: react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) + react-hook-form: + specifier: ^7.53.0 + version: 7.53.0(react@18.3.1) react-icons: specifier: ^5.3.0 version: 5.3.0(react@18.3.1) @@ -724,6 +742,38 @@ packages: '@chakra-ui/system': '>=2.0.0' react: '>=18' + '@codemirror/autocomplete@6.18.1': + resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/common': ^1.0.0 + + '@codemirror/commands@6.7.0': + resolution: {integrity: sha512-+cduIZ2KbesDhbykV02K25A5xIVrquSPz4UxxYBemRlAT2aW8dhwUgLDwej7q/RJUHKk4nALYcR1puecDvbdqw==} + + '@codemirror/lang-json@6.0.1': + resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==} + + '@codemirror/language@6.10.3': + resolution: {integrity: sha512-kDqEU5sCP55Oabl6E7m5N+vZRoc0iWqgDVhEKifcHzPzjqCegcO4amfrYVL9PmPZpl4G0yjkpTpUO/Ui8CzO8A==} + + '@codemirror/lint@6.8.2': + resolution: {integrity: sha512-PDFG5DjHxSEjOXk9TQYYVjZDqlZTFaDBfhQixHnQOEVDDNHUbEh/hstAjcQJaA6FQdZTD1hquXTK0rVBLADR1g==} + + '@codemirror/search@6.5.6': + resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==} + + '@codemirror/state@6.4.1': + resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==} + + '@codemirror/theme-one-dark@6.1.2': + resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==} + + '@codemirror/view@6.34.1': + resolution: {integrity: sha512-t1zK/l9UiRqwUNPm+pdIT0qzJlzuVckbTEMVNFhfWkGiBQClstzg+78vedCvLSX0xJEZ6lwZbPpnljL7L6iwMQ==} + '@emotion/babel-plugin@11.12.0': resolution: {integrity: sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==} @@ -1003,6 +1053,18 @@ packages: '@jsdevtools/ono@7.1.3': resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@lezer/common@1.2.2': + resolution: {integrity: sha512-Z+R3hN6kXbgBWAuejUNPihylAL1Z5CaFqnIe0nTX8Ej+XlIy3EGtXxn6WtLMO+os2hRkQvm2yvaGMYliUzlJaw==} + + '@lezer/highlight@1.2.1': + resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==} + + '@lezer/json@1.0.2': + resolution: {integrity: sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==} + + '@lezer/lr@1.4.2': + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1030,6 +1092,13 @@ packages: resolution: {integrity: sha512-baiMx18+IMuD1yyvOGaHM9QrVUPGGG0jC+z+IPHnRJWUAUvaKuWKyE8gjDj2rzv3sz9zOGoRSPgeBVHRhZnBlA==} engines: {node: '>=14.0.0'} + '@replit/codemirror-indentation-markers@6.5.3': + resolution: {integrity: sha512-hL5Sfvw3C1vgg7GolLe/uxX5T3tmgOA3ZzqlMv47zjU1ON51pzNWiVbS22oh6crYhtVhv8b3gdXwoYp++2ilHw==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@rollup/rollup-android-arm-eabi@4.24.0': resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} cpu: [arm] @@ -1370,6 +1439,28 @@ packages: resolution: {integrity: sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@uiw/codemirror-extensions-basic-setup@4.23.5': + resolution: {integrity: sha512-eTMfT8TejVN/D5vvuz9Lab+MIoRYdtqa2ftZZmU3JpcDIXf9KaExPo+G2Rl9HqySzaasgGXOOG164MAnj3MSIw==} + peerDependencies: + '@codemirror/autocomplete': '>=6.0.0' + '@codemirror/commands': '>=6.0.0' + '@codemirror/language': '>=6.0.0' + '@codemirror/lint': '>=6.0.0' + '@codemirror/search': '>=6.0.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + + '@uiw/react-codemirror@4.23.5': + resolution: {integrity: sha512-2zzGpx61L4mq9zDG/hfsO4wAH209TBE8VVsoj/qrccRe6KfcneCwKgRxtQjxBCCnO0Q5S+IP+uwCx5bXRzgQFQ==} + peerDependencies: + '@babel/runtime': '>=7.11.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/theme-one-dark': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + codemirror: '>=6.0.0' + react: '>=16.8.0' + react-dom: '>=16.8.0' + '@vitejs/plugin-react-swc@3.7.0': resolution: {integrity: sha512-yrknSb3Dci6svCd/qhHqhFPDSw0QtjumcqdKMoNNzmOl5lMXTTiqzjWtG4Qask2HdvvzaNgSunbQGet8/GrKdA==} peerDependencies: @@ -1647,6 +1738,9 @@ packages: code-block-writer@13.0.2: resolution: {integrity: sha512-XfXzAGiStXSmCIwrkdfvc7FS5Dtj8yelCtyOf2p2skCAfvLd6zu0rGzuS9NSCO3bq1JKpFZ7tbKdKlcd5occQA==} + codemirror@6.0.1: + resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -1697,6 +1791,9 @@ packages: resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} engines: {node: '>=10'} + crelt@1.0.6: + resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2805,6 +2902,12 @@ packages: '@types/react': optional: true + react-hook-form@7.53.0: + resolution: {integrity: sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + react-icons@5.3.0: resolution: {integrity: sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==} peerDependencies: @@ -3072,6 +3175,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + style-mod@4.1.2: + resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} + stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} @@ -3313,6 +3419,9 @@ packages: jsdom: optional: true + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} @@ -4219,6 +4328,61 @@ snapshots: '@chakra-ui/system': 2.6.2(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.5)(react@18.3.1))(@types/react@18.3.5)(react@18.3.1))(react@18.3.1) react: 18.3.1 + '@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.2)': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.2 + + '@codemirror/commands@6.7.0': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.2 + + '@codemirror/lang-json@6.0.1': + dependencies: + '@codemirror/language': 6.10.3 + '@lezer/json': 1.0.2 + + '@codemirror/language@6.10.3': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/common': 1.2.2 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + style-mod: 4.1.2 + + '@codemirror/lint@6.8.2': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + crelt: 1.0.6 + + '@codemirror/search@6.5.6': + dependencies: + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + crelt: 1.0.6 + + '@codemirror/state@6.4.1': {} + + '@codemirror/theme-one-dark@6.1.2': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@lezer/highlight': 1.2.1 + + '@codemirror/view@6.34.1': + dependencies: + '@codemirror/state': 6.4.1 + style-mod: 4.1.2 + w3c-keyname: 2.2.8 + '@emotion/babel-plugin@11.12.0': dependencies: '@babel/helper-module-imports': 7.24.7 @@ -4466,6 +4630,22 @@ snapshots: '@jsdevtools/ono@7.1.3': {} + '@lezer/common@1.2.2': {} + + '@lezer/highlight@1.2.1': + dependencies: + '@lezer/common': 1.2.2 + + '@lezer/json@1.0.2': + dependencies: + '@lezer/common': 1.2.2 + '@lezer/highlight': 1.2.1 + '@lezer/lr': 1.4.2 + + '@lezer/lr@1.4.2': + dependencies: + '@lezer/common': 1.2.2 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -4487,6 +4667,12 @@ snapshots: '@remix-run/router@1.19.2': {} + '@replit/codemirror-indentation-markers@6.5.3(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)': + dependencies: + '@codemirror/language': 6.10.3 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + '@rollup/rollup-android-arm-eabi@4.24.0': optional: true @@ -4827,6 +5013,33 @@ snapshots: '@typescript-eslint/types': 8.5.0 eslint-visitor-keys: 3.4.3 + '@uiw/codemirror-extensions-basic-setup@4.23.5(@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.2))(@codemirror/commands@6.7.0)(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)': + dependencies: + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.2) + '@codemirror/commands': 6.7.0 + '@codemirror/language': 6.10.3 + '@codemirror/lint': 6.8.2 + '@codemirror/search': 6.5.6 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + + '@uiw/react-codemirror@4.23.5(@babel/runtime@7.25.6)(@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.2))(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.34.1)(codemirror@6.0.1(@lezer/common@1.2.2))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.6 + '@codemirror/commands': 6.7.0 + '@codemirror/state': 6.4.1 + '@codemirror/theme-one-dark': 6.1.2 + '@codemirror/view': 6.34.1 + '@uiw/codemirror-extensions-basic-setup': 4.23.5(@codemirror/autocomplete@6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.2))(@codemirror/commands@6.7.0)(@codemirror/language@6.10.3)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1) + codemirror: 6.0.1(@lezer/common@1.2.2) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + transitivePeerDependencies: + - '@codemirror/autocomplete' + - '@codemirror/language' + - '@codemirror/lint' + - '@codemirror/search' + '@vitejs/plugin-react-swc@3.7.0(vite@5.4.6(@types/node@22.5.4))': dependencies: '@swc/core': 1.7.14 @@ -5162,6 +5375,18 @@ snapshots: code-block-writer@13.0.2: {} + codemirror@6.0.1(@lezer/common@1.2.2): + dependencies: + '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.10.3)(@codemirror/state@6.4.1)(@codemirror/view@6.34.1)(@lezer/common@1.2.2) + '@codemirror/commands': 6.7.0 + '@codemirror/language': 6.10.3 + '@codemirror/lint': 6.8.2 + '@codemirror/search': 6.5.6 + '@codemirror/state': 6.4.1 + '@codemirror/view': 6.34.1 + transitivePeerDependencies: + - '@lezer/common' + color-convert@1.9.3: dependencies: color-name: 1.1.3 @@ -5208,6 +5433,8 @@ snapshots: path-type: 4.0.0 yaml: 1.10.2 + crelt@1.0.6: {} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 @@ -6425,6 +6652,10 @@ snapshots: optionalDependencies: '@types/react': 18.3.5 + react-hook-form@7.53.0(react@18.3.1): + dependencies: + react: 18.3.1 + react-icons@5.3.0(react@18.3.1): dependencies: react: 18.3.1 @@ -6750,6 +6981,8 @@ snapshots: strip-json-comments@3.1.1: {} + style-mod@4.1.2: {} + stylis@4.2.0: {} supports-color@5.5.0: @@ -6985,6 +7218,8 @@ snapshots: - supports-color - terser + w3c-keyname@2.2.8: {} + webidl-conversions@7.0.0: {} whatwg-mimetype@3.0.0: {} diff --git a/airflow/ui/src/components/ActionModal.tsx b/airflow/ui/src/components/ActionModal.tsx new file mode 100644 index 0000000000000..2381e11c06e98 --- /dev/null +++ b/airflow/ui/src/components/ActionModal.tsx @@ -0,0 +1,67 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + Button, + Modal, + ModalBody, + ModalCloseButton, + ModalContent, + ModalFooter, + ModalHeader, + ModalOverlay, + type ModalProps, + Box, +} from "@chakra-ui/react"; +import type { ReactNode } from "react"; + +type Props = { + readonly header: ReactNode | string; + readonly subheader?: ReactNode | string; + readonly submitButton: ReactNode; +} & ModalProps; + +const ActionModal = ({ + children, + header, + isOpen, + onClose, + subheader, + submitButton, + ...otherProps +}: Props) => ( + + + + {header} + + + {subheader} + {children} + + + + Cancel + + {submitButton} + + + +); + +export default ActionModal; diff --git a/airflow/ui/src/components/TriggerDag.tsx b/airflow/ui/src/components/TriggerDag.tsx new file mode 100644 index 0000000000000..0bc4ba3d7ea6a --- /dev/null +++ b/airflow/ui/src/components/TriggerDag.tsx @@ -0,0 +1,203 @@ +/*! + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { + Box, + Button, + useDisclosure, + Text, + Accordion, + AccordionItem, + AccordionButton, + AccordionIcon, + AccordionPanel, + FormControl, + FormLabel, + Input, + FormErrorMessage, + Tr, + Td, + Table, +} from "@chakra-ui/react"; +import { json, jsonParseLinter } from "@codemirror/lang-json"; +import { linter, lintGutter } from "@codemirror/lint"; +import { indentationMarkers } from "@replit/codemirror-indentation-markers"; +import CodeMirror, { lineNumbers, type ViewUpdate } from "@uiw/react-codemirror"; +import { useForm, SubmitHandler, Controller } from "react-hook-form"; +import { FiPlay } from "react-icons/fi"; + +import ActionModal from "./ActionModal"; + +type Props = { + readonly dagDisplayName: string; + readonly dagId: string; +}; + +type TriggerDagModalProps = { + readonly isOpen: boolean; + readonly onClose: () => void; +} & Props; + +const TriggerDagModal = ({ + dagDisplayName, + dagId, + isOpen, + onClose, +}: TriggerDagModalProps) => { + const onTrigger = (values: any) => + new Promise((resolve) => { + setTimeout(() => { + alert(JSON.stringify(values, null, 2)); + resolve(); + // Trigger here TODO + onClose(); + }, 3000); + }); + + const { + control, + formState: { errors, isSubmitting }, + handleSubmit, + register, + } = useForm(); + + return ( + + Trigger + + } + > + + + + + + + DAG Run Options + + + + + + + + + + + + Logical date: + + + + + + {errors.name?.message} + + + + + + Run id: + + + + + {errors.name?.message} + + + + + + + Configuration JSON: + + ( + { + field.onChange(value); + }} + /> + )} + /> + + {errors.name?.message} + + + + + + + + + + + {/* TODO Trigger form from component */} + {/* TODO Toggle to unpause DAG if paused */} + + ); +}; + +export const TriggerDag = ({ dagDisplayName, dagId }: Props) => { + const { isOpen, onClose, onOpen } = useDisclosure(); + + return ( + <> + + + + + > + ); +}; diff --git a/airflow/ui/src/pages/DagsList/DagCard.tsx b/airflow/ui/src/pages/DagsList/DagCard.tsx index d555abbc0ce1b..ae2d881f8f35f 100644 --- a/airflow/ui/src/pages/DagsList/DagCard.tsx +++ b/airflow/ui/src/pages/DagsList/DagCard.tsx @@ -32,6 +32,7 @@ import { FiCalendar, FiTag } from "react-icons/fi"; import type { DAGResponse } from "openapi/requests/types.gen"; import { TogglePause } from "src/components/TogglePause"; +import { TriggerDag } from "src/components/TriggerDag"; type Props = { readonly dag: DAGResponse; @@ -89,6 +90,10 @@ export const DagCard = ({ dag }: Props) => { + diff --git a/airflow/ui/src/pages/DagsList/DagsList.tsx b/airflow/ui/src/pages/DagsList/DagsList.tsx index 5e1324873296f..633ccc8169d38 100644 --- a/airflow/ui/src/pages/DagsList/DagsList.tsx +++ b/airflow/ui/src/pages/DagsList/DagsList.tsx @@ -42,6 +42,7 @@ import { useTableURLState } from "src/components/DataTable/useTableUrlState"; import { ErrorAlert } from "src/components/ErrorAlert"; import { SearchBar } from "src/components/SearchBar"; import { TogglePause } from "src/components/TogglePause"; +import { TriggerDag } from "src/components/TriggerDag"; import { SearchParamsKeys, type SearchParamsKeysType, @@ -97,6 +98,17 @@ const columns: Array> = [ enableSorting: false, header: () => "Tags", }, + { + accessorKey: "trigger", + cell: ({ row }) => ( + + ), + enableSorting: false, + header: "", + }, ]; const {