Franknoirot/file tree fixes (#2525)
* Navigate between files with single-click * Better semantic name for optional event passed into FileTree * Bug fix: reset modeling state when navigating to a new file * Add more context to E2E test TODO comment * Newly-created file tree items are immediately set to renaming mode * Bug fix: redirect to working file if you delete your current one * Remove ContextMenu, unrelated branch * Turn off autocorrect in renaming form * Gracefully handle renaming a folder that our current file is inside of * Update cargo.lock * Fix renaming queue * Navigate to newly-created files * Make delete project and delete file/folder share deletion confirmation component * Bug fix: navigate to project root if we delete our current file's parent directory * Don't navigate to newly-created directories
This commit is contained in:
@ -3576,6 +3576,10 @@ test('Basic default modeling and sketch hotkeys work', async ({ page }) => {
|
||||
* TODO: There is a bug somewhere that causes this test to fail
|
||||
* if you toggle the codePane closed before your trigger the
|
||||
* start of the sketch.
|
||||
* and a separate Safari-only bug that causes the test to fail
|
||||
* if the pane is open the entire test. The maintainer of CodeMirror
|
||||
* has pinpointed this to the unusual browser behavior:
|
||||
* https://discuss.codemirror.net/t/how-to-force-unfocus-of-the-codemirror-element-in-safari/8095/3
|
||||
*/
|
||||
await codePaneButton.click()
|
||||
|
||||
|
196
src-tauri/Cargo.lock
generated
196
src-tauri/Cargo.lock
generated
@ -344,7 +344,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -379,7 +379,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -425,7 +425,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -574,7 +574,7 @@ dependencies = [
|
||||
"proc-macro-crate 3.1.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
"syn_derive",
|
||||
]
|
||||
|
||||
@ -883,7 +883,7 @@ dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1085,7 +1085,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1095,7 +1095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1119,7 +1119,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1130,7 +1130,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1177,7 +1177,7 @@ checksum = "377af281d8f23663862a7c84623bc5dcf7f8c44b13c7496a590bdc157f941a43"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@ -1214,7 +1214,7 @@ dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_tokenstream",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1225,7 +1225,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1287,7 +1287,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1319,7 +1319,7 @@ checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1417,7 +1417,7 @@ checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1568,7 +1568,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1684,7 +1684,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1960,7 +1960,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1988,7 +1988,7 @@ dependencies = [
|
||||
"inflections",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2063,7 +2063,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2461,15 +2461,6 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
@ -2568,7 +2559,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.57"
|
||||
version = "0.1.58"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
@ -2591,7 +2582,7 @@ dependencies = [
|
||||
"kittycad-execution-plan-traits",
|
||||
"lazy_static",
|
||||
"mime_guess",
|
||||
"parse-display 0.9.0",
|
||||
"parse-display",
|
||||
"reqwest 0.11.27",
|
||||
"ropey",
|
||||
"schemars",
|
||||
@ -2627,13 +2618,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kittycad"
|
||||
version = "0.3.1"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6e12eb45fd9a28c8e99dbdef54556246b39acee14e4aa6f0fc43636caa62d9"
|
||||
checksum = "b0cbef813153197e60c0e96f59eea0b75f8418380f414b20250ee81b60e522c3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"base64 0.21.7",
|
||||
"base64 0.22.1",
|
||||
"bigdecimal",
|
||||
"bytes",
|
||||
"chrono",
|
||||
@ -2642,10 +2633,10 @@ dependencies = [
|
||||
"format_serde_error",
|
||||
"futures",
|
||||
"http 0.2.12",
|
||||
"itertools 0.10.5",
|
||||
"itertools",
|
||||
"log",
|
||||
"mime_guess",
|
||||
"parse-display 0.8.2",
|
||||
"parse-display",
|
||||
"phonenumber",
|
||||
"rand 0.8.5",
|
||||
"reqwest 0.11.27",
|
||||
@ -2672,7 +2663,7 @@ checksum = "0611fc9b9786175da21d895ffa0f65039e19c9111e94a41b7af999e3b95f045f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3360,43 +3351,17 @@ dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-display"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6509d08722b53e8dafe97f2027b22ccbe3a5db83cb352931e9716b0aa44bc5c"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"parse-display-derive 0.8.2",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-display"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06af5f9333eb47bd9ba8462d612e37a8328a5cb80b13f0af4de4c3b89f52dee5"
|
||||
dependencies = [
|
||||
"parse-display-derive 0.9.0",
|
||||
"parse-display-derive",
|
||||
"regex",
|
||||
"regex-syntax 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-display-derive"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68517892c8daf78da08c0db777fcc17e07f2f63ef70041718f8a7630ad84f341"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"regex-syntax 0.7.5",
|
||||
"structmeta 0.2.0",
|
||||
"syn 2.0.65",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parse-display-derive"
|
||||
version = "0.9.0"
|
||||
@ -3407,8 +3372,8 @@ dependencies = [
|
||||
"quote",
|
||||
"regex",
|
||||
"regex-syntax 0.8.3",
|
||||
"structmeta 0.3.0",
|
||||
"syn 2.0.65",
|
||||
"structmeta",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3550,7 +3515,7 @@ dependencies = [
|
||||
"phf_shared 0.11.2",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3582,14 +3547,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "phonenumber"
|
||||
version = "0.3.4+8.13.34"
|
||||
version = "0.3.5+8.13.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d888d375f2963bf06c5079665fbe53db69860879ff5a78524fe3c93c54fb7b8"
|
||||
checksum = "f174c8db59b620032bd52b655fc97000458850fec0db35fcd4e802b668517ec0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"either",
|
||||
"fnv",
|
||||
"itertools 0.12.1",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"quick-xml",
|
||||
@ -3618,7 +3583,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3770,9 +3735,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.81"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
|
||||
checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -4002,12 +3967,6 @@ version = "0.6.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.3"
|
||||
@ -4456,7 +4415,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4565,7 +4524,7 @@ checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4576,7 +4535,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4609,7 +4568,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4630,7 +4589,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4672,7 +4631,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4931,18 +4890,6 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "structmeta"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ad9e09554f0456d67a69c1584c9798ba733a5b50349a6c0d0948710523922d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.2.0",
|
||||
"syn 2.0.65",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structmeta"
|
||||
version = "0.3.0"
|
||||
@ -4951,19 +4898,8 @@ checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"structmeta-derive 0.3.0",
|
||||
"syn 2.0.65",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structmeta-derive"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a60bcaff7397072dca0017d1db428e30d5002e00b6847703e2e42005c95fbe00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"structmeta-derive",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4974,7 +4910,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4996,7 +4932,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5029,9 +4965,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.65"
|
||||
version = "2.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -5047,7 +4983,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5064,7 +5000,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5281,7 +5217,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
"tauri-utils",
|
||||
"thiserror",
|
||||
"time",
|
||||
@ -5299,7 +5235,7 @@ dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
"tauri-codegen",
|
||||
"tauri-utils",
|
||||
]
|
||||
@ -5665,7 +5601,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5754,7 +5690,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5943,7 +5879,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5972,7 +5908,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6093,7 +6029,7 @@ source = "git+https://github.com/Aleph-Alpha/ts-rs#f898578d80d3e2a54080c1c046c45
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
@ -6306,7 +6242,7 @@ dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6405,7 +6341,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -6439,7 +6375,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@ -6580,7 +6516,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6686,7 +6622,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6697,7 +6633,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7139,7 +7075,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.65",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
InterpreterFrom,
|
||||
Prop,
|
||||
StateFrom,
|
||||
assign,
|
||||
} from 'xstate'
|
||||
import { useCommandsContext } from 'hooks/useCommandsContext'
|
||||
import { fileMachine } from 'machines/fileMachine'
|
||||
@ -37,7 +38,7 @@ export const FileMachineProvider = ({
|
||||
}) => {
|
||||
const navigate = useNavigate()
|
||||
const { commandBarSend } = useCommandsContext()
|
||||
const { project } = useRouteLoaderData(paths.FILE) as IndexLoaderData
|
||||
const { project, file } = useRouteLoaderData(paths.FILE) as IndexLoaderData
|
||||
|
||||
const [state, send] = useMachine(fileMachine, {
|
||||
context: {
|
||||
@ -53,8 +54,32 @@ export const FileMachineProvider = ({
|
||||
context.selectedDirectory + sep() + event.data.name
|
||||
)}`
|
||||
)
|
||||
} else if (
|
||||
event.data &&
|
||||
'path' in event.data &&
|
||||
event.data.path.endsWith(FILE_EXT)
|
||||
) {
|
||||
// Don't navigate to newly created directories
|
||||
navigate(`${paths.FILE}/${encodeURIComponent(event.data.path)}`)
|
||||
}
|
||||
},
|
||||
addFileToRenamingQueue: assign({
|
||||
itemsBeingRenamed: (context, event) => [
|
||||
...context.itemsBeingRenamed,
|
||||
event.data.path,
|
||||
],
|
||||
}),
|
||||
removeFileFromRenamingQueue: assign({
|
||||
itemsBeingRenamed: (
|
||||
context,
|
||||
event: EventFrom<typeof fileMachine, 'done.invoke.rename-file'>
|
||||
) =>
|
||||
context.itemsBeingRenamed.filter(
|
||||
(path) => path !== event.data.oldPath
|
||||
),
|
||||
}),
|
||||
renameToastSuccess: (_, event) => toast.success(event.data.message),
|
||||
createToastSuccess: (_, event) => toast.success(event.data.message),
|
||||
toastSuccess: (_, event) =>
|
||||
event.data && toast.success((event.data || '') + ''),
|
||||
toastError: (_, event) => toast.error((event.data || '') + ''),
|
||||
@ -70,37 +95,56 @@ export const FileMachineProvider = ({
|
||||
}
|
||||
},
|
||||
createFile: async (context, event) => {
|
||||
let name = event.data.name.trim() || DEFAULT_FILE_NAME
|
||||
let createdName = event.data.name.trim() || DEFAULT_FILE_NAME
|
||||
let createdPath: string
|
||||
|
||||
if (event.data.makeDir) {
|
||||
await mkdir(await join(context.selectedDirectory.path, name))
|
||||
createdPath = await join(context.selectedDirectory.path, createdName)
|
||||
await mkdir(createdPath)
|
||||
} else {
|
||||
await create(
|
||||
createdPath =
|
||||
context.selectedDirectory.path +
|
||||
sep() +
|
||||
name +
|
||||
(name.endsWith(FILE_EXT) ? '' : FILE_EXT)
|
||||
)
|
||||
createdName +
|
||||
(createdName.endsWith(FILE_EXT) ? '' : FILE_EXT)
|
||||
await create(createdPath)
|
||||
}
|
||||
|
||||
return `Successfully created "${name}"`
|
||||
return {
|
||||
message: `Successfully created "${createdName}"`,
|
||||
path: createdPath,
|
||||
}
|
||||
},
|
||||
renameFile: async (
|
||||
context: ContextFrom<typeof fileMachine>,
|
||||
event: EventFrom<typeof fileMachine, 'Rename file'>
|
||||
) => {
|
||||
const { oldName, newName, isDir } = event.data
|
||||
let name = newName ? newName : DEFAULT_FILE_NAME
|
||||
const name = newName ? newName : DEFAULT_FILE_NAME
|
||||
const oldPath = await join(context.selectedDirectory.path, oldName)
|
||||
const newDirPath = await join(context.selectedDirectory.path, name)
|
||||
const newPath =
|
||||
newDirPath + (name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT)
|
||||
|
||||
await rename(
|
||||
await join(context.selectedDirectory.path, oldName),
|
||||
(await join(context.selectedDirectory.path, name)) +
|
||||
(name.endsWith(FILE_EXT) || isDir ? '' : FILE_EXT),
|
||||
{}
|
||||
)
|
||||
return (
|
||||
oldName !== name && `Successfully renamed "${oldName}" to "${name}"`
|
||||
await rename(oldPath, newPath, {})
|
||||
|
||||
if (oldPath === file?.path && project?.path) {
|
||||
// If we just renamed the current file, navigate to the new path
|
||||
navigate(paths.FILE + '/' + encodeURIComponent(newPath))
|
||||
} else if (file?.path.includes(oldPath)) {
|
||||
// If we just renamed a directory that the current file is in, navigate to the new path
|
||||
navigate(
|
||||
paths.FILE +
|
||||
'/' +
|
||||
encodeURIComponent(file.path.replace(oldPath, newDirPath))
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
message: `Successfully renamed "${oldName}" to "${name}"`,
|
||||
newPath,
|
||||
oldPath,
|
||||
}
|
||||
},
|
||||
deleteFile: async (
|
||||
context: ContextFrom<typeof fileMachine>,
|
||||
@ -117,6 +161,17 @@ export const FileMachineProvider = ({
|
||||
console.error('Error deleting file', e)
|
||||
)
|
||||
}
|
||||
|
||||
// If we just deleted the current file or one of its parent directories,
|
||||
// navigate to the project root
|
||||
if (
|
||||
(event.data.path === file?.path ||
|
||||
file?.path.includes(event.data.path)) &&
|
||||
project?.path
|
||||
) {
|
||||
navigate(paths.FILE + '/' + encodeURIComponent(project.path))
|
||||
}
|
||||
|
||||
return `Successfully deleted ${isDir ? 'folder' : 'file'} "${
|
||||
event.data.name
|
||||
}"`
|
||||
|
@ -2,11 +2,11 @@ import type { FileEntry, IndexLoaderData } from 'lib/types'
|
||||
import { paths } from 'lib/paths'
|
||||
import { ActionButton } from './ActionButton'
|
||||
import Tooltip from './Tooltip'
|
||||
import { Dispatch, useEffect, useRef, useState } from 'react'
|
||||
import { Dispatch, useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useNavigate, useRouteLoaderData } from 'react-router-dom'
|
||||
import { Dialog, Disclosure } from '@headlessui/react'
|
||||
import { Disclosure } from '@headlessui/react'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faChevronRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faChevronRight } from '@fortawesome/free-solid-svg-icons'
|
||||
import { useFileContext } from 'hooks/useFileContext'
|
||||
import styles from './FileTree.module.css'
|
||||
import { sortProject } from 'lib/tauriFS'
|
||||
@ -16,6 +16,8 @@ import { codeManager, kclManager } from 'lib/singletons'
|
||||
import { useDocumentHasFocus } from 'hooks/useDocumentHasFocus'
|
||||
import { useLspContext } from './LspProvider'
|
||||
import useHotkeyWrapper from 'lib/hotkeyWrapper'
|
||||
import { useModelingContext } from 'hooks/useModelingContext'
|
||||
import { DeleteConfirmationDialog } from './ProjectCard/DeleteProjectDialog'
|
||||
|
||||
function getIndentationCSS(level: number) {
|
||||
return `calc(1rem * ${level + 1})`
|
||||
@ -23,11 +25,11 @@ function getIndentationCSS(level: number) {
|
||||
|
||||
function RenameForm({
|
||||
fileOrDir,
|
||||
setIsRenaming,
|
||||
onSubmit,
|
||||
level = 0,
|
||||
}: {
|
||||
fileOrDir: FileEntry
|
||||
setIsRenaming: Dispatch<React.SetStateAction<boolean>>
|
||||
onSubmit: () => void
|
||||
level?: number
|
||||
}) {
|
||||
const { send } = useFileContext()
|
||||
@ -35,7 +37,6 @@ function RenameForm({
|
||||
|
||||
function handleRenameSubmit(e: React.FormEvent<HTMLFormElement>) {
|
||||
e.preventDefault()
|
||||
setIsRenaming(false)
|
||||
send({
|
||||
type: 'Rename file',
|
||||
data: {
|
||||
@ -49,7 +50,7 @@ function RenameForm({
|
||||
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
|
||||
if (e.key === 'Escape') {
|
||||
e.stopPropagation()
|
||||
setIsRenaming(false)
|
||||
onSubmit()
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,10 +62,12 @@ function RenameForm({
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
autoFocus
|
||||
autoCapitalize="off"
|
||||
autoCorrect="off"
|
||||
placeholder={fileOrDir.name}
|
||||
className="w-full py-1 bg-transparent text-chalkboard-100 placeholder:text-chalkboard-70 dark:text-chalkboard-10 dark:placeholder:text-chalkboard-50 focus:outline-none focus:ring-0"
|
||||
onKeyDown={handleKeyDown}
|
||||
onBlur={() => setIsRenaming(false)}
|
||||
onBlur={onSubmit}
|
||||
style={{ paddingInlineStart: getIndentationCSS(level) }}
|
||||
/>
|
||||
</label>
|
||||
@ -75,7 +78,7 @@ function RenameForm({
|
||||
)
|
||||
}
|
||||
|
||||
function DeleteConfirmationDialog({
|
||||
function DeleteFileTreeItemDialog({
|
||||
fileOrDir,
|
||||
setIsOpen,
|
||||
}: {
|
||||
@ -84,48 +87,23 @@ function DeleteConfirmationDialog({
|
||||
}) {
|
||||
const { send } = useFileContext()
|
||||
return (
|
||||
<Dialog
|
||||
open={true}
|
||||
onClose={() => setIsOpen(false)}
|
||||
className="relative z-50"
|
||||
>
|
||||
<div className="fixed inset-0 bg-chalkboard-110/80 grid place-content-center">
|
||||
<Dialog.Panel className="rounded p-4 bg-chalkboard-10 dark:bg-chalkboard-100 border border-destroy-80 max-w-2xl">
|
||||
<Dialog.Title as="h2" className="text-2xl font-bold mb-4">
|
||||
Delete {fileOrDir.children !== undefined ? 'Folder' : 'File'}
|
||||
</Dialog.Title>
|
||||
<Dialog.Description className="my-6">
|
||||
This will permanently delete "{fileOrDir.name || 'this file'}"
|
||||
{fileOrDir.children !== undefined
|
||||
? ' and all of its contents. '
|
||||
: '. '}
|
||||
This action cannot be undone.
|
||||
</Dialog.Description>
|
||||
|
||||
<div className="flex justify-between">
|
||||
<ActionButton
|
||||
Element="button"
|
||||
onClick={async () => {
|
||||
<DeleteConfirmationDialog
|
||||
title={`Delete ${fileOrDir.children !== undefined ? 'folder' : 'file'}`}
|
||||
onDismiss={() => setIsOpen(false)}
|
||||
onConfirm={() => {
|
||||
send({ type: 'Delete file', data: fileOrDir })
|
||||
setIsOpen(false)
|
||||
}}
|
||||
iconStart={{
|
||||
icon: faTrashAlt,
|
||||
bgClassName: 'bg-destroy-80',
|
||||
iconClassName:
|
||||
'text-destroy-20 group-hover:text-destroy-10 hover:text-destroy-10 dark:text-destroy-20 dark:group-hover:text-destroy-10 dark:hover:text-destroy-10',
|
||||
}}
|
||||
className="hover:border-destroy-40 dark:hover:border-destroy-40"
|
||||
>
|
||||
Delete
|
||||
</ActionButton>
|
||||
<ActionButton Element="button" onClick={() => setIsOpen(false)}>
|
||||
Cancel
|
||||
</ActionButton>
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</div>
|
||||
</Dialog>
|
||||
<p className="my-4">
|
||||
This will permanently delete "{fileOrDir.name || 'this file'}"
|
||||
{fileOrDir.children !== undefined ? ' and all of its contents. ' : '. '}
|
||||
</p>
|
||||
<p className="my-4">
|
||||
Are you sure you want to delete "{fileOrDir.name || 'this file'}
|
||||
"? This action cannot be undone.
|
||||
</p>
|
||||
</DeleteConfirmationDialog>
|
||||
)
|
||||
}
|
||||
|
||||
@ -133,35 +111,57 @@ const FileTreeItem = ({
|
||||
project,
|
||||
currentFile,
|
||||
fileOrDir,
|
||||
onDoubleClick,
|
||||
onNavigateToFile,
|
||||
level = 0,
|
||||
}: {
|
||||
project?: IndexLoaderData['project']
|
||||
currentFile?: IndexLoaderData['file']
|
||||
fileOrDir: FileEntry
|
||||
onDoubleClick?: () => void
|
||||
onNavigateToFile?: () => void
|
||||
level?: number
|
||||
}) => {
|
||||
const { send, context } = useFileContext()
|
||||
const { send: fileSend, context: fileContext } = useFileContext()
|
||||
const { onFileOpen, onFileClose } = useLspContext()
|
||||
const navigate = useNavigate()
|
||||
const [isRenaming, setIsRenaming] = useState(false)
|
||||
const [isConfirmingDelete, setIsConfirmingDelete] = useState(false)
|
||||
const isCurrentFile = fileOrDir.path === currentFile?.path
|
||||
|
||||
const isRenaming = fileContext.itemsBeingRenamed.includes(fileOrDir.path)
|
||||
const removeCurrentItemFromRenaming = useCallback(
|
||||
() =>
|
||||
fileSend({
|
||||
type: 'assign',
|
||||
data: {
|
||||
itemsBeingRenamed: fileContext.itemsBeingRenamed.filter(
|
||||
(path) => path !== fileOrDir.path
|
||||
),
|
||||
},
|
||||
}),
|
||||
[fileContext.itemsBeingRenamed, fileOrDir.path, fileSend]
|
||||
)
|
||||
|
||||
const addCurrentItemToRenaming = useCallback(() => {
|
||||
fileSend({
|
||||
type: 'assign',
|
||||
data: {
|
||||
itemsBeingRenamed: [...fileContext.itemsBeingRenamed, fileOrDir.path],
|
||||
},
|
||||
})
|
||||
}, [fileContext.itemsBeingRenamed, fileOrDir.path, fileSend])
|
||||
|
||||
function handleKeyUp(e: React.KeyboardEvent<HTMLButtonElement>) {
|
||||
if (e.metaKey && e.key === 'Backspace') {
|
||||
// Open confirmation dialog
|
||||
setIsConfirmingDelete(true)
|
||||
} else if (e.key === 'Enter') {
|
||||
// Show the renaming form
|
||||
setIsRenaming(true)
|
||||
addCurrentItemToRenaming()
|
||||
} else if (e.code === 'Space') {
|
||||
handleDoubleClick()
|
||||
handleClick()
|
||||
}
|
||||
}
|
||||
|
||||
function handleDoubleClick() {
|
||||
function handleClick() {
|
||||
if (fileOrDir.children !== undefined) return // Don't open directories
|
||||
|
||||
if (fileOrDir.name?.endsWith(FILE_EXT) === false && project?.path) {
|
||||
@ -181,7 +181,7 @@ const FileTreeItem = ({
|
||||
// Open kcl files
|
||||
navigate(`${paths.FILE}/${encodeURIComponent(fileOrDir.path)}`)
|
||||
}
|
||||
onDoubleClick?.()
|
||||
onNavigateToFile?.()
|
||||
}
|
||||
|
||||
return (
|
||||
@ -199,8 +199,10 @@ const FileTreeItem = ({
|
||||
<button
|
||||
className="flex gap-1 items-center py-0.5 rounded-none border-none p-0 m-0 text-sm w-full hover:!bg-transparent text-left !text-inherit"
|
||||
style={{ paddingInlineStart: getIndentationCSS(level) }}
|
||||
onDoubleClick={handleDoubleClick}
|
||||
onClick={(e) => e.currentTarget.focus()}
|
||||
onClick={(e) => {
|
||||
e.currentTarget.focus()
|
||||
handleClick()
|
||||
}}
|
||||
onKeyUp={handleKeyUp}
|
||||
>
|
||||
<CustomIcon
|
||||
@ -212,7 +214,7 @@ const FileTreeItem = ({
|
||||
) : (
|
||||
<RenameForm
|
||||
fileOrDir={fileOrDir}
|
||||
setIsRenaming={setIsRenaming}
|
||||
onSubmit={removeCurrentItemFromRenaming}
|
||||
level={level}
|
||||
/>
|
||||
)}
|
||||
@ -225,17 +227,23 @@ const FileTreeItem = ({
|
||||
<Disclosure.Button
|
||||
className={
|
||||
' group border-none text-sm rounded-none p-0 m-0 flex items-center justify-start w-full py-0.5 hover:text-primary hover:bg-primary/5 dark:hover:text-inherit dark:hover:bg-primary/10' +
|
||||
(context.selectedDirectory.path.includes(fileOrDir.path)
|
||||
(fileContext.selectedDirectory.path.includes(fileOrDir.path)
|
||||
? ' ui-open:bg-primary/10'
|
||||
: '')
|
||||
}
|
||||
style={{ paddingInlineStart: getIndentationCSS(level) }}
|
||||
onClick={(e) => e.currentTarget.focus()}
|
||||
onClickCapture={(e) =>
|
||||
send({ type: 'Set selected directory', data: fileOrDir })
|
||||
fileSend({
|
||||
type: 'Set selected directory',
|
||||
data: fileOrDir,
|
||||
})
|
||||
}
|
||||
onFocusCapture={(e) =>
|
||||
send({ type: 'Set selected directory', data: fileOrDir })
|
||||
fileSend({
|
||||
type: 'Set selected directory',
|
||||
data: fileOrDir,
|
||||
})
|
||||
}
|
||||
onKeyDown={(e) => e.key === 'Enter' && e.preventDefault()}
|
||||
onKeyUp={handleKeyUp}
|
||||
@ -263,7 +271,7 @@ const FileTreeItem = ({
|
||||
/>
|
||||
<RenameForm
|
||||
fileOrDir={fileOrDir}
|
||||
setIsRenaming={setIsRenaming}
|
||||
onSubmit={removeCurrentItemFromRenaming}
|
||||
level={-1}
|
||||
/>
|
||||
</div>
|
||||
@ -279,10 +287,16 @@ const FileTreeItem = ({
|
||||
<ul
|
||||
className="m-0 p-0"
|
||||
onClickCapture={(e) => {
|
||||
send({ type: 'Set selected directory', data: fileOrDir })
|
||||
fileSend({
|
||||
type: 'Set selected directory',
|
||||
data: fileOrDir,
|
||||
})
|
||||
}}
|
||||
onFocusCapture={(e) =>
|
||||
send({ type: 'Set selected directory', data: fileOrDir })
|
||||
fileSend({
|
||||
type: 'Set selected directory',
|
||||
data: fileOrDir,
|
||||
})
|
||||
}
|
||||
>
|
||||
{fileOrDir.children?.map((child) => (
|
||||
@ -290,7 +304,7 @@ const FileTreeItem = ({
|
||||
fileOrDir={child}
|
||||
project={project}
|
||||
currentFile={currentFile}
|
||||
onDoubleClick={onDoubleClick}
|
||||
onNavigateToFile={onNavigateToFile}
|
||||
level={level + 1}
|
||||
key={level + '-' + child.path}
|
||||
/>
|
||||
@ -302,7 +316,7 @@ const FileTreeItem = ({
|
||||
</Disclosure>
|
||||
)}
|
||||
{isConfirmingDelete && (
|
||||
<DeleteConfirmationDialog
|
||||
<DeleteFileTreeItemDialog
|
||||
fileOrDir={fileOrDir}
|
||||
setIsOpen={setIsConfirmingDelete}
|
||||
/>
|
||||
@ -314,7 +328,7 @@ const FileTreeItem = ({
|
||||
interface FileTreeProps {
|
||||
className?: string
|
||||
file?: IndexLoaderData['file']
|
||||
closePanel: (
|
||||
onNavigateToFile: (
|
||||
focusableElement?:
|
||||
| HTMLElement
|
||||
| React.MutableRefObject<HTMLElement | null>
|
||||
@ -371,30 +385,34 @@ export const FileTreeMenu = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export const FileTree = ({ className = '', closePanel }: FileTreeProps) => {
|
||||
export const FileTree = ({
|
||||
className = '',
|
||||
onNavigateToFile: closePanel,
|
||||
}: FileTreeProps) => {
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className="flex items-center gap-1 px-4 py-1 bg-chalkboard-20/40 dark:bg-chalkboard-80/50 border-b border-b-chalkboard-30 dark:border-b-chalkboard-80">
|
||||
<h2 className="flex-1 m-0 p-0 text-sm mono">Files</h2>
|
||||
<FileTreeMenu />
|
||||
</div>
|
||||
<FileTreeInner onDoubleClick={closePanel} />
|
||||
<FileTreeInner onNavigateToFile={closePanel} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const FileTreeInner = ({
|
||||
onDoubleClick,
|
||||
onNavigateToFile,
|
||||
}: {
|
||||
onDoubleClick?: () => void
|
||||
onNavigateToFile?: () => void
|
||||
}) => {
|
||||
const loaderData = useRouteLoaderData(paths.FILE) as IndexLoaderData
|
||||
const { send, context } = useFileContext()
|
||||
const { send: fileSend, context: fileContext } = useFileContext()
|
||||
const { send: modelingSend } = useModelingContext()
|
||||
const documentHasFocus = useDocumentHasFocus()
|
||||
|
||||
// Refresh the file tree when the document gets focus
|
||||
useEffect(() => {
|
||||
send({ type: 'Refresh' })
|
||||
fileSend({ type: 'Refresh' })
|
||||
}, [documentHasFocus])
|
||||
|
||||
return (
|
||||
@ -402,15 +420,22 @@ export const FileTreeInner = ({
|
||||
<ul
|
||||
className="m-0 p-0 text-sm"
|
||||
onClickCapture={(e) => {
|
||||
send({ type: 'Set selected directory', data: context.project })
|
||||
fileSend({
|
||||
type: 'Set selected directory',
|
||||
data: fileContext.project,
|
||||
})
|
||||
}}
|
||||
>
|
||||
{sortProject(context.project.children || []).map((fileOrDir) => (
|
||||
{sortProject(fileContext.project?.children || []).map((fileOrDir) => (
|
||||
<FileTreeItem
|
||||
project={context.project}
|
||||
project={fileContext.project}
|
||||
currentFile={loaderData?.file}
|
||||
fileOrDir={fileOrDir}
|
||||
onDoubleClick={onDoubleClick}
|
||||
onNavigateToFile={() => {
|
||||
// Reset modeling state when navigating to a new file
|
||||
modelingSend({ type: 'Cancel' })
|
||||
onNavigateToFile?.()
|
||||
}}
|
||||
key={fileOrDir.path}
|
||||
/>
|
||||
))}
|
||||
|
@ -1,33 +1,26 @@
|
||||
import { Dialog } from '@headlessui/react'
|
||||
import { ActionButton } from 'components/ActionButton'
|
||||
|
||||
interface DeleteProjectDialogProps {
|
||||
projectName: string
|
||||
interface DeleteConfirmationDialogProps extends React.PropsWithChildren<{}> {
|
||||
title: string
|
||||
onConfirm: () => void
|
||||
onDismiss: () => void
|
||||
}
|
||||
|
||||
export function DeleteProjectDialog({
|
||||
projectName,
|
||||
export function DeleteConfirmationDialog({
|
||||
title,
|
||||
onConfirm,
|
||||
onDismiss,
|
||||
}: DeleteProjectDialogProps) {
|
||||
children,
|
||||
}: DeleteConfirmationDialogProps) {
|
||||
return (
|
||||
<Dialog open={true} onClose={onDismiss} className="relative z-50">
|
||||
<div className="fixed inset-0 grid bg-chalkboard-110/80 place-content-center">
|
||||
<Dialog.Panel className="max-w-2xl p-4 border rounded bg-chalkboard-10 dark:bg-chalkboard-100 border-destroy-80">
|
||||
<Dialog.Title as="h2" className="mb-4 text-2xl font-bold">
|
||||
Delete File
|
||||
{title}
|
||||
</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
This will permanently delete "{projectName || 'this file'}
|
||||
".
|
||||
</Dialog.Description>
|
||||
|
||||
<p className="my-4">
|
||||
Are you sure you want to delete "{projectName || 'this file'}
|
||||
"? This action cannot be undone.
|
||||
</p>
|
||||
<Dialog.Description>{children}</Dialog.Description>
|
||||
|
||||
<div className="flex justify-between">
|
||||
<ActionButton
|
||||
|
@ -5,7 +5,7 @@ import { ActionButton } from '../ActionButton'
|
||||
import { FILE_EXT } from 'lib/constants'
|
||||
import { useHotkeys } from 'react-hotkeys-hook'
|
||||
import Tooltip from '../Tooltip'
|
||||
import { DeleteProjectDialog } from './DeleteProjectDialog'
|
||||
import { DeleteConfirmationDialog } from './DeleteProjectDialog'
|
||||
import { ProjectCardRenameForm } from './ProjectCardRenameForm'
|
||||
import { Project } from 'wasm-lib/kcl/bindings/Project'
|
||||
|
||||
@ -160,14 +160,23 @@ function ProjectCard({
|
||||
</div>
|
||||
)}
|
||||
{isConfirmingDelete && (
|
||||
<DeleteProjectDialog
|
||||
projectName={project.name}
|
||||
<DeleteConfirmationDialog
|
||||
title="Delete Project"
|
||||
onConfirm={async () => {
|
||||
await handleDeleteProject(project)
|
||||
setIsConfirmingDelete(false)
|
||||
}}
|
||||
onDismiss={() => setIsConfirmingDelete(false)}
|
||||
/>
|
||||
>
|
||||
<p className="my-4">
|
||||
This will permanently delete "{project.name || 'this file'}
|
||||
".
|
||||
</p>
|
||||
<p className="my-4">
|
||||
Are you sure you want to delete "{project.name || 'this file'}
|
||||
"? This action cannot be undone.
|
||||
</p>
|
||||
</DeleteConfirmationDialog>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
|
@ -158,7 +158,7 @@ function ProjectMenuPopover({
|
||||
<FileTree
|
||||
file={file}
|
||||
className="overflow-hidden border-0 border-y border-chalkboard-30 dark:border-chalkboard-80"
|
||||
closePanel={close}
|
||||
onNavigateToFile={close}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex-1 p-4 text-sm overflow-hidden">
|
||||
|
@ -4,7 +4,7 @@ import { Project } from 'wasm-lib/kcl/bindings/Project'
|
||||
|
||||
export const fileMachine = createMachine(
|
||||
{
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QDECWAbMACAtgQwGMALVAOzAGI9ZZUpSBtABgF1FQAHAe1oBdUupdiAAeiAKwBGcQDoALACYAHAE4AzGoUA2JXK1yANCACeiabOmSlGpkqsqAvg6NpMuQiXIyAEtSykuLAAzDDgKAGEAJzA8XmwQzGY2JBBuPgEhFLEESTVxWS1xBWVVcTU5PXEjUwRNFRkFWwB2FQVxJia5JnE5JxdQ92IyMB8-BLCAJTBSPBx40KThNNR+QWFslSVZJS1u3TUVSR1xJurEXSYZJslipismbTklPpBXbHwhr19YYNDYCOisXmiVYSx4Kwy6zMeQKRRKKjKFUKZwQPXqkjkmjUTCYWi0TQOCheb0GnhG31+mH+ABEwJg4pSwIsUstVplQNlcvkZIVikpSuVKijdFoZOItJJpEomtcYUTnK8Bh8yaMfuN-gB5DjTRnMzjgtlQnIwnlw-kIwXIkyIdSSGRKHF5XFqSwdYlKjzDVWM-4AZTAvCwsDpYAIcQgWAgqGiYa4kWMetSBshWTMNyaMkOuV0ChUBJUEpRnUuux6WmxGkkTF6CpJyq9URi-FIUEZFAgghGZAAblwANYjAiAuIAWnGidZKY50O5vPhiKF1oQcnF9q0myYCN2FSa4ndbnrXkbsTIrfGFDAkUicZkHHQsSCcZwMiHTbAY4WoJZybWqeNq82ddygUaQHiqJc7BkTRcwUOQjmKHR133d5PS8KYZhwU82w7Lwe37EZogw99xy-fV0l-adalzeQVForY1Ada4ni0FE5CaJRM0UAlmm6LRkNJL10NmLDz0va9Ilve9eEfSJn0I2ZiM-ZIyIhCjREQOoaLospGIxHYUQY0U8VaVoJUdB5+MPEZaXpETQnbTsZDwgcZAgENRxI5Sk3I9l1P-UVci6cUbg0JRlBRcRNkzHRdwUGVaPEOxLNQ6z3LszALyvG87wfJ9XPcxSQS8yc1M5PIMz0aU7gYuQCyOIsegaaUCTCwpnT42sPU+EYpjwKMWx9BzcNIXsXMBCAPypCcf187I7DUGQqweWDGgJNR8SLJ55AY9ibgLPJy2S7qZF6-qzz+IauxG-CZHGya4AYSRipmo15sWnFikUDoNA2pcXVkBQbFo7FuMkJojpVU70rCMTsqkmS5JiCb1WmnzXtyd7lq+tbfpqYoFEzSL9DqNofo6-oDxSigpiCaJYCIVHVNmxAtEaBpyxuZQ8iOaQUTBjNpWJxo2l3TpnheAI3PgFI6xSsE0b-EcWKXJWZBxHF2hAip0ySzrKeOikAh9eWmaNSVriappqy2CpWkkAzqLUJp8Q5h4DgRGsKZQg2xj+E3DT-c2OIlGVdwqFc4rUYUuntB0wesaQmhAvc9e9lVj2bc7MH9qc-OkNjMwFfkygLWqIpxe0cTsWCOiOE4IcE6ZhIG8Yc9KxBFFYlp5EkWirFB6Q1AbrwbIDaG2+ZnIegzTYLWLg59BUYUmAWwHKo3B51HlL2BLQpHoellSA8oooOOsSLGiRdowdY2r7RWu5OhdQLycVfWVS1aZx+-BXKPzmei70VLkvJcKhbBijKHicq3QQLiycEAA */
|
||||
/** @xstate-layout N4IgpgJg5mDOIC5QDECWAbMACAtgQwGMALVAOzAGI9ZZUpSBtABgF1FQAHAe1oBdUupdiAAeiAKwBGcQDoALACYAHAE4AzGoUA2JXK1yANCACeiabOmSlGpkqsqAvg6NpMuQiXIUASmABmAE5wRMxsSCDcfAJC4WIIWgpMMtpqkgrKalJa0kamCJIA7AUySgX6mkwK4gXVckpOLhjY+MRkYDIAEtRYpFxYfk2wFADCQXi82AOYocKRqPyCwnGSmbJa4ulKquJqcnriuYiaKsm2BSpVTAVyTOJyDSCuzR5tnd1TcD5gpHg4k00zcJzBYxUBxFRKWRKLS3XRqFSSHTVQ4IXRJAppRJWSr6erOR5NdytchvWD9QYjMYTcnTVizHjzaJLMyrGTrTbbXb7FF3E6SOSaNRMJhaLQFeEKB5PImedpdMkfIYAETAmGpH0BnAZIOZ+VZ7OUnL26xRui0MnE2WkpQxq0l+OlLVlpJpnwA8hxvq7NRFtUzYizxGsNoaVDtjQcTIh1JISsLMiLUlIrlLCU7XvLXUMAMpgXhYWCqsAECYQLAQVBBEtcALGH3A-1gsxpYoIla6BQqcUqbIo65JGF3LRCjSSJj3B1pl4k0ZgcZkKCuigQQTtMgANy4AGt2gQqWAALQaulAv2LAP5ZQnaoQuR3K5KJg5KMIeFJJSJfQFeM7NSQ1NuOmM5UguS5gAEAQ1jIHDoOMfg1jgMh7nOExHgCJ5alE55NnqloyBCWjqIo0iVJGeR2DImidgociIukOiEQBzzEu0vg-DgoEfMuq4yBu27tEE7GHseYSYYy2GiEcTBqPIVQ1FcEL8toKIJOaaQXPY2TWOIeKNIB06sd8vycU0FDgZBATQbBvDwQEiGCb8wnoaJvpYaCkmvp28gqD5kJ-lc-LQiif7mqKFwXNk8aVExMqvCqaomZg3EknxO4yBARaoSJ9JubqKx4SsNyWmkGgfkoPIQvhOg1AoRQ+TpkgxUB7TxXmiWUOZUEwXBCHpZlTm0i5DYScsmTFHopRPn+cg9oifZ3MkNp-to4iJloTUGTIvh4BWpCLoqyVrqQm5pWMEBoZgsD1me7lxHYMljpUNGJOKahin2dTyH+BR2J2w6WmoG0sVtc67ftFIrilx38TIZ0XXADCSENN26vdMiPekihXBo70vkmyQ2D5Qrik+BRA8621g1mZkQV11m2fZoPw1dGGueJt2IGjGPPdjb0FCi6QKPh4g9gK1G-qKTj4r0GXwOEjoGTl7O6gomgWtcVR3kVH6GC+B5QuUlphtJKhaxOenMc6ma9FmSs6hekiFLGyjfnUdwzQokjBV5ahlGUqSVPCYbmwS+nA5mip242HmOz9bKFEU7t3rVaimjcJSPoU1jSAUnviOTryzvOe2ulHI1mHcraclsOyiyoPLCnGthpDcGLrGTk5hxTRkcSXHxlxzCDKEktSa-eOk0aajslLstyu9J1j2hbsUkq1-B900A95ZX+HV35demtJBMTRCwqdpoBckpT7Vy2J9s4RsSgzyLiQRqTKJ7CcOtYtcqSFetndLavA9N8dqW8HY7whGGP8+99D1xfCoWwFodiijGrcT2eInBAA */
|
||||
id: 'File machine',
|
||||
|
||||
initial: 'Reading files',
|
||||
@ -12,6 +12,7 @@ export const fileMachine = createMachine(
|
||||
context: {
|
||||
project: {} as Project,
|
||||
selectedDirectory: {} as FileEntry,
|
||||
itemsBeingRenamed: [] as string[],
|
||||
},
|
||||
|
||||
on: {
|
||||
@ -65,7 +66,11 @@ export const fileMachine = createMachine(
|
||||
onDone: [
|
||||
{
|
||||
target: 'Reading files',
|
||||
actions: ['toastSuccess'],
|
||||
actions: [
|
||||
'createToastSuccess',
|
||||
'addFileToRenamingQueue',
|
||||
'navigateToFile',
|
||||
],
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
@ -84,7 +89,7 @@ export const fileMachine = createMachine(
|
||||
onDone: [
|
||||
{
|
||||
target: '#File machine.Reading files',
|
||||
actions: ['toastSuccess'],
|
||||
actions: ['renameToastSuccess'],
|
||||
},
|
||||
],
|
||||
onError: [
|
||||
@ -94,6 +99,8 @@ export const fileMachine = createMachine(
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
exit: 'removeFileFromRenamingQueue',
|
||||
},
|
||||
|
||||
'Deleting file': {
|
||||
@ -157,6 +164,21 @@ export const fileMachine = createMachine(
|
||||
type: 'done.invoke.read-files'
|
||||
data: Project
|
||||
}
|
||||
| {
|
||||
type: 'done.invoke.rename-file'
|
||||
data: {
|
||||
message: string
|
||||
oldPath: string
|
||||
newPath: string
|
||||
}
|
||||
}
|
||||
| {
|
||||
type: 'done.invoke.create-file'
|
||||
data: {
|
||||
message: string
|
||||
path: string
|
||||
}
|
||||
}
|
||||
| { type: 'assign'; data: { [key: string]: any } }
|
||||
| { type: 'Refresh' },
|
||||
},
|
||||
|
Reference in New Issue
Block a user