localtower 1.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +133 -33
- data/app/assets/javascripts/localtower/application.js +30830 -0
- data/app/assets/javascripts/localtower/application.js.map +7 -0
- data/app/assets/stylesheets/localtower/application.css +1179 -0
- data/app/assets/stylesheets/src/application.css +68 -0
- data/app/controllers/localtower/pages_controller.rb +20 -35
- data/app/javascript/application.js +46 -0
- data/app/javascript/components/DarkSelect.js +115 -0
- data/app/javascript/components/ModernTooltip.js +26 -0
- data/app/javascript/components/NewMigrationForm.js +687 -0
- data/app/javascript/components/NewModelForm.js +432 -0
- data/app/javascript/components/data/Stores.js +294 -0
- data/app/views/layouts/localtower/application.html.erb +80 -66
- data/app/views/localtower/_migration.html.erb +30 -0
- data/app/views/localtower/pages/_alert_no_models.html.erb +1 -1
- data/app/views/localtower/pages/migrations.html.erb +24 -55
- data/app/views/localtower/pages/new_migration.html.erb +33 -96
- data/app/views/localtower/pages/new_model.html.erb +17 -83
- data/config/routes.rb +1 -1
- data/lib/localtower/engine.rb +9 -2
- data/lib/localtower/generators/migration.rb +218 -91
- data/lib/localtower/generators/model.rb +29 -20
- data/lib/localtower/generators/service_objects/insert_array.rb +5 -3
- data/lib/localtower/generators/service_objects/insert_defaults.rb +73 -3
- data/lib/localtower/generators/service_objects/insert_foreign_keys.rb +35 -0
- data/lib/localtower/generators/service_objects/insert_indexes.rb +41 -18
- data/lib/localtower/generators/service_objects/insert_nullable.rb +5 -3
- data/lib/localtower/status.rb +3 -1
- data/lib/localtower/tools.rb +20 -9
- data/lib/localtower/version.rb +1 -1
- data/lib/localtower.rb +0 -6
- data/public/com/favicon-64.png +0 -0
- data/public/com/twitter-cover-1.png +0 -0
- data/public/com/twitter-cover-2.png +0 -0
- data/public/fonts/Circular/CircularStd-Black.otf +0 -0
- data/public/fonts/Circular/CircularStd-BlackItalic.otf +0 -0
- data/public/fonts/Circular/CircularStd-Bold.otf +0 -0
- data/public/fonts/Circular/CircularStd-BoldItalic.otf +0 -0
- data/public/fonts/Circular/CircularStd-Book.otf +0 -0
- data/public/fonts/Circular/CircularStd-BookItalic.otf +0 -0
- data/public/fonts/Circular/CircularStd-Light Italic.otf +0 -0
- data/public/fonts/Circular/CircularStd-Light.otf +0 -0
- data/public/fonts/Circular/CircularStd-Medium.otf +0 -0
- data/public/fonts/Circular/CircularStd-MediumItalic.otf +0 -0
- data/public/fonts/Circular/Read Me.txt +5 -0
- data/public/fonts/Circular/www.dfonts.org.url +2 -0
- data/public/screenshots/v0.1.1/1_schema.png +0 -0
- data/public/screenshots/v0.1.1/2_models_1.png +0 -0
- data/public/screenshots/v0.1.1/2_models_2.png +0 -0
- data/public/screenshots/v0.1.1/3_relations.png +0 -0
- data/public/screenshots/v0.1.1/4_migrations.png +0 -0
- data/public/screenshots/v0.1.6/1_schema.png +0 -0
- data/public/screenshots/v0.1.6/2_models_1.png +0 -0
- data/public/screenshots/v0.1.6/3_relations.png +0 -0
- data/public/screenshots/v0.1.6/4_migrations.png +0 -0
- data/public/screenshots/v0.1.6/5_capture.png +0 -0
- data/public/screenshots/v1.0.0/migrations.png +0 -0
- data/public/screenshots/v1.0.0/models.png +0 -0
- data/public/screenshots/v1.0.0/new_migration.png +0 -0
- data/public/screenshots/v1.0.0/new_model.png +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.44.30.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.44.42.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.44.54.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.48.21.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.48.28.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.48.51.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.49.09.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.50.04.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.50.11.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.50.19.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.51.47.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.51.48.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.52.02.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.52.18.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.52.26.jpg +0 -0
- data/public/screenshots/v2.0.0/Screenshot 2024-11-18 at 22.52.38.jpg +0 -0
- data/public/screenshots/v2.0.0/migrations.png +0 -0
- data/public/screenshots/v2.0.0/new_migration.png +0 -0
- data/public/screenshots/v2.0.0/new_model.png +0 -0
- data/public/vendor/jquery-3.7.1.min.js +2 -0
- data/public/vendor/lucide.min.js +12 -0
- data/public/vendor/monokai-sublime.css +80 -0
- data/public/vendor/rails-ujs.min.js +8 -0
- data/spec/dummy/Gemfile +1 -1
- data/spec/dummy/Gemfile.lock +146 -104
- data/spec/dummy/config/database.yml +4 -6
- data/spec/dummy/config/puma.rb +1 -1
- data/spec/dummy/db/schema.rb +2 -39
- data/spec/dummy/lib/tasks/reset.rake +16 -0
- data/spec/dummy/log/development.log +22746 -15994
- data/spec/dummy/log/localtower.log +747 -1891
- data/spec/dummy/log/test.log +1145 -0
- data/spec/dummy/tmp/cache/sessions/localtower/726/FE1/_session_id%3A2%3A%3A69d6764784f832ea25700ea2f242210f3f8d94b48912b0f09ffc44311f0376eb +0 -0
- data/spec/dummy/tmp/cache/sessions/localtower/77E/121/_session_id%3A2%3A%3A0b3c1fe7154461ba023ba6c81dd1b999348757880b505f4b082faed263a627f9 +1 -0
- data/spec/dummy/tmp/cache/sessions/localtower/7EB/8A1/_session_id%3A2%3A%3Af88237c1d157546a5dcde894fd6c1410162a8eba318748d4ac573ee75e40df16 +0 -0
- data/spec/dummy/tmp/local_secret.txt +1 -0
- data/spec/factories/migration.rb +77 -40
- data/spec/factories/model.rb +46 -26
- data/spec/lib/localtower/generators/migration_spec.rb +16 -24
- data/spec/lib/localtower/generators/model_spec.rb +71 -8
- data/spec/lib/localtower/generators/service_objects/insert_array_spec.rb +1 -1
- data/spec/lib/localtower/generators/service_objects/insert_defaults_spec.rb +1 -1
- data/spec/lib/localtower/generators/service_objects/insert_foreign_keys_spec.rb +101 -0
- data/spec/lib/localtower/generators/service_objects/insert_indexes_spec.rb +1 -1
- data/spec/lib/localtower/generators/service_objects/insert_nullable_spec.rb +2 -2
- data/spec/spec_helper.rb +2 -3
- metadata +107 -238
- data/app/views/localtower/pages/models.html.erb +0 -63
- data/public/css/app.css +0 -55
- data/public/js/app.js +0 -337
- data/public/light-bootstrap-dashboard-master/assets/css/animate.min.css +0 -6
- data/public/light-bootstrap-dashboard-master/assets/css/bootstrap.min.css +0 -5
- data/public/light-bootstrap-dashboard-master/assets/css/demo.css +0 -61
- data/public/light-bootstrap-dashboard-master/assets/css/light-bootstrap-dashboard.css +0 -2789
- data/public/light-bootstrap-dashboard-master/assets/css/pe-icon-7-stroke.css +0 -632
- data/public/light-bootstrap-dashboard-master/assets/fonts/Pe-icon-7-stroke.eot +0 -0
- data/public/light-bootstrap-dashboard-master/assets/fonts/Pe-icon-7-stroke.svg +0 -212
- data/public/light-bootstrap-dashboard-master/assets/fonts/Pe-icon-7-stroke.ttf +0 -0
- data/public/light-bootstrap-dashboard-master/assets/fonts/Pe-icon-7-stroke.woff +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/default-avatar.png +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/face-0.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/face-1.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/face-2.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/face-3.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/face-4.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/face-5.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/face-6.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/face-7.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/faces/tim_vector.jpe +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/favicon.ico +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/loading-bubbles.svg +0 -14
- data/public/light-bootstrap-dashboard-master/assets/img/mask.png +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/new_logo.png +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/sidebar-1.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/sidebar-2.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/sidebar-3.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/sidebar-4.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/sidebar-5.jpg +0 -0
- data/public/light-bootstrap-dashboard-master/assets/img/tim_80x80.png +0 -0
- data/public/light-bootstrap-dashboard-master/assets/js/bootstrap-checkbox-radio-switch.js +0 -502
- data/public/light-bootstrap-dashboard-master/assets/js/bootstrap-notify.js +0 -404
- data/public/light-bootstrap-dashboard-master/assets/js/bootstrap-select.js +0 -438
- data/public/light-bootstrap-dashboard-master/assets/js/bootstrap.min.js +0 -7
- data/public/light-bootstrap-dashboard-master/assets/js/chartist.min.js +0 -9
- data/public/light-bootstrap-dashboard-master/assets/js/demo.js +0 -152
- data/public/light-bootstrap-dashboard-master/assets/js/jquery-1.10.2.js +0 -9789
- data/public/light-bootstrap-dashboard-master/assets/js/light-bootstrap-dashboard.js +0 -179
- data/public/logo-localtower-white-300.png +0 -0
- data/public/logo-localtower-white.png +0 -0
- data/public/logo-localtower.png +0 -0
- data/public/vendor/font-awesome.min.css +0 -4
- data/public/vendor/highlight-js-default.min.css +0 -9
- data/spec/dummy/app/models/post.rb +0 -3
- data/spec/dummy/app/models/user.rb +0 -3
- data/spec/dummy/db/migrate/20230119221452_create_users.rb +0 -14
- data/spec/dummy/db/migrate/20230119221751_change_users_at1674166670.rb +0 -7
- data/spec/dummy/db/migrate/20230119222054_create_posts.rb +0 -11
- data/spec/dummy/db/migrate/20230119222106_change_posts_at1674166865.rb +0 -5
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/-Y/-YOiiBKqc2UODHFjctm8xc7xFoZaL7zOjWQj6qQ2wyE.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/-d/-dwueM4vmPt8L51S3jeSyg_AjGDcj0GUN6pDpCA1gCg.cache +0 -3
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/0g/0gaJnJQdtd2ACbihXxn8OnjLWlDjnQ_WxfgOpbiLzhg.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/0r/0rFCsCV9kZnEYtZZ6sfig8329OU31bqjecDFqSVank8.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/1J/1J2k_CpnQE3d-PZAQwOVGQALGkta4qVvhdsKjgG0e4Q.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/2p/2pYVH2Z_syqh6ok8QYxJNKxXpx1Iwppf6JGElZI0gpw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/3W/3WBmqd-2V6q5N-jvbyp-tlcfn3aHYMwBppbOUm7x4qg.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/4K/4KFPlHkhdDW0riGUmlbaR-kmDz6JUnQvY6fwW8qsdaE.cache +0 -3
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/6x/6xMeRWmLpNK_flx6-JA3KazvUxSCxyPxHv9Zm3eC26Q.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/7d/7dNqI_dCDJLJmI1oM4xwFp9nRRNOem-4P4OD7PMyz2E.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/8X/8XquhxVcp5A8QquLtxO8NgKTMJch0eqQmzFmRGIZP6I.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Ah/AhdfXXtU63kXS4TnsH2Vi1yWgVkIEeV8Z8XA68hrNQc.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Bt/BtAePnwLSGw82xUGI7wuhWDfuwarOQVS91YqCsweMcs.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Bx/BxzoG0KxeNLac4xTNeJv3qfeytbNBw58xj2zD-xdbrE.cache +0 -2
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/CC/CCD0ROPX0yxHwNpVZmuP8ZNtgQpaVCMXpdzC0Wb5n24.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/DS/DS43oxBg6K5PMWLn2mTy_4EnxI03ehHkxpjV7NCi8yM.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Do/Do83AoOat5W-c1g7piDGy2GMmffsY6JY0Qfuh5PY3GM.cache +0 -2
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/EI/EI0Nxk-VRATWstMuVCVc0_GdYlQ-a0dx6n2g0l3vIik.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/EN/ENhJnzJAU2IK-7aHqubj9N8Jo_UTmjG_VEQqyIkolQ8.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Fc/FcS6VUHN3Bd4pHGqd5NHA8jA4OLwWrU94s3b4GGxX9c.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/G0/G0kukI-r0q0Vbrg6e_jnYJoYcOX8K__h-mwKbCf4twE.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/I1/I1Jw08-mz8xzgrgi6giCzpf1UmzGTSbl4eJEw4DAoJM.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/IV/IVOO1dXBmgjieDk__g57p6aYt0Z3CmfTa32jhegoyko.cache +0 -3
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/JY/JYPmv5WP4wxdI9EKEEPkK_fVtqeSLfmint_5E8fQLQ8.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/MX/MXI3KxaQPZGImSvCNZ_TbQVruWCJ3E0xiVxza1ZCAjM.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/OU/OUoioCqXALK909jXPV3VSyCJIdNC7bsogUfdnRTpc5o.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/PH/PHjtqNLUPAUDiSlu5AbPjlIo20mOGNm0uNjMLhX2NvM.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/RC/RC9vfALY5K634pTeau0BAhTHl7d5_5yA3tM-QTLiKtI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/RG/RG1PrmlixwaUlG8BV0kcm_3F7OQekxsrLYjBdf403-k.cache +0 -2
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Ut/UtoMO6n6FHTpRCGk9VfxlfTI2Ao2GYJ_6kMzx3B9VH8.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/VE/VExnbpDk3LxYdPk3htUrZQXPI8NK_zlKtSFfVXJlxU4.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Wm/WmKTjykiU-Tx_Faf5zduEeEQ-DozAs5omKToM2l1cZM.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/X-/X-KjhDPd0nI155N_FaxFSgaOiYo0_ytqlmkBlLM7ayw.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/XX/XXVhj-O91tJ5c8pz7DQlTABOv8TIRVg5haw9VOq9HuI.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/YC/YCiifo5NCMwDChFqYFiV4EaYEx8hy3Efle1PsGbIdak.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Ya/YayMISAqD-Y3vBFywwKrXbUovGf5o77HUF5s8mnQgO0.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/Zl/Zl-NEb0aDLmZ9gN4gdY1OYlbUXD4JhkFY_y23m55zmo.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/_h/_hnjPptBeD3GP5B0iJR6pvyVkiMiq-o2TxaYmGf9KJo.cache +0 -3
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/_p/_poEF6QbTPYJiQCFGoXxIXjmvcn6T0I87ElzJGHguk0.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/aa/aaSj2zt8ddc87nZqTpOI9gRCKVnoalXKFBww7t4t3Kg.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/bZ/bZHWUkrOLp0WM_Ogo36Qjt4cxDt-rOFgtcj4LNB-BVE.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/cP/cPSNG_663TNT944Rke919luRS6FtpMwVc_7aDph645w.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/ce/ceq8fcZGIoqWrCl9vrCRrywEdx42iy9PrGG9CwFSIF4.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/cl/cljhP0Jc018nLnG1rpdg-FUf6mlIqrQYvXTNXTNG9Bw.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/dm/dmod3fTZdoKso2FGM5RTQtb4kTB6vywsiXLWDygYFN4.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/dy/dySDGcUTqlKx2MTvOmIEP-WzhyhCfU5xhN9qgxbz3rI.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/gQ/gQYdmEzbLjTcFCnsfzXzEmeminOchF263snAk3IvXM0.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/gh/ghvuMAqccBGljlmEaI3Gt5tH5rEg6hseKYMYfRMkHdY.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/gt/gt8QC7k92A4hXA3HlCpQulW73tqd6x63I3uT-YrGMj0.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/hf/hfVg-y7dPSQKbb7V3I7M5w7IpOhDiIB2H31d2tmbZMU.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/iF/iFLwyhZIu1Jxm77NUT2qWeTDMmyELW4U85t9rGE_KVg.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/kF/kFlIcBBnSyKE00OjpM90pqSn93mLMUv9esz86nrO-Cs.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/ma/MazNt_5OaYexRuZnccZZ_7AONlxn1a4W3KdWyHyBdws.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/ma/ma3w08gnDTeqwY2-C9BlToxA6-AS8bvXlu-nBiz0UYs.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/n_/n_xYqQYhwEMQknb3jFQnjlxxBE9TzMNHCdJ-bEyZFIw.cache +0 -2
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/nx/nxTv3sKVUQZADJyM3dPaVmUA78MIsMLD_K279yN_GsI.cache +0 -2
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/pv/pv6tV3CDkIAmLXdU8EPLlNEkXAKJPufVD4VP30o4fWo.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/qP/qPmv5snMrDw830S6hSICDcnIy7kVEWoFKXhGKT38lG4.cache +0 -2
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/sY/sYvTb1uPWWmnHJNXKuW_xSco-aUb-rN2f0J35zSIzuc.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/su/suQ_jjDxRiIn4VEqFJYKaBWJILaeGKBvoTv49XNX0vo.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/u8/u8IrW5IIQ7espwk2Vpk23zheL9YZA0tnbKq9X7E-WA0.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/wh/whzETExjcZCkn4msasD2aylgfhfpKPZrNxTkY-SOIDg.cache +0 -2
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/x7/x7PYh8DJvPykcEqpVab2vcY9-GFz-3cqtoMlRAu94Uc.cache +0 -2
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/y6/y6oxsJD3pAY9ph1_5M-77uiEjTVw8BheLZNygCKPm1g.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/yH/yHZ-a1J23ZCf2n5mEHINMz23Iec2cLGTKauW7k4yGTE.cache +0 -0
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/z7/z7KfUWYoSaGq8tQ5mbHwyfXyT3Pa4FWKJswHcIdJuds.cache +0 -1
- data/spec/dummy/tmp/cache/assets/sprockets/v4.0.0/zu/zuExWc5WHxeOUPZUKHl9a9ZRmN50g7jMOD28macn6M0.cache +0 -0
- data/spec/dummy/tmp/pids/server.pid +0 -1
@@ -0,0 +1,687 @@
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
2
|
+
import { X, Plus, TableOfContents } from "lucide-react";
|
3
|
+
// import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
|
4
|
+
|
5
|
+
import DarkSelect from "./DarkSelect.js";
|
6
|
+
import ModernTooltip from "./ModernTooltip.js";
|
7
|
+
import Stores from "./data/Stores.js";
|
8
|
+
|
9
|
+
const NewMigrationForm = () => {
|
10
|
+
const COLUMN_DEFAULTS = window.COLUMN_DEFAULTS;
|
11
|
+
|
12
|
+
const VISIBLE_FIELDS = {
|
13
|
+
add_column: [
|
14
|
+
"model_name",
|
15
|
+
"action_name",
|
16
|
+
"column_name",
|
17
|
+
"column_type",
|
18
|
+
"default",
|
19
|
+
"nullable",
|
20
|
+
"unique",
|
21
|
+
"index",
|
22
|
+
"index_algorithm",
|
23
|
+
"foreign_key",
|
24
|
+
],
|
25
|
+
remove_column: ["model_name", "action_name", "list_attributes"],
|
26
|
+
rename_column: [
|
27
|
+
"model_name",
|
28
|
+
"action_name",
|
29
|
+
"list_attributes",
|
30
|
+
"new_column_name",
|
31
|
+
],
|
32
|
+
change_column_type: [
|
33
|
+
"model_name",
|
34
|
+
"action_name",
|
35
|
+
"list_attributes",
|
36
|
+
"new_column_type",
|
37
|
+
],
|
38
|
+
belongs_to: ["model_name", "action_name", "list_models", "foreign_key"],
|
39
|
+
add_index_to_column: [
|
40
|
+
"model_name",
|
41
|
+
"action_name",
|
42
|
+
"list_attributes",
|
43
|
+
"unique",
|
44
|
+
"index",
|
45
|
+
"index_algorithm",
|
46
|
+
],
|
47
|
+
remove_index_to_column: ["model_name", "action_name", "list_indexes"],
|
48
|
+
drop_table: ["model_name", "action_name"],
|
49
|
+
};
|
50
|
+
|
51
|
+
const DEFAULT_LINE = {
|
52
|
+
table_name: Stores().APP_MODELS[0] ? Stores().APP_MODELS[0].table_name : "",
|
53
|
+
model_name: Stores().APP_MODELS[0] ? Stores().APP_MODELS[0].underscore : "",
|
54
|
+
action_name: Stores().actionsForSelect()[0]
|
55
|
+
? Stores().actionsForSelect()[0].value
|
56
|
+
: "",
|
57
|
+
column_type: "string",
|
58
|
+
column_name: "",
|
59
|
+
new_column_name: "",
|
60
|
+
new_column_type: "",
|
61
|
+
default: "",
|
62
|
+
unique: false,
|
63
|
+
foreign_key: false,
|
64
|
+
index: "",
|
65
|
+
index_algorithm: "default",
|
66
|
+
index_name: "",
|
67
|
+
nullable: true,
|
68
|
+
};
|
69
|
+
|
70
|
+
const [formRows, setFormRows] = useState([DEFAULT_LINE]);
|
71
|
+
const [showOptions, setShowOptions] = useState({});
|
72
|
+
|
73
|
+
const shouldBeVisible = (row, td_name) => {
|
74
|
+
return VISIBLE_FIELDS[row.action_name].includes(td_name) ? "block" : "none";
|
75
|
+
};
|
76
|
+
|
77
|
+
const handleAddRow = (event) => {
|
78
|
+
event.preventDefault();
|
79
|
+
|
80
|
+
setFormRows([...formRows, { ...DEFAULT_LINE }]);
|
81
|
+
};
|
82
|
+
|
83
|
+
const handleDeleteRow = (index, event) => {
|
84
|
+
event.preventDefault();
|
85
|
+
|
86
|
+
// Don't delete if there is only one row:
|
87
|
+
if (formRows.length === 1) {
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
|
91
|
+
setFormRows(formRows.filter((row, rowIndex) => rowIndex !== index));
|
92
|
+
};
|
93
|
+
|
94
|
+
const handleInputChange = (index, event) => {
|
95
|
+
const { name, value } = event.target;
|
96
|
+
const updatedRows = [...formRows];
|
97
|
+
|
98
|
+
let newValue = value;
|
99
|
+
|
100
|
+
// Sanitise default input:
|
101
|
+
if (name === "column_name") {
|
102
|
+
newValue = Stores().snakeCase(newValue);
|
103
|
+
newValue = newValue.trim();
|
104
|
+
}
|
105
|
+
|
106
|
+
updatedRows[index][name] = newValue;
|
107
|
+
|
108
|
+
if (name === "model_name") {
|
109
|
+
updatedRows[index].table_name =
|
110
|
+
Stores().modelByValue(newValue).table_name;
|
111
|
+
updatedRows[index].column_name = "";
|
112
|
+
updatedRows[index].index_name = "";
|
113
|
+
updatedRows[index].index = "";
|
114
|
+
updatedRows[index].index_algorithm = "";
|
115
|
+
updatedRows[index].default = "";
|
116
|
+
}
|
117
|
+
|
118
|
+
if (name === "action_name") {
|
119
|
+
updatedRows[index].column_name = "";
|
120
|
+
updatedRows[index].index_name = "";
|
121
|
+
}
|
122
|
+
|
123
|
+
if (name === "action_name" && newValue === "add_index_to_column") {
|
124
|
+
updatedRows[index].index = "default";
|
125
|
+
}
|
126
|
+
|
127
|
+
// Reset default if change.
|
128
|
+
if (name === "column_type") {
|
129
|
+
// result index:
|
130
|
+
// result default:
|
131
|
+
updatedRows[index].index = "";
|
132
|
+
updatedRows[index].default = "";
|
133
|
+
// close modal:
|
134
|
+
setShowOptions({ [index]: false });
|
135
|
+
}
|
136
|
+
|
137
|
+
if (name === "default" && newValue !== "") {
|
138
|
+
updatedRows[index].nullable = false;
|
139
|
+
}
|
140
|
+
|
141
|
+
// For the selector of the referenced model:
|
142
|
+
if (
|
143
|
+
name === "column_type" &&
|
144
|
+
value === "references" &&
|
145
|
+
Stores().APP_MODELS[0]
|
146
|
+
) {
|
147
|
+
updatedRows[index].column_name = Stores().APP_MODELS[0].underscore;
|
148
|
+
updatedRows[index].foreign_key = true;
|
149
|
+
}
|
150
|
+
|
151
|
+
if (
|
152
|
+
updatedRows[index].column_type !== "references" &&
|
153
|
+
updatedRows[index].foreign_key === true
|
154
|
+
) {
|
155
|
+
updatedRows[index].foreign_key = false;
|
156
|
+
}
|
157
|
+
|
158
|
+
// Reset unique if no index is selected:
|
159
|
+
if (
|
160
|
+
name === "index" &&
|
161
|
+
newValue === "" &&
|
162
|
+
updatedRows[index].unique === true
|
163
|
+
) {
|
164
|
+
updatedRows[index].unique = false;
|
165
|
+
}
|
166
|
+
|
167
|
+
setFormRows(updatedRows);
|
168
|
+
};
|
169
|
+
|
170
|
+
const handleCheckboxChange = (index, event) => {
|
171
|
+
const { name, checked, value } = event.target;
|
172
|
+
const updatedRows = [...formRows];
|
173
|
+
|
174
|
+
let finalValue = checked;
|
175
|
+
|
176
|
+
if (name === "nullable" && checked && updatedRows[index].default !== "") {
|
177
|
+
return false;
|
178
|
+
}
|
179
|
+
|
180
|
+
if (name === "unique" && checked && updatedRows[index].index === "") {
|
181
|
+
updatedRows[index].index = "default";
|
182
|
+
}
|
183
|
+
|
184
|
+
if (
|
185
|
+
name === "index_algorithm" &&
|
186
|
+
checked &&
|
187
|
+
updatedRows[index].index != ""
|
188
|
+
) {
|
189
|
+
finalValue = value === "concurrently" ? "concurrently" : "default";
|
190
|
+
}
|
191
|
+
|
192
|
+
updatedRows[index][name] = finalValue;
|
193
|
+
|
194
|
+
setFormRows(updatedRows);
|
195
|
+
};
|
196
|
+
|
197
|
+
const handleOptionClick = (index, option) => {
|
198
|
+
const updatedRows = [...formRows];
|
199
|
+
updatedRows[index].default = option.value;
|
200
|
+
|
201
|
+
if (updatedRows[index].default !== "") {
|
202
|
+
updatedRows[index].nullable = false;
|
203
|
+
} else {
|
204
|
+
updatedRows[index].nullable = true;
|
205
|
+
}
|
206
|
+
|
207
|
+
setFormRows(updatedRows);
|
208
|
+
setShowOptions({ [index]: false });
|
209
|
+
};
|
210
|
+
|
211
|
+
const handleShowOptions = (index, event) => {
|
212
|
+
event.preventDefault();
|
213
|
+
|
214
|
+
if (showOptions[index]) {
|
215
|
+
setShowOptions({ [index]: false });
|
216
|
+
} else {
|
217
|
+
setShowOptions({ [index]: true });
|
218
|
+
}
|
219
|
+
};
|
220
|
+
|
221
|
+
const addToForm = () => {
|
222
|
+
// Add the form to the hidden input:
|
223
|
+
document.getElementById("form_attributes").value = JSON.stringify(formRows);
|
224
|
+
};
|
225
|
+
|
226
|
+
useEffect(() => {
|
227
|
+
addToForm();
|
228
|
+
}, [formRows]); // This effect depends on formRows
|
229
|
+
|
230
|
+
if (Stores().APP_MODELS.length === 0) {
|
231
|
+
return <div className="flex flex-col gap-2"></div>;
|
232
|
+
}
|
233
|
+
|
234
|
+
return (
|
235
|
+
<div>
|
236
|
+
<table className="w-full max-w-screen-xl">
|
237
|
+
<tbody className="border-b border-localtower-500">
|
238
|
+
{formRows.map((row, index) => (
|
239
|
+
<tr key={`$row-${index}`} className="pb-2">
|
240
|
+
<td className="w-40 py-2 pr-3">
|
241
|
+
{/* ============== */}
|
242
|
+
{/* LIST MODELS / TABLES */}
|
243
|
+
<div className="w-40">
|
244
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
245
|
+
Model
|
246
|
+
</div>
|
247
|
+
<DarkSelect
|
248
|
+
keySuffix={"model_name" + row.table_name}
|
249
|
+
options={Stores().modelsForSelect()}
|
250
|
+
defaultValue={Stores().modelsForSelect()[0]}
|
251
|
+
value={row.model_name}
|
252
|
+
onChange={(selectedOption) => {
|
253
|
+
if (selectedOption && selectedOption.value) {
|
254
|
+
const syntheticEvent = {
|
255
|
+
target: {
|
256
|
+
name: "model_name",
|
257
|
+
value: selectedOption.value,
|
258
|
+
},
|
259
|
+
};
|
260
|
+
handleInputChange(index, syntheticEvent);
|
261
|
+
}
|
262
|
+
}}
|
263
|
+
/>
|
264
|
+
</div>
|
265
|
+
</td>
|
266
|
+
<td className="w-56 py-2 pr-3">
|
267
|
+
{/* ============== */}
|
268
|
+
{/* LIST ACTIONS */}
|
269
|
+
<div className="w-56">
|
270
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
271
|
+
Action
|
272
|
+
</div>
|
273
|
+
<DarkSelect
|
274
|
+
keySuffix={"action_name" + row.table_name}
|
275
|
+
options={Stores().actionsForSelect()}
|
276
|
+
defaultValue={Stores().actionsForSelect()[0]}
|
277
|
+
customClassNamesOverrides={{ menu: "!w-[450px]" }}
|
278
|
+
onChange={(selectedOption) => {
|
279
|
+
if (selectedOption && selectedOption.value) {
|
280
|
+
const syntheticEvent = {
|
281
|
+
target: {
|
282
|
+
name: "action_name",
|
283
|
+
value: selectedOption.value,
|
284
|
+
},
|
285
|
+
};
|
286
|
+
handleInputChange(index, syntheticEvent);
|
287
|
+
}
|
288
|
+
}}
|
289
|
+
/>
|
290
|
+
</div>
|
291
|
+
</td>
|
292
|
+
<td className="py-2 pr-3 flex flex-row gap-2">
|
293
|
+
{/* ============== */}
|
294
|
+
{/* LIST ATTRIBUTES */}
|
295
|
+
<div
|
296
|
+
className="w-48"
|
297
|
+
style={{ display: shouldBeVisible(row, "list_attributes") }}
|
298
|
+
>
|
299
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
300
|
+
Column
|
301
|
+
</div>
|
302
|
+
<DarkSelect
|
303
|
+
keySuffix={"column_name" + row.table_name}
|
304
|
+
options={Stores().attributesForSelect(
|
305
|
+
Stores().filterAttributes(row)
|
306
|
+
)}
|
307
|
+
defaultValue=""
|
308
|
+
onChange={(selectedOption) => {
|
309
|
+
const syntheticEvent = {
|
310
|
+
target: {
|
311
|
+
name: "column_name",
|
312
|
+
value: selectedOption.value,
|
313
|
+
},
|
314
|
+
};
|
315
|
+
handleInputChange(index, syntheticEvent);
|
316
|
+
}}
|
317
|
+
/>
|
318
|
+
</div>
|
319
|
+
{/* ============== */}
|
320
|
+
{/* LIST INDEXES */}
|
321
|
+
<div
|
322
|
+
className="w-80"
|
323
|
+
style={{ display: shouldBeVisible(row, "list_indexes") }}
|
324
|
+
>
|
325
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
326
|
+
Index to remove
|
327
|
+
</div>
|
328
|
+
<DarkSelect
|
329
|
+
keySuffix={"list_indexes" + row.table_name}
|
330
|
+
options={Stores()
|
331
|
+
.filterIndexes(row)
|
332
|
+
.map((attr) => ({
|
333
|
+
value: attr.value,
|
334
|
+
label: attr.label,
|
335
|
+
}))}
|
336
|
+
defaultValue=""
|
337
|
+
onChange={(selectedOption) => {
|
338
|
+
const syntheticEvent = {
|
339
|
+
target: {
|
340
|
+
name: "index_name",
|
341
|
+
value: selectedOption.value,
|
342
|
+
},
|
343
|
+
};
|
344
|
+
handleInputChange(index, syntheticEvent);
|
345
|
+
}}
|
346
|
+
/>
|
347
|
+
</div>
|
348
|
+
{/* ============== */}
|
349
|
+
{/* LIST MODELS (COLUMN NAME) */}
|
350
|
+
<div
|
351
|
+
className="w-40"
|
352
|
+
style={{ display: shouldBeVisible(row, "list_models") }}
|
353
|
+
>
|
354
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
355
|
+
Models
|
356
|
+
</div>
|
357
|
+
<DarkSelect
|
358
|
+
keySuffix={"list_models" + row.table_name}
|
359
|
+
options={Stores().modelsForSelectWithout([row.model_name])}
|
360
|
+
value={row.column_name}
|
361
|
+
onChange={(selectedOption) => {
|
362
|
+
const syntheticEvent = {
|
363
|
+
target: {
|
364
|
+
name: "column_name",
|
365
|
+
value: selectedOption.value,
|
366
|
+
},
|
367
|
+
};
|
368
|
+
handleInputChange(index, syntheticEvent);
|
369
|
+
}}
|
370
|
+
/>
|
371
|
+
</div>
|
372
|
+
{/* ============== */}
|
373
|
+
{/* COLUMN NAME */}
|
374
|
+
<div
|
375
|
+
className="w-48"
|
376
|
+
style={{ display: shouldBeVisible(row, "column_name") }}
|
377
|
+
>
|
378
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
379
|
+
Column name
|
380
|
+
</div>
|
381
|
+
<input
|
382
|
+
type="text"
|
383
|
+
className="px-2 py-1.5 rounded bg-localtower-600 border border-localtower-500 inline-block w-full outline-none focus:border-localtower-400 transition-colors text-localtower-100"
|
384
|
+
name="column_name"
|
385
|
+
value={row.column_name}
|
386
|
+
onChange={(event) => handleInputChange(index, event)}
|
387
|
+
/>
|
388
|
+
</div>
|
389
|
+
{/* ============== */}
|
390
|
+
{/* COLUMN TYPE */}
|
391
|
+
<div
|
392
|
+
className="w-48"
|
393
|
+
style={{ display: shouldBeVisible(row, "column_type") }}
|
394
|
+
>
|
395
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
396
|
+
Column type
|
397
|
+
</div>
|
398
|
+
<DarkSelect
|
399
|
+
keySuffix={"column_type" + row.table_name}
|
400
|
+
options={Stores().typesForSelect()}
|
401
|
+
defaultValue={Stores().typesForSelect()[0]}
|
402
|
+
onChange={(selectedOption) => {
|
403
|
+
const syntheticEvent = {
|
404
|
+
target: {
|
405
|
+
name: "column_type",
|
406
|
+
value: selectedOption.value,
|
407
|
+
},
|
408
|
+
};
|
409
|
+
handleInputChange(index, syntheticEvent);
|
410
|
+
}}
|
411
|
+
/>
|
412
|
+
</div>
|
413
|
+
{/* ============== */}
|
414
|
+
{/* NEW COLUMN TYPE */}
|
415
|
+
<div
|
416
|
+
className="w-40"
|
417
|
+
style={{ display: shouldBeVisible(row, "new_column_type") }}
|
418
|
+
>
|
419
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
420
|
+
New column type
|
421
|
+
</div>
|
422
|
+
<DarkSelect
|
423
|
+
keySuffix={"new_column_type" + row.table_name}
|
424
|
+
options={Stores().typesForSelect()}
|
425
|
+
defaultValue={Stores().typesForSelect()[0]}
|
426
|
+
onChange={(selectedOption) => {
|
427
|
+
const syntheticEvent = {
|
428
|
+
target: {
|
429
|
+
name: "new_column_type",
|
430
|
+
value: selectedOption.value,
|
431
|
+
},
|
432
|
+
};
|
433
|
+
handleInputChange(index, syntheticEvent);
|
434
|
+
}}
|
435
|
+
/>
|
436
|
+
</div>
|
437
|
+
{/* ============== */}
|
438
|
+
{/* DEFAULT VALUES */}
|
439
|
+
<div style={{ display: shouldBeVisible(row, "default") }}>
|
440
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
441
|
+
Default value
|
442
|
+
</div>
|
443
|
+
<div className="relative">
|
444
|
+
<input
|
445
|
+
type="text"
|
446
|
+
name="default"
|
447
|
+
className="px-2 py-1.5 pr-8 rounded bg-localtower-600 border border-localtower-500 block w-full outline-none focus:border-localtower-400 transition-colors text-localtower-100"
|
448
|
+
value={row.default}
|
449
|
+
placeholder="NULL"
|
450
|
+
onChange={(event) => handleInputChange(index, event)}
|
451
|
+
/>
|
452
|
+
{COLUMN_DEFAULTS[row.column_type] && (
|
453
|
+
<div className="absolute inset-y-0 right-0 pl-3 pr-1 flex space-x-1 items-center">
|
454
|
+
<button
|
455
|
+
className="bg-localtower-600 p-1 rounded-sm border border-localtower-500 outline-none hover:border-localtower-450 hover:bg-locatower-900 active:opacity-60 transition-colors cursor-pointer"
|
456
|
+
onClick={(event) => handleShowOptions(index, event)}
|
457
|
+
>
|
458
|
+
<TableOfContents
|
459
|
+
strokeWidth={1}
|
460
|
+
size={17}
|
461
|
+
className="text-localtower-200"
|
462
|
+
/>
|
463
|
+
</button>
|
464
|
+
</div>
|
465
|
+
)}
|
466
|
+
{COLUMN_DEFAULTS[row.column_type] && showOptions[index] && (
|
467
|
+
<div
|
468
|
+
className="options-popup bg-localtower-600 border border-localtower-500 text-localtower-100 rounded flex flex-col gap-2 overflow-hidden z-30 w-60"
|
469
|
+
style={{
|
470
|
+
display: showOptions[index] ? "block" : "none",
|
471
|
+
position: "absolute",
|
472
|
+
top: "100%",
|
473
|
+
left: "0",
|
474
|
+
right: "0",
|
475
|
+
}}
|
476
|
+
>
|
477
|
+
{COLUMN_DEFAULTS[row.column_type] &&
|
478
|
+
COLUMN_DEFAULTS[row.column_type].map((option) => (
|
479
|
+
<div
|
480
|
+
key={option.value}
|
481
|
+
onClick={() => handleOptionClick(index, option)}
|
482
|
+
className="hover:bg-localtower-900 p-2 active:opacity-60 cursor-pointer"
|
483
|
+
>
|
484
|
+
{option.label}
|
485
|
+
</div>
|
486
|
+
))}
|
487
|
+
</div>
|
488
|
+
)}
|
489
|
+
</div>
|
490
|
+
</div>
|
491
|
+
{/* ============== */}
|
492
|
+
{/* NEW COLUMN NAME */}
|
493
|
+
<div
|
494
|
+
className="w-48"
|
495
|
+
style={{ display: shouldBeVisible(row, "new_column_name") }}
|
496
|
+
>
|
497
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
498
|
+
New column name
|
499
|
+
</div>
|
500
|
+
<input
|
501
|
+
type="text"
|
502
|
+
className="px-2 py-1.5 rounded bg-localtower-600 border border-localtower-500 inline-block w-full outline-none focus:border-localtower-400 transition-colors text-localtower-100"
|
503
|
+
name="new_column_name"
|
504
|
+
value={row.new_column_name}
|
505
|
+
onChange={(event) => handleInputChange(index, event)}
|
506
|
+
/>
|
507
|
+
</div>
|
508
|
+
{/* ============== */}
|
509
|
+
{/* INDEX */}
|
510
|
+
<div
|
511
|
+
className="w-40"
|
512
|
+
style={{ display: shouldBeVisible(row, "index") }}
|
513
|
+
>
|
514
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
515
|
+
Index
|
516
|
+
</div>
|
517
|
+
<DarkSelect
|
518
|
+
options={Stores().indexesForSelect()}
|
519
|
+
value={row.index}
|
520
|
+
customClassNamesOverrides={{ menu: "!w-40" }}
|
521
|
+
onChange={(selectedOption) => {
|
522
|
+
const syntheticEvent = {
|
523
|
+
target: {
|
524
|
+
name: "index",
|
525
|
+
value: selectedOption.value,
|
526
|
+
},
|
527
|
+
};
|
528
|
+
handleInputChange(index, syntheticEvent);
|
529
|
+
}}
|
530
|
+
/>
|
531
|
+
</div>
|
532
|
+
{/* ============== */}
|
533
|
+
{/* CHECKBOXES */}
|
534
|
+
<div>
|
535
|
+
<div className="text-xs text-localtower-450 pb-0.5 font-medium">
|
536
|
+
|
537
|
+
</div>
|
538
|
+
<div>
|
539
|
+
<div className="w-64 flex flex-row gap-0.5 h-8 items-center">
|
540
|
+
{row.column_type !== "references" && (
|
541
|
+
<div
|
542
|
+
style={{ display: shouldBeVisible(row, "nullable") }}
|
543
|
+
>
|
544
|
+
<ModernTooltip
|
545
|
+
content="Use the 'Nullable' option to allow null values."
|
546
|
+
title="Nullable"
|
547
|
+
>
|
548
|
+
<label
|
549
|
+
className="inline-flex items-center align-middle gap-2 px-2 py-1 rounded hover:bg-localtower-900 cursor-pointer active:opacity-60 transition-all select-none group"
|
550
|
+
style={{
|
551
|
+
opacity: row.default === "" ? 1 : 0.5,
|
552
|
+
backgroundColor: row.nullable ? "black" : "",
|
553
|
+
}}
|
554
|
+
>
|
555
|
+
<input
|
556
|
+
type="checkbox"
|
557
|
+
name="nullable"
|
558
|
+
checked={row.nullable}
|
559
|
+
onChange={(event) =>
|
560
|
+
handleCheckboxChange(index, event)
|
561
|
+
}
|
562
|
+
/>
|
563
|
+
<span>NULL</span>
|
564
|
+
</label>
|
565
|
+
</ModernTooltip>
|
566
|
+
</div>
|
567
|
+
)}
|
568
|
+
<div
|
569
|
+
style={{ display: shouldBeVisible(row, "foreign_key") }}
|
570
|
+
>
|
571
|
+
<ModernTooltip
|
572
|
+
content="Use the 'Foreign Key' option to create a foreign key to another table."
|
573
|
+
title="Foreign Key"
|
574
|
+
>
|
575
|
+
<label
|
576
|
+
className="inline-flex items-center align-middle gap-2 px-2 py-1 rounded hover:bg-localtower-900 cursor-pointer active:opacity-60 transition-all select-none"
|
577
|
+
style={{
|
578
|
+
backgroundColor: row.foreign_key ? "black" : "",
|
579
|
+
}}
|
580
|
+
>
|
581
|
+
<input
|
582
|
+
type="checkbox"
|
583
|
+
name="foreign_key"
|
584
|
+
checked={row.foreign_key}
|
585
|
+
onChange={(event) =>
|
586
|
+
handleCheckboxChange(index, event)
|
587
|
+
}
|
588
|
+
/>
|
589
|
+
<span>FK</span>
|
590
|
+
</label>
|
591
|
+
</ModernTooltip>
|
592
|
+
</div>
|
593
|
+
{row.column_type !== "references" && (
|
594
|
+
<div
|
595
|
+
style={{ display: shouldBeVisible(row, "unique") }}
|
596
|
+
>
|
597
|
+
<ModernTooltip
|
598
|
+
content="Use the 'Unique' option to create a unique index."
|
599
|
+
title="Index Unique"
|
600
|
+
>
|
601
|
+
<label
|
602
|
+
className="inline-flex items-center align-middle gap-2 px-2 py-1 rounded hover:bg-localtower-900 cursor-pointer active:opacity-60 transition-all select-none"
|
603
|
+
style={{
|
604
|
+
backgroundColor: row.unique ? "black" : "",
|
605
|
+
}}
|
606
|
+
>
|
607
|
+
<input
|
608
|
+
type="checkbox"
|
609
|
+
name="unique"
|
610
|
+
checked={row.unique}
|
611
|
+
onChange={(event) =>
|
612
|
+
handleCheckboxChange(index, event)
|
613
|
+
}
|
614
|
+
/>
|
615
|
+
<span>IU</span>
|
616
|
+
</label>
|
617
|
+
</ModernTooltip>
|
618
|
+
</div>
|
619
|
+
)}
|
620
|
+
<div
|
621
|
+
style={{
|
622
|
+
display: shouldBeVisible(row, "index_algorithm"),
|
623
|
+
}}
|
624
|
+
>
|
625
|
+
<ModernTooltip
|
626
|
+
content="Use the 'Index Concurrently' option to create indexes without blocking writes to the table."
|
627
|
+
title="Index Concurrently"
|
628
|
+
>
|
629
|
+
<label
|
630
|
+
className="inline-flex items-center align-middle gap-2 px-2 py-1 rounded hover:bg-localtower-900 cursor-pointer active:opacity-60 transition-all select-none"
|
631
|
+
style={{
|
632
|
+
backgroundColor:
|
633
|
+
row.index_algorithm === "concurrently"
|
634
|
+
? "black"
|
635
|
+
: "",
|
636
|
+
opacity: row.index != "" ? 1 : 0,
|
637
|
+
}}
|
638
|
+
>
|
639
|
+
<input
|
640
|
+
type="checkbox"
|
641
|
+
name="index_algorithm"
|
642
|
+
value="concurrently"
|
643
|
+
checked={row.index_algorithm === "concurrently"}
|
644
|
+
onChange={(event) =>
|
645
|
+
handleCheckboxChange(index, event)
|
646
|
+
}
|
647
|
+
/>
|
648
|
+
<span>IC</span>
|
649
|
+
</label>
|
650
|
+
</ModernTooltip>
|
651
|
+
</div>
|
652
|
+
</div>
|
653
|
+
</div>
|
654
|
+
</div>
|
655
|
+
</td>
|
656
|
+
<td className="p-2">
|
657
|
+
<span
|
658
|
+
className="rounded bg-localtower-800 text-localtower-100 border border-localtower-500 outline-none hover:border-localtower-450 hover:bg-900 active:opacity-60 transition-colors inline-flex gap-1 cursor-pointer"
|
659
|
+
style={{
|
660
|
+
opacity: formRows.length === 1 ? 0.5 : 1,
|
661
|
+
cursor: formRows.length === 1 ? "not-allowed" : "pointer",
|
662
|
+
}}
|
663
|
+
>
|
664
|
+
<X
|
665
|
+
onClick={(event) => handleDeleteRow(index, event)}
|
666
|
+
className="text-xs px-1.5 py-1.5"
|
667
|
+
/>
|
668
|
+
</span>
|
669
|
+
</td>
|
670
|
+
</tr>
|
671
|
+
))}
|
672
|
+
</tbody>
|
673
|
+
</table>
|
674
|
+
<div className="flex justify-start py-4">
|
675
|
+
<button
|
676
|
+
className="text-xs px-1.5 py-1.5 pr-2.5 rounded bg-localtower-800 text-localtower-100 border border-localtower-500 outline-none hover:border-localtower-450 hover:bg-900 active:opacity-60 transition-colors inline-flex gap-1"
|
677
|
+
onClick={handleAddRow}
|
678
|
+
>
|
679
|
+
<Plus strokeWidth={1} size={16} />
|
680
|
+
Add action
|
681
|
+
</button>
|
682
|
+
</div>
|
683
|
+
</div>
|
684
|
+
);
|
685
|
+
};
|
686
|
+
|
687
|
+
export default NewMigrationForm;
|