Compare commits

...

425 commits

Author SHA1 Message Date
coderaiser
7f28803a82 chore: cloudcmd: actions: lint ☘️ 2026-07-16 15:31:22 +00:00
coderaiser
943bdecd3e test: coverage 2026-07-16 15:29:08 +00:00
coderaiser
e4ff4a78cc chore: cloudcmd: actions: lint ☘️ 2026-07-16 12:27:35 +00:00
coderaiser
fec5538f01 test: common: util: coverage 2026-07-16 12:26:33 +00:00
coderaiser
b7bb363aa8 test: cloudfunc: coverage 2026-07-16 12:23:46 +00:00
coderaiser
cd4a2cec76 chore: cloudcmd: actions: lint ☘️ 2026-07-16 09:28:42 +00:00
coderaiser
0638ca32cb feature: migrate from webpack to rspack 2026-07-16 12:27:20 +03:00
coderaiser
fe185cc93e chore: cloudcmd: actions: lint ☘️ 2026-07-15 20:27:25 +00:00
coderiaser
7edea50296 chore: lint 2026-07-15 23:26:28 +03:00
coderaiser
8258cdb651
chore: rm rulesdir 2026-07-15 21:18:06 +02:00
coderaiser
a9e29eee85 test: cloudcmd: coverage 2026-07-15 10:31:07 +00:00
coderaiser
a52a6aae62 test: coverage 2026-07-15 09:36:03 +00:00
coderaiser
92c79830f5 chore: madrun: test: rm test-e2e 2026-07-15 08:21:03 +00:00
coderiaser
8629f67972 feature: cloudcmd: docker: io: arm 2026-06-29 18:19:08 +03:00
coderiaser
c04d363c46 test: e2e: spawn 2026-06-29 18:16:34 +03:00
coderiaser
046a4ef22e chore: lint 2026-06-29 17:54:20 +03:00
coderiaser
579c9e41d7 feature: cloudcmd: serve-once v4.0.1 2026-06-29 17:48:06 +03:00
coderiaser
6014898610 feature: cloudcmd: @babel/preset-env v8.0.2 2026-06-29 17:48:06 +03:00
coderiaser
ad3bf95e5f feature: cloudcmd: @babel/plugin-transform-optional-chaining v8.0.1 2026-06-29 17:48:05 +03:00
coderiaser
4e22a4edde feature: cloudcmd: @babel/core v8.0.1 2026-06-29 17:48:04 +03:00
coderiaser
9c50fe53e7 feature: cloudcmd: @babel/code-frame v8.0.0 2026-06-29 17:48:04 +03:00
coderiaser
a2a2d51ec1 chore: cloudcmd: v19.19.1 2026-06-15 14:50:37 +03:00
coderiaser
c36c32cb08 chore: lint 2026-06-15 14:49:57 +03:00
coderiaser
78b206e06b feature: client: key: Ctrl + L -> Ctrl + Shift + L: Log out (#466) 2026-06-15 14:49:47 +03:00
coderiaser
ef83a61a0c chore: actions: typos 2026-06-04 17:55:58 +03:00
coderaiser
f5c0aa5c4c Update nodejs.yml 2026-06-04 17:55:44 +03:00
coderaiser
e59167b1fa chore: actions: permissions 2026-06-04 16:05:15 +03:00
coderiaser
ea584aceea chore: actions: typos.ai 2026-06-04 15:42:02 +03:00
coderiaser
4d7116b467 chore: docker: io: git 2026-06-03 23:47:50 +03:00
coderiaser
b149288545 feature: docker: io: NPM_CONFIG_PACKAGE_LOCK=false 2026-06-03 23:40:16 +03:00
coderiaser
9d06279ba8 featur: docker: io: add gh 2026-06-03 23:39:27 +03:00
coderiaser
21e1dcf0e5 chore: actions: typos 2026-06-03 18:46:19 +03:00
coderaiser
b3b0c1d159 chore: package: rm unused optimize-css-assets-webpack-plugin 2026-06-03 13:02:04 +00:00
coderaiser
76d7bf4d73
feature: docker: typos, shellcheck: add 2026-06-02 10:03:23 +02:00
coderaiser
f1d80282eb chore: cloudcmd: actions: lint ☘️ 2026-06-01 20:39:12 +00:00
coderiaser
220cc5557b chore: actions: API_KEY 2026-06-01 23:32:27 +03:00
coderiaser
d2176c93fb chore: actions: typo 2026-06-01 22:56:08 +03:00
coderaiser
c558e44a1c
docs: readme: InstaPods 2026-06-01 13:29:58 +03:00
coderaiser
45ec062bce
docs: readme: deploy on InstaPods 2026-06-01 13:24:07 +03:00
coderaiser
f8edddd442
chore: .nvmrc 2026-05-30 13:12:09 +02:00
coderiaser
fc3d5ac700 chore: cloudcmd: v19.19.0 2026-05-26 23:17:05 +03:00
coderaiser
4ee38db68c feature: client: view: flac: add support 2026-05-26 23:16:40 +03:00
coderiaser
1dfa7ca355 chore: cloudcmd: v19.18.1 2026-05-26 22:09:29 +03:00
coderiaser
40ecef5ec4 feature: cloudcmd: ratelimit: X-Forwarded-For (#437) 2026-05-26 22:08:16 +03:00
coderiaser
cad5e0f44e chore: lint 2026-05-26 21:45:25 +03:00
coderiaser
d139011cc3 chore: cloudcmd: v19.18.0 2026-05-26 00:21:45 +03:00
coderiaser
5d9628ce70 feature: cloudcmd: rate limit: add support (#437) 2026-05-26 00:21:24 +03:00
coderiaser
161bede8db fix: client: menu: @putout/bundle@5.5. 2026-05-24 22:24:54 +03:00
coderiaser
2be395e640 feature: cloudcmd: get rid of manifest: 401 basic auth 2026-05-24 21:40:26 +03:00
coderiaser
447d990f43 fix: cloudcmd: server: rest: sendError 2026-05-21 00:05:43 +03:00
coderaiser
4f4725ac3c chore: cloudcmd: actions: lint ☘️ 2026-05-17 11:25:50 +00:00
coderiaser
eff03299b6 chore: cloudcmd: v19.17.0 2026-05-17 14:24:10 +03:00
coderiaser
a6adf39db2 chore: lint 2026-05-17 14:24:10 +03:00
coderiaser
70ff6fb29f feature: cloudcmd: cssnano-preset-default v8.0.1 2026-05-17 14:24:10 +03:00
coderiaser
eb32fff688 feature: style: owner, mode: improve 2026-05-17 14:24:10 +03:00
coderiaser
6071b66118 fix: css: query: hide time on mobile 2026-05-17 14:24:10 +03:00
coderiaser
83c0b8d3f1 feature: cloudcmd: superc8 v12.6.0 2026-05-17 14:24:10 +03:00
coderiaser
79da2319f8 feature: docker: io: cline: add 2026-05-17 14:24:10 +03:00
coderiaser
68eacb916a feature: qword: add 2026-05-13 00:22:57 +03:00
coderiaser
ccf608a52e chore: lint 2026-05-10 22:51:18 +03:00
coderiaser
4acd294bf6 feature: docker: io: tmux 2026-05-10 22:44:33 +03:00
coderiaser
05c800431d feature: cloudcmd: @supertape/loader-css v1.0.0 2026-05-06 22:21:16 +03:00
coderiaser
6ff1db2710 chore: lint 2026-05-05 23:51:29 +03:00
coderiaser
800a6545a1 feature: cloudcmd: eslint-plugin-n v18.0.1 2026-05-05 23:51:23 +03:00
coderiaser
a985bb36ca feature: cloudcmd: supertape v13.0.0 2026-05-05 23:50:02 +03:00
coderiaser
e7c55e05b8 fix: docker: io: XDG_CONFIG_HOME 2026-05-03 23:57:16 +03:00
coderiaser
4315ec6179 feature: docker: io XDG_CONFIG_HOME: /etc -> /usr/local/etc 2026-05-03 16:08:15 +03:00
coderiaser
628d12fa2f chore: cloudcmd: v19.16.0 2026-05-03 16:02:16 +03:00
coderiaser
d82d0335b2 feature: client: vim: rr for rename file 2026-05-03 16:01:46 +03:00
coderiaser
acfa27cf74 feature: docker: io: nvchad: add 2026-05-03 00:42:54 +03:00
coderiaser
14f009f832 feature: docker: io: bash-completion: add 2026-05-03 00:16:16 +03:00
coderiaser
d1f6476604 chore: docker: io: no git 2026-05-01 21:01:24 +03:00
coderiaser
c6c6014691 feature: docker: io: f4 2026-05-01 20:21:49 +03:00
coderiaser
9a6b89356e feature: docker: io: GOPATH 2026-05-01 19:05:41 +03:00
coderiaser
882fe83623 chore: cloudcmd: v19.15.0 2026-04-29 12:36:10 +03:00
coderiaser
a9bc22ce29 feature: cloudcmd: operation: rm useless checks 2026-04-29 12:36:10 +03:00
coderiaser
36bacfe915 feature: cloudcmd: client: key: vim: cc, mm 2026-04-29 12:36:10 +03:00
coderiaser
bcbef1a3b0 chore: cloudcmd: v19.14.0 2026-04-29 12:36:10 +03:00
coderiaser
591da25cfe feature: cloudcmd: ponse v8.0.0 2026-04-29 12:36:10 +03:00
coderiaser
1e1b073c8c feature: docker: io: /usr/src/cloudcmd -> /usr/local/share/cloudcmd 2026-04-29 12:35:51 +03:00
coderiaser
ea7b828cbb feature: docker: io: ubuntu: resolute 2026-04-26 18:38:39 +03:00
coderiaser
cd6c11ace2 feature: docker: io: far2l 2026-04-26 18:29:45 +03:00
coderiaser
c4beeec63b feature: docker: io: gdu: add 2026-04-26 12:06:57 +03:00
coderiaser
87c13e7cce chore: cloudcmd: v19.13.1 2026-04-21 23:31:22 +03:00
coderiaser
d5cd11e812 feature: cloudcmd: montag v2.0.1 2026-04-21 23:30:41 +03:00
coderiaser
dc94d2db7a feature: docker: io: add latest git version 2026-04-21 22:47:17 +03:00
coderiaser
1637beee78 feature: docker: io: /usr/local/src -> /usr/local/share 2026-04-20 23:46:29 +03:00
coderaiser
0541b7e351 chore: cloudcmd: actions: lint ☘️ 2026-04-19 16:35:25 +00:00
coderiaser
b1bc4e731f feature: Docker: io: pv 2026-04-19 19:34:22 +03:00
coderiaser
7c0dca6038 feature: docker: io: git: master 2026-04-15 16:22:31 +03:00
coderiaser
24fd0a8aa7 chore: cloudcmd: v19.13.0 2026-04-15 02:39:12 +03:00
coderiaser
2b3dc1573d feature: cloudcmd: Ctrl + L: logout 2026-04-15 02:39:12 +03:00
coderiaser
48693d9e24 fix: docker: io: XDG_CACHE_HOME 2026-04-14 00:09:31 +03:00
coderiaser
977a8aaaf4 feature: docker: io: strace: add 2026-04-13 22:40:14 +03:00
coderiaser
15537ec518 chore: docker: io: remove haskell
This reverts commit b0687b54c7.
2026-04-13 22:36:54 +03:00
coderiaser
7d0098fd5c feature: docker: io: XDG_CACHE_HOME=/tmp/cache 2026-04-13 22:36:43 +03:00
coderiaser
da0c4c4704 chore: actions: docker: io: rm cache 2026-04-13 22:36:43 +03:00
coderiaser
b0687b54c7 chore: docker: io: get back haskell 2026-04-13 22:36:43 +03:00
coderiaser
a89e901b2b feature: actions: docker: io: add 2026-04-12 19:00:58 +03:00
coderiaser
ef06a0c310 chore: cloudcmd: v19.12.5 2026-04-12 18:37:50 +03:00
coderiaser
e7242900a4 chore: docker: io: get rid of haskell 2026-04-12 18:37:50 +03:00
coderiaser
a6b01dce49 chore: actions: cache 2026-04-12 18:31:55 +03:00
coderiaser
1cfc1a6f5d feature: docker: io: only amd64 2026-04-12 18:03:46 +03:00
coderiaser
9915757dce chore: cloudcmd: v19.12.4 2026-04-12 14:13:49 +03:00
coderiaser
673fba2e21 feature: docker: io: haskell 2026-04-12 14:13:49 +03:00
coderiaser
d37f8cd36e feature: docker: io: palabra: node 2026-04-12 13:56:16 +03:00
coderiaser
5e509a4d7b chore: cloudcmd: v19.12.3 2026-04-12 13:04:53 +03:00
coderiaser
cb6cabd4c9 feature: docker: io: PALABRA_DIR 2026-04-12 12:54:58 +03:00
coderiaser
f61cc46f41 chore: cloudcmd: v19.12.2 2026-04-11 22:29:12 +03:00
coderiaser
32a8f169d4 feature: docker: io: get rid of haskell: to slow install 2026-04-11 22:29:12 +03:00
coderiaser
aa74123228 feature: docker: io: rizin, yara 2026-04-11 16:47:53 +03:00
coderiaser
27f20d6af8 chore: cloudcmd: v19.12.1 2026-04-11 15:54:19 +03:00
coderiaser
4695480ead feature: docker: io: add PREFIX 2026-04-11 15:54:19 +03:00
coderiaser
bec3f5a799 chore: cloudcmd: v19.12.0 2026-04-09 19:14:43 +03:00
coderiaser
13b15b7bea feature: docker: io: palabra 2026-04-09 19:13:55 +03:00
coderiaser
969bc770e3 chore: cloudcmd: v19.11.14 2026-04-07 20:55:31 +03:00
coderiaser
5ecc48e348 feature: docker: io: rustup env 2026-04-07 20:55:31 +03:00
coderiaser
9efefc23e0 chore: cloudcmd: v19.11.13 2026-04-07 12:34:02 +03:00
coderiaser
6a08479a1b feature: docker: io: BUN_INSTALL 2026-04-07 12:33:26 +03:00
coderiaser
c2563ed6b3 chore: cloudcmd: v19.11.12 2026-04-06 21:22:52 +03:00
coderiaser
46c655546e feature: docker: io: npm_config_cache 2026-04-06 21:22:23 +03:00
coderiaser
4fa0786a39 chore: cloudcmd: v19.11.11 2026-04-06 20:59:36 +03:00
coderiaser
ae2ce3882c feature: docker: io: $DENO_DIR 2026-04-06 20:58:51 +03:00
coderiaser
3c9389c4f0 chore: cloudcmd: v19.11.10 2026-04-06 19:56:41 +03:00
coderiaser
bb6be7abbb feature: docker: io: nvm: node 2026-04-06 19:56:41 +03:00
coderiaser
3aac4e68b4 chore: cloudcmd: v19.11.9 2026-04-06 13:24:03 +03:00
coderiaser
ea96d13fab feature: docker: io: net-tools 2026-04-06 13:23:34 +03:00
coderiaser
f9c5804fb8 chore: cloudcmd: v19.11.8 2026-04-06 12:56:31 +03:00
coderiaser
84f96fa185 feature: docker: io: debian -> ubuntu 2026-04-06 12:56:31 +03:00
coderiaser
8238bd4011 chore: cloudcmd: v19.11.7 2026-04-05 21:38:55 +03:00
coderiaser
36cdef3717 feature: docker: io: bookworm 2026-04-05 21:38:26 +03:00
coderiaser
f8035d6c49 chore: cloudcmd: v19.11.6 2026-04-05 20:53:01 +03:00
coderiaser
845f9bd127 feature: cloudcmd: gritty v10.2.0 2026-04-05 20:52:26 +03:00
coderiaser
b5ec9ce210 chore: cloudcmd: v19.11.5 2026-04-05 00:33:37 +03:00
coderiaser
71a1d78c39 feature: docker: io: hexyl: add 2026-04-05 00:33:37 +03:00
coderiaser
6bbfeb9024 chore: cloudcmd: v19.11.4 2026-04-05 00:33:37 +03:00
coderiaser
a038470816 feature: docker: io: neovim: apt -> github 2026-04-05 00:33:37 +03:00
coderiaser
45e0ff41f4 chore: cloudcmd: v19.11.3 2026-04-04 18:39:59 +03:00
coderiaser
9970ff7629 feature: docker: io: btop 2026-04-04 18:34:13 +03:00
coderiaser
4395a47178 feature: docker: io: $PATH: add $HOME/.local/bin 2026-04-04 18:30:01 +03:00
coderiaser
77daf5028e chore: cloudcmd: v19.11.2 2026-04-04 18:23:34 +03:00
coderiaser
c40ae8e405 feature: docker: io: htop 2026-04-04 18:23:04 +03:00
coderiaser
f463c5c5a7 feature: docker: io: aptitude: add 2026-04-04 17:20:05 +03:00
coderiaser
d1032f09ab feature: docker: io: remove unused 2026-04-04 17:19:09 +03:00
coderiaser
b3e682c0a5 chore: cloudcmd: v19.11.1 2026-04-04 17:11:39 +03:00
coderiaser
ffabdc5276 feature: docker: io: ncdu 2026-04-04 17:11:39 +03:00
coderiaser
7787bfc22e feature: cloudcmd: user-menu: runFromCDN 2026-04-04 17:04:55 +03:00
coderiaser
406429aec8 chore: cloudcmd: v19.11.0 2026-04-04 02:05:28 +03:00
coderiaser
32f89d3874 feature: cloudcmd: user-menu: root 2026-04-04 02:04:40 +03:00
coderiaser
1c0021dbb6 chore: cloudcmd: v19.10.2 2026-04-04 00:06:30 +03:00
coderiaser
df4fb51716 feature: cloudcmd: aleman v2.0.1 2026-04-04 00:05:55 +03:00
coderiaser
314cceb462 chore: cloudcmd: v19.10.1 2026-04-03 23:12:27 +03:00
coderiaser
ceb7ef4ff7 feature: docker: io: keep /var/lib/apt/lists 2026-04-03 23:12:00 +03:00
coderiaser
34fad6ea73 chore: cloudcmd: v19.10.0 2026-04-02 18:19:15 +03:00
chaoliang yan
d12e7bd0c5 fix: distribute: fix event listener leak on socket disconnect (#462) 2026-04-02 18:18:47 +03:00
coderiaser
b8a621ca1b chore: cloudcmd: v19.9.24 2026-04-02 18:13:16 +03:00
coderiaser
1fc1e3734c feature: docker: io: apt-get upgrade 2026-04-02 18:13:16 +03:00
coderiaser
582b7423dc chore: cloudcmd: v19.9.23 2026-04-01 23:25:43 +03:00
coderiaser
e4d7d441fc feature: docker: io: nix 2026-04-01 23:25:43 +03:00
coderiaser
e53aa06cdb chore: cloudcmd: v19.9.22 2026-03-31 00:59:44 +03:00
coderiaser
b4345ed40d feature: docker: io: DENO_DIR 2026-03-31 00:59:02 +03:00
coderiaser
ddbf4d69a4 chore: cloudcmd: v19.9.21 2026-03-31 00:55:49 +03:00
coderiaser
e2855641ca feature: docker: io: rustup 2026-03-31 00:55:49 +03:00
coderiaser
5c6a9a958e fix: css: columns: name: 40% -> 35% 2026-03-31 00:50:35 +03:00
coderiaser
d2a7f6343a chore: cloudcmd: v19.9.20 2026-03-31 00:28:13 +03:00
coderiaser
2b29448062 feature: iocmd: io: nvm 2026-03-31 00:28:13 +03:00
coderiaser
09a8b2bd1c chore: cloudcmd: v19.9.19 2026-03-30 20:54:27 +03:00
coderiaser
6a52b11e46 feature: docker: io: go, rust 2026-03-30 20:53:59 +03:00
coderiaser
9a053ec374 chore: cloudcmd: v19.9.18 2026-03-30 20:36:44 +03:00
coderaiser
6aa496c995 chore: cloudcmd: actions: lint ☘️ 2026-03-30 20:36:43 +03:00
coderiaser
738059f27f feature: docker: io: fzf 2026-03-30 19:19:04 +03:00
coderiaser
3fc8932f4c feature: docker: io: less, el_GR 2026-03-30 19:10:51 +03:00
coderiaser
2db458bc7b chore: cloudcmd: v19.9.17 2026-03-30 00:11:13 +03:00
coderiaser
cf424d6c05 feature: docker: io: command-not-found update 2026-03-30 00:10:48 +03:00
coderiaser
8b9004b4dd chore: cloudcmd: v19.9.16 2026-03-29 23:22:14 +03:00
coderiaser
efb24e229f feature: docker: io: get back debian 2026-03-29 23:22:14 +03:00
coderiaser
19347a2b4c feature: docker: io: add command-not-found 2026-03-29 23:14:51 +03:00
coderiaser
a80f109d19 chore: cloudcmd: v19.9.15 2026-03-29 22:42:08 +03:00
coderiaser
74e008198f feature: docker: io: BUN_INSTALL_CACHE_DIR 2026-03-29 22:42:08 +03:00
coderiaser
d25a08d2bd feature: docker: io: ubuntu 2026-03-29 22:42:08 +03:00
coderiaser
e04c459489 feature: docker: io: net-tools: add 2026-03-29 20:12:12 +03:00
coderiaser
3d2944bd13 chore: cloudcmd: v19.9.14 2026-03-29 19:58:06 +03:00
coderaiser
52a9076f14 chore: cloudcmd: actions: lint ☘️ 2026-03-29 14:01:56 +00:00
coderiaser
7e2d2ede98 test: bin: coverage 2026-03-29 17:00:48 +03:00
coderiaser
6c7709be9c fix: docker: io: PS1 2026-03-29 17:00:48 +03:00
coderiaser
340a639f1b test: bin: cloudcmd: -h 2026-03-29 13:44:18 +03:00
coderiaser
aa5a772f00 chore: cloudcmd: v19.9.13 2026-03-29 13:41:12 +03:00
coderiaser
439b3710cc fix: bin: currify 2026-03-29 13:40:39 +03:00
coderiaser
e41828410c fix: docker: io: xterm-256color 2026-03-29 13:39:54 +03:00
coderiaser
799d86bda4 chore: cloudcmd: v19.9.12 2026-03-29 12:58:45 +03:00
coderiaser
a423739cb8 feature: cloudcmd: bin: get rid of require 2026-03-29 12:58:45 +03:00
coderiaser
47acb8fdf7 chore: cloudcmd: v19.9.11 2026-03-29 12:30:45 +03:00
coderiaser
1f95f18898 feature: cloudcmd: get rid of simport 2026-03-29 12:29:39 +03:00
coderiaser
2aaf0a5385 chore: cloudcmd: v19.9.10 2026-03-29 12:21:37 +03:00
coderiaser
1a44ab0eac fix: docker: io: use node
This reverts commit cc7f9dc75b.
2026-03-29 12:21:37 +03:00
coderiaser
fe3e201143 docs: help: readme from cloudcmd.io 2026-03-29 12:21:37 +03:00
coderiaser
f0deb32362 feature: docker: io: add ja_JP.UTF-8 2026-03-29 00:59:53 +02:00
coderiaser
ba6f66e73e chore: cloudcmd: v19.9.9 2026-03-29 00:56:35 +02:00
coderiaser
cc7f9dc75b feature: docker: io: use ubuntu 2026-03-29 00:55:53 +02:00
coderaiser
f671f79814
fix: docker: io: PS1 environment variable in Dockerfile 2026-03-28 23:42:07 +01:00
coderaiser
fa8875d53c chore: cloudcmd: actions: lint ☘️ 2026-03-28 20:44:34 +00:00
coderiaser
2dd62241f7 chore: cloudcmd: v19.9.8 2026-03-28 22:43:32 +02:00
coderiaser
4d1cd8cdc6 feature: docker: io: ffmpeg 2026-03-28 22:42:38 +02:00
coderiaser
54b56fdc38 feature: cloudcmd: vim: ESC: use only to enable, do not use to disable 2026-03-28 22:40:46 +02:00
coderiaser
785c32e2e3 chore: docker: io: echo 2026-03-27 19:50:01 +02:00
coderiaser
c3f2b7c32f chore: cloudcmd: v19.9.7 2026-03-27 19:46:11 +02:00
coderiaser
110908e221 feature: docker: io: apt-get 2026-03-27 19:45:32 +02:00
coderiaser
8be917da4a chore: cloudcmd: v19.9.6 2026-03-27 18:31:34 +02:00
coderiaser
8db81f30dc feature: docker: io: add UTF-8 2026-03-27 18:31:34 +02:00
coderiaser
56439d5ec2 chore: cloudcmd: v19.9.5 2026-03-26 13:17:11 +02:00
coderiaser
e761cacbd0 fix: columns: name-size-date-time: 20% -> 19% 2026-03-26 13:16:40 +02:00
coderiaser
0bb706995a chore: cloudcmd: v19.9.4 2026-03-26 13:15:02 +02:00
coderiaser
69498ed6ab feature: docker: io: pull.rebase by default 2026-03-26 13:13:44 +02:00
coderiaser
82f8d846a9 chore: docker: get rid of healcheck 2026-03-24 16:41:10 +02:00
coderiaser
1ea4aa67ca chore: cloudcmd: v19.9.3 2026-03-24 16:33:55 +02:00
coderiaser
8763788bad feature: docker: io: healthcheck 2026-03-24 16:33:31 +02:00
coderiaser
c1c67c18af chore: cloudcmd: v19.9.2 2026-03-23 23:55:21 +02:00
coderiaser
09a02074e1 feature: docker: io: git config: add 2026-03-23 23:54:48 +02:00
coderiaser
c448eaa48b feature: docker: io: buni 2026-03-23 23:54:48 +02:00
coderaiser
05ad2fd635 chore: cloudcmd: actions: lint ☘️ 2026-03-23 21:50:02 +00:00
coderiaser
b949a149ec chore: cloudcmd: v19.9.1 2026-03-23 23:49:01 +02:00
coderiaser
6e5318faa7 fix: client: modules: config: input: quote 2026-03-23 23:48:34 +02:00
coderiaser
ec66ba78a7 chore: cloudcmd: v19.9.0 2026-03-23 23:04:38 +02:00
coderiaser
a1216cddeb feature: cloudcmd: add ability to hide port configuration 2026-03-23 23:03:47 +02:00
coderiaser
2f0affd3a3 chore: cloudcmd: v19.8.15 2026-03-23 22:51:10 +02:00
coderiaser
68b2aa780b feature: docker: io: cloudcmd_vim 2026-03-23 22:50:34 +02:00
coderiaser
56e21b4011 chore: cloudcmd: v19.8.14 2026-03-23 22:12:37 +02:00
coderiaser
665ed9c2e9 fix: docker: io: get back port 2026-03-23 22:12:03 +02:00
coderiaser
a44a28f496 chore: cloudcmd: v19.8.13 2026-03-23 19:42:52 +02:00
coderaiser
f51229fc6f feature: docker: io: port 2026-03-23 17:42:02 +00:00
coderiaser
0c9f3922f8 chore: actions: lint 2026-03-23 19:19:04 +02:00
coderiaser
4410cd2665 chore: cloudcmd: v19.8.12 2026-03-23 17:07:19 +00:00
coderiaser
618a561514 feature: docker: io: PS1 2026-03-23 17:07:19 +00:00
coderiaser
682729ac3e chore: cloudcmd: v19.8.11 2026-03-23 18:53:19 +02:00
coderiaser
67f27d8425 feature: docker: io: bun, deno 2026-03-23 18:52:54 +02:00
coderiaser
97672ef5d5 fix: docker: io: apt-get install -> apt-get 2026-03-23 18:41:51 +02:00
coderiaser
e6684df59e chore: cloudcmd: v19.8.10 2026-03-23 18:32:52 +02:00
coderiaser
9493e4de7e featur: docker: io: ls --color 2026-03-23 18:18:10 +02:00
coderiaser
025b005e12 feature: docker: io: add PS1 2026-03-23 18:16:38 +02:00
coderiaser
2d524a4974 chore: cloudcmd: v19.8.9 2026-03-23 15:46:53 +02:00
coderiaser
5e0b681d8b chore: docker: lint 2026-03-23 15:46:11 +02:00
coderiaser
b052cf220d fix: cloudcmd: no time available: --.--.---- -> --:--:-- (#461) 2026-03-23 15:46:00 +02:00
coderiaser
4fa92f9394 chore: cloudcmd: v19.8.8 2026-03-23 12:23:24 +02:00
coderiaser
02dbe56d79 feature: server: user-menu: when error send it 2026-03-23 12:20:31 +02:00
coderiaser
e616cc0bc9 chore: cloudcmd: v19.8.7 2026-03-23 12:13:18 +02:00
coderiaser
ecc76e8b1e feature: docker: io: renamify-cli, runny, redfork 2026-03-23 12:12:28 +02:00
coderiaser
0fbfa0f0cf chore: cloudcmd: v19.8.6 2026-03-23 01:49:08 +02:00
coderiaser
53c072abe4 fix: @putout/plugin-cloudcmd: devDependencies -> dependnecies 2026-03-23 01:48:46 +02:00
coderiaser
4b9922bf92 feature: docker: /usr/src: app -> cloudcmd 2026-03-23 01:43:05 +02:00
coderiaser
1bb77992b0 chore: cloudcmd: v19.8.5 2026-03-23 01:39:37 +02:00
coderiaser
bec991d941 chore: lint 2026-03-23 01:39:15 +02:00
coderiaser
56fc8b838a fix: docker: gritty 2026-03-23 01:31:58 +02:00
coderiaser
df21e81d5a chore: docker: lint 2026-03-23 00:52:54 +02:00
coderiaser
8b83277ec0 chore: cloudcmd: v19.8.4 2026-03-23 00:30:04 +02:00
coderiaser
660f57e914 chore: actions: docker: set-output -> GITHUB_OUTPUT (https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/) 2026-03-23 00:30:02 +02:00
coderiaser
151c56f9a3 feature: Dockerfile: simplify 2026-03-23 00:19:55 +02:00
coderiaser
9e529605e1 feature: docker: vim nvim 2026-03-22 23:22:01 +02:00
coderiaser
ca97c21e9c chore: cloudcmd: v19.8.3 2026-03-22 22:25:32 +02:00
coderiaser
01677e6a09 fix: docker: io: slim -> io 2026-03-22 22:24:44 +02:00
coderiaser
7e35c60677 feature: docker: io: curl wget 2026-03-22 22:19:21 +02:00
coderiaser
a20640ed75 chore: cloudcmd: v19.8.2 2026-03-22 16:02:19 +02:00
coderaiser
e5b221f7ac feature: docker: io: add 2026-03-22 13:59:47 +00:00
coderiaser
2396000a6a chore: cloudcmd: v19.8.1 2026-03-22 02:04:27 +02:00
coderiaser
7661f69f1a test: cloudcmd: coverage 2026-03-22 02:04:27 +02:00
coderaiser
708a4c6b99 feature: docker: slim: add 2026-03-21 23:38:56 +00:00
coderaiser
84f3a3dc79 chore: cloudcmd: actions: lint ☘️ 2026-03-21 22:16:01 +00:00
coderaiser
80613f46fa feature: docker: slim: add 2026-03-21 22:14:53 +00:00
coderaiser
e9a8910c9c chore: cloudcmd: actions: lint ☘️ 2026-03-20 15:56:30 +00:00
coderiaser
e78f5d943f chore: cloudcmd: v19.8.0 2026-03-20 17:55:27 +02:00
coderiaser
10934b3ad9 feature: cloudcmd: add ability to show modification time (#230) 2026-03-20 17:54:58 +02:00
coderaiser
ddf5a59f70 chore: cloudcmd: actions: lint ☘️ 2026-03-20 14:55:06 +00:00
coderiaser
59037f2c18 fix: cloudcmd: bin: --show-config 2026-03-20 16:53:57 +02:00
coderiaser
1444550865 chore: cloudcmd: v19.7.1 2026-03-18 12:46:21 +02:00
coderiaser
b0c1d36c81 feature: cloudcmd: @cloudcmd/fileop v9.0.7 (#460) 2026-03-18 12:45:30 +02:00
coderaiser
10b225a337 chore: cloudcmd: actions: lint ☘️ 2026-03-17 19:12:28 +00:00
coderiaser
289f67e0d3 chore: cloudcmd: v19.7.0 2026-03-17 21:11:22 +02:00
coderiaser
daf8387516 feature: cloudfunc: override date format (#459) 2026-03-17 21:10:56 +02:00
coderaiser
170b4da211 chore: cloudcmd: actions: lint ☘️ 2026-03-17 18:45:13 +00:00
coderiaser
c9b27bb514 chore: cloudcmd: v19.6.9 2026-03-17 20:44:05 +02:00
coderiaser
5c19ddba61 chore: lint 2026-03-17 20:43:43 +02:00
coderiaser
b28a070a28 feature: cloudcmd: redzip v4.6.1 2026-03-17 20:41:28 +02:00
coderiaser
43c5a01102 feature: cloudcmd: css-minimizer-webpack-plugin v8.0.0 2026-03-17 20:41:21 +02:00
coderiaser
15dcae5c5e feature: cloudcmd: webpack-cli v7.0.2 2026-03-17 20:41:15 +02:00
coderiaser
5976da81df feature: cloudcmd: @cloudcmd/fileop v9.0.5 2026-02-28 15:50:32 +02:00
coderiaser
37cb83f2cf feature: cloudcmd: redzip v4.6.0 2026-02-28 15:50:27 +02:00
coderiaser
dd5f392293 chore: cloudcmd: v19.6.8 2026-02-27 01:14:17 +02:00
coderiaser
15fab5142f feature: cloudcmd: copymitter v10.3.0 (#458) 2026-02-27 01:13:19 +02:00
coderiaser
d2801ca896 chore: cloudcmd: v19.6.7 2026-02-26 20:18:27 +02:00
coderiaser
68c7d0be3b feature: cloudcmd: onezip v7.0.0 2026-02-26 20:17:28 +02:00
coderiaser
bfbaae9ec0 chore: cloudcmd: v19.6.6 2026-02-26 19:24:05 +02:00
coderiaser
3987cc82c1 feature: cloudcmd: redzip v4.5.1 (#457) 2026-02-26 19:23:14 +02:00
coderiaser
559b7424b6 chore: cloudcmd: v19.6.5 2026-02-26 16:06:55 +02:00
coderiaser
964ae989f2 feature: cloudcmd: redzip v4.5.0 (#457) 2026-02-26 16:06:21 +02:00
coderaiser
ff4e02c210 chore: cloudcmd: actions: lint ☘️ 2026-02-25 15:04:30 +00:00
coderiaser
9ead35242a chore: lint: scan -> fix 2026-02-25 17:03:22 +02:00
coderiaser
061ab38b24 chore: madrun: simplify 2026-02-25 17:02:22 +02:00
coderiaser
07bc9e2782 chore: cloudcmd: v19.6.4 2026-02-25 17:00:54 +02:00
coderiaser
a66eeda37e feature: cloudcmd: copymitter v10.2.0 (coderaiser/cloudcmd#457) 2026-02-25 16:59:19 +02:00
coderiaser
4340533acf feature: cloudcmd: c8 v11.0.0 2026-02-25 16:59:12 +02:00
coderiaser
394939e0d5 chore: cloudcmd: v19.6.3 2026-02-24 23:21:34 +02:00
coderiaser
0857711f61 feature: cloudcmd: redzip v4.2.0 (#457) 2026-02-24 23:21:27 +02:00
coderiaser
5aba36cca0 chore: cloudcmd: v19.6.2 2026-02-24 21:26:52 +02:00
coderiaser
3d2e5feda2 chore: lint 2026-02-24 21:24:15 +02:00
coderiaser
321a54dd59 feature: cloudcmd: @cloudcmd/fileop v9.0.2 (#457) 2026-02-24 21:23:33 +02:00
coderiaser
feb6eb2468 chore: cloudcmd: v19.6.1 2026-02-24 15:12:26 +02:00
coderiaser
7c5ac408e5 feature: cloudcmd: @cloudcmd/fileop v9.0.1 (#457) 2026-02-24 15:11:44 +02:00
coderiaser
37ecb3d7ac docs: readme: import: default -> named 2026-02-21 17:36:59 +02:00
coderiaser
52023c82cb chore: cloudcmd: v19.6.0 2026-02-21 17:34:43 +02:00
coderiaser
6d19bf2e14 feature: common: object.omit -> omit 2026-02-21 17:33:20 +02:00
coderiaser
d7214aba70 chore: cloudcmd: v19.5.1 2026-02-18 19:57:27 +02:00
coderiaser
6e1cf4ef52 feature: cloudcmd: supermenu v5.0.0 2026-02-18 19:56:56 +02:00
coderiaser
3aed798ff1 chore: cloudcmd: v19.5.0 2026-02-18 19:46:35 +02:00
coderaiser
957fbc6533 chore: cloudcmd: actions: lint ☘️ 2026-02-18 17:41:57 +00:00
coderiaser
b20539ef2b feature: common: entity: encode {,} 2026-02-18 19:40:55 +02:00
coderiaser
7ef134f46f feature: cloudcmd: rendy v5.0.0 2026-02-18 19:21:47 +02:00
coderiaser
cdeb40d191 chore: cloudcmd: v19.4.1 2026-02-18 14:55:46 +02:00
coderiaser
1e18d51342 feature: cloudcmd: @cloudcmd/fileop v9.0.0 2026-02-18 14:54:54 +02:00
coderiaser
8836d816d5 chore: cloudcmd: v19.4.0 2026-02-18 14:16:01 +02:00
coderiaser
ff9fcb1189 chore: lint 2026-02-18 14:15:22 +02:00
coderiaser
45cf9bafcd fix: menu: prefix (#456) 2026-02-18 14:09:30 +02:00
coderiaser
3e647290fd feature: cloudcmd: redlint v6.0.0 2026-02-18 14:04:19 +02:00
coderiaser
800ed012ba feature: cloudcmd: putout v42.0.5 2026-02-18 14:04:18 +02:00
coderiaser
525c17d4bd feature: cloudcmd: madrun v13.0.0 2026-02-18 14:04:17 +02:00
coderiaser
4424749978 feature: cloudcmd: eslint-plugin-putout v31.0.0 2026-02-18 14:04:17 +02:00
coderiaser
9fc3c389bf chore: cloudcmd: v19.3.9 2026-02-15 23:46:59 +02:00
coderiaser
9ffe3ef137 feature: cloudcmd: copymitter v10.0.0 (#457) 2026-02-15 23:44:18 +02:00
coderiaser
a9105e6797 chore: cloudcmd: v19.3.8 2026-02-15 22:35:16 +02:00
coderiaser
3438a0c6a1 chore: webpack: add css minification 2026-02-15 22:34:39 +02:00
coderaiser
e969b3c2b3 chore: cloudcmd: actions: lint ☘️ 2026-02-15 20:25:32 +00:00
coderiaser
d274a2b3db fix: spinner (#456) 2026-02-15 22:24:34 +02:00
coderiaser
5c9ae0a0de chore: cloudcmd: v19.3.7 2026-02-13 16:25:48 +02:00
coderiaser
8fd79a2792 feature: cloudcmd: win32 v8.0.0 2026-02-13 16:24:43 +02:00
coderiaser
9267f7a28d chore: cloudcmd: v19.3.6 2026-02-12 14:07:31 +02:00
coderiaser
3479c3b3f2 test: server: route: console-io -> gritty 2026-02-12 14:06:46 +02:00
coderiaser
ac94eccd90 feature: cloudcmd: konsole: named 2026-02-12 14:00:34 +02:00
coderiaser
144e4a3468 feature: cloudcmd: gritty v10.0.0 2026-02-12 14:00:34 +02:00
coderiaser
938f9e7674 feature: cloudcmd: console-io v15.0.1 2026-02-10 20:01:56 +02:00
coderiaser
c229160605 chore: cloudcmd: v19.3.5 2026-02-08 20:41:09 +02:00
coderiaser
fb40bd9cec feature: rm cssnano: has no sense for spinner, option disabled by default (https://svgo.dev/docs/plugins/convertPathData/) 2026-02-08 20:39:03 +02:00
coderiaser
76125be9f5 feature: cloudcmd: eslint v10.0.0 2026-02-07 16:51:36 +02:00
coderiaser
d0730e12d9 chore: cloudcmd: v19.3.4 2026-02-06 22:00:21 +02:00
coderiaser
66a08c7f71 feature: cloudcmd: deepword v11.0.0 2026-02-06 21:59:42 +02:00
coderiaser
f3a0d3a3fe chore: cloudcmd: v19.3.3 2026-02-05 14:22:52 +02:00
coderiaser
4a5a56f403 feature: cloudcmd: dword v16.0.0 2026-02-05 14:22:09 +02:00
coderiaser
846dd1bf22 chore: cloudcmd: v19.3.2 2026-02-04 20:52:09 +02:00
coderiaser
99d8435e9d fix: cloudcmd: exports 2026-02-04 20:51:08 +02:00
coderiaser
30f42e9495 feature: cloudcmd: restafary v13.0.1 2026-02-04 20:50:00 +02:00
coderiaser
f84ce8534e feature: cloudcmd: edward v16.0.0 2026-02-03 21:31:42 +02:00
coderiaser
a266c1452c fix: cloudcmd: default -> named 2026-02-03 20:08:58 +02:00
coderaiser
b61818fe62 chore: cloudcmd: actions: lint ☘️ 2026-02-03 14:27:37 +00:00
coderiaser
dad4cd1f57 chore: cloudcmd: v19.3.1 2026-02-03 16:23:35 +02:00
coderiaser
f5cabc7696 test: static: user-menu: compare directories 2026-02-03 16:23:21 +02:00
coderiaser
6e3ba27131 fix: Closing X in editor disappeared (#455) 2026-02-03 16:23:13 +02:00
coderaiser
e68338a17b chore: cloudcmd: actions: lint ☘️ 2026-02-03 14:16:16 +00:00
coderiaser
c7095e2570 chore: cloudcmd: v19.3.0 2026-02-03 16:11:23 +02:00
coderiaser
31570e4fae chore: current-file: typo 2026-02-03 16:11:23 +02:00
coderiaser
307583e374 chore: lint 2026-02-03 15:53:21 +02:00
coderiaser
09601047e5 chore: cssnano: back to cjs 2026-02-03 15:50:38 +02:00
coderiaser
3d19f4727a test: user-menu: coverage 2026-02-03 15:45:45 +02:00
coderiaser
4533a25c6f feature: cloudcmd: migrate to ESM 2026-02-03 15:03:49 +02:00
coderiaser
e8a81c49ea feature: client: dom: events: migrate to ESM 2026-02-03 14:19:16 +02:00
coderiaser
071141bc5a feature: client: terminal-run: migrate to ESM 2026-02-03 14:11:52 +02:00
coderiaser
1db64d7324 chore: cloudcmd: v19.2.0 2026-02-03 14:06:43 +02:00
coderiaser
bb32f7c448 feature: client: dom: migrate to ESM 2026-02-03 14:06:12 +02:00
coderiaser
457c83dba9 feature: client: migrate to ESM 2026-02-03 13:35:24 +02:00
coderiaser
f8a941bdd9 feature: client: modules: markdown: migrate to ESM 2026-02-03 13:29:12 +02:00
coderiaser
9d6cffafdc feature: client: polifyll: migrate to ESM 2026-02-03 13:27:16 +02:00
coderiaser
5b704d0684 feature: client: edit-names: migrate to ESM 2026-02-03 12:23:26 +02:00
coderiaser
2c2ca8eb39 feature: client: edit-file: migrate to ESM 2026-02-03 12:20:47 +02:00
coderiaser
c9f57c5f20 feature: client: modules: edit-file-vim: migrate to ESM 2026-02-03 01:07:24 +02:00
coderiaser
327ac9dee6 feature: client: modules: help: migrate to ESM 2026-02-03 00:58:16 +02:00
coderiaser
dc34ee8714 feature: cloudcmd: @putout/plugin-cloudcmd v5.0.0 2026-02-03 00:56:39 +02:00
coderiaser
3cd3695be6 feature: client: modules: edit-names-vim: migrate to ESM 2026-02-03 00:56:05 +02:00
coderiaser
dfcbfd632e feature: client: modules: terminal: migrate to ESM 2026-02-03 00:36:40 +02:00
coderiaser
bf50550911 chore: cloudcmd: v19.1.21 2026-02-02 22:39:21 +02:00
coderiaser
e3ad330ebc feature: client: konsole: migrate to ESM 2026-02-02 22:38:53 +02:00
coderiaser
983fd9af3d feature: client: edit: migrate to ESM 2026-02-02 22:37:02 +02:00
coderiaser
ebabad948f feature: common: entity: migrate to ESM 2026-02-02 22:23:33 +02:00
coderiaser
c3b71653bb feature: client: dom: images -> #images 2026-02-02 19:18:08 +02:00
coderiaser
8cad7514e7 feature: common: cloudfunc -> #common/cloudfunc 2026-02-02 19:16:21 +02:00
coderiaser
1f174870ab feature: client: view: migrate to ESM 2026-02-02 19:10:56 +02:00
coderiaser
7173f6cb18 feature: cloudcmd: smalltalk v5.0.0 2026-02-02 19:05:52 +02:00
coderiaser
0d7b037ac2 client: modules: command-line: migrate to ESM 2026-02-01 23:31:20 +02:00
coderiaser
dae57c3d20 chore: cloudcmd: v19.1.20 2026-01-31 22:48:38 +02:00
coderiaser
c1014c9cc0 feature: client: dom: operations: rename-current: migrate to ESM 2026-01-31 22:47:52 +02:00
coderiaser
2e486f8bed feature: cloudcmd: restafary v13.0.0 2026-01-31 22:45:48 +02:00
coderiaser
6addb29f7f feature: cloudcmd: redzip v4.0.0 2026-01-31 22:28:28 +02:00
coderiaser
c0988590a7 chore: lint 2026-01-30 21:43:39 +02:00
coderiaser
5e742c5b82 chore: cloudcmd: v19.1.19 2026-01-30 21:04:48 +02:00
coderiaser
2a0feac7e0 feature: cloudcmd: @cloudcmd/modal v4.0.0 2026-01-30 21:03:43 +02:00
coderiaser
603e232ca2 chore: cloudcmd: v19.1.18 2026-01-30 00:56:11 +02:00
coderiaser
73fa4961c0 feature: client: modules: user-menu: migrate to ESM 2026-01-30 00:55:32 +02:00
coderiaser
ebfdf8c087 feature: client: modules: operation: migrate to ESM 2026-01-29 18:52:38 +02:00
coderiaser
ad6831712b feature: client: modules: menu: migrate to ESM 2026-01-29 18:49:38 +02:00
coderiaser
9e65c52ff1 test: client: dom: index: migrate to ESM 2026-01-29 18:47:30 +02:00
coderiaser
0054cfa363 feature: client: dom: load-remote: migrate to ESM 2026-01-29 18:46:43 +02:00
coderiaser
145bc48722 chore: cloudcmd: types 2026-01-29 18:33:05 +02:00
coderiaser
e4d0ece093 feature: client: dom: rest: migrate to ESM 2026-01-29 18:31:10 +02:00
coderiaser
c704ffe47a feature: client: dom: storage: migrate to ESM 2026-01-29 18:22:12 +02:00
coderiaser
5182cb8107 feature: client: modules: upload: migrate to ESM 2026-01-29 18:18:39 +02:00
coderiaser
9543f1adb0 feature: client: dom: upload-files: migrate to ESM 2026-01-29 18:17:24 +02:00
coderiaser
21d765fb9f chore: cloudcmd: v19.1.17 2026-01-29 16:14:04 +02:00
coderiaser
f9c2831939 feature: client: dom: migrate to ESM 2026-01-29 16:13:41 +02:00
coderiaser
9d2c4e4a0d feature: client: dom: cmd: move out 2026-01-29 14:51:15 +02:00
coderiaser
5a2aa70f90 feature: client: dom: simplify require 2026-01-29 14:45:02 +02:00
coderiaser
dee50a8548 feature: client: dom: files: migrate to ESM 2026-01-29 14:27:19 +02:00
coderiaser
23c0d77042 feature: client: dom: dom-tree: migrate to ESM 2026-01-29 14:25:56 +02:00
coderiaser
cf2c641564 feature: client: directory: migrate to ESM 2026-01-29 14:25:56 +02:00
coderiaser
0eb802e7bd feature: client: dom: dialog: migrate to ESM 2026-01-29 14:18:34 +02:00
coderiaser
8223800ac6 chore: madrun: wisdom: CI 2026-01-28 23:07:39 +02:00
coderiaser
041d889970 chore: cloudcmd: v19.1.16 2026-01-28 23:05:36 +02:00
coderiaser
4c242631fa fix: css: spinner: do not minify svg 2026-01-28 23:05:08 +02:00
coderiaser
75938809ea chore: cloudcmd: v19.1.15 2026-01-28 23:01:32 +02:00
coderiaser
265c0b491a feature: client: key: vim: migrate to ESM 2026-01-28 23:00:50 +02:00
coderiaser
9ab2cec877 chore: lint 2026-01-28 22:54:29 +02:00
coderiaser
82bb338c1f test: client: key: migrate to ESM 2026-01-28 22:53:36 +02:00
coderiaser
3bc49f02f8 feature: client: set-current-by-char: migrate to ESM 2026-01-28 22:52:32 +02:00
coderiaser
4f1a797cd7 chore: cloudcmd: v19.1.14 2026-01-28 21:04:24 +02:00
coderiaser
f8a63b5a13 feature: client: key: binder: migrate to ESM 2026-01-28 21:03:53 +02:00
coderiaser
d250bf0223 test: client: get rid of mock-require 2026-01-28 20:59:38 +02:00
coderiaser
e1d2f01f57 test: client: vim: get rid of mock-require 2026-01-28 20:58:46 +02:00
coderiaser
2cc97f33f1 feature: client: cloud: migrate to ESM 2026-01-28 20:57:26 +02:00
coderiaser
b5acbafab9 chore: lint 2026-01-28 16:17:52 +02:00
coderiaser
bf1ffd0751 chore: cloudcmd: v19.1.13 2026-01-27 21:18:53 +02:00
coderiaser
41b5a96fa6 feature: client: load: migrate to ESM 2026-01-27 21:18:16 +02:00
219 changed files with 4289 additions and 2044 deletions

View file

@ -1,45 +1,31 @@
'use strict'; export default {
'F2 - Rename File': renameCurrent,
module.exports = { 'L - Lint': run('npm run lint'),
'F2 - Rename file': async ({DOM}) => { 'F - Fix Lint': run('npm run fix:lint'),
await DOM.renameCurrent(); 'T - Test': run('npm run test'),
}, 'C - Coverage': run('npm run coverage'),
'L - Lint': async ({CloudCmd}) => { 'D - Build Dev': run('npm run build:client:dev'),
const {TerminalRun} = CloudCmd; 'P - Build Prod': run('npm run build:client'),
await run(TerminalRun, 'npm run lint');
},
'F - Fix Lint': async ({CloudCmd}) => {
const {TerminalRun} = CloudCmd;
await run(TerminalRun, 'npm run fix:lint');
},
'T - Test': async ({CloudCmd}) => {
const {TerminalRun} = CloudCmd;
await run(TerminalRun, 'npm run test');
},
'C - Coverage': async ({CloudCmd}) => {
const {TerminalRun} = CloudCmd;
await run(TerminalRun, 'npm run coverage');
},
'D - Build Dev': async ({CloudCmd}) => {
const {TerminalRun} = CloudCmd;
await run(TerminalRun, 'npm run build:client:dev');
CloudCmd.refresh();
},
'P - Build Prod': async ({CloudCmd}) => {
const {TerminalRun} = CloudCmd;
await run(TerminalRun, 'npm run build:client');
CloudCmd.refresh();
},
}; };
async function run(TerminalRun, command) { async function renameCurrent(DOM) {
await TerminalRun.show({ await DOM.renameCurrent();
command, }
closeMessage: 'Press any key to close Terminal',
autoClose: false, function run(command) {
}); return async ({CloudCmd, DOM}) => {
const {TerminalRun, config} = CloudCmd;
const {CurrentInfo} = DOM;
const {dirPath} = CurrentInfo;
const cwd = config('root') + dirPath;
return await TerminalRun.show({
cwd,
command,
closeMessage: 'Press any key to close Terminal',
autoClose: false,
});
};
} }

60
.github/workflows/docker-io.yml vendored Normal file
View file

@ -0,0 +1,60 @@
name: Docker IO
permissions:
contents: write
on:
- push
jobs:
buildx:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v5
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Use Node.js 24.x
uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install Redrun
run: bun i redrun -g --no-save
- name: NPM Install
run: bun i --no-save
- name: Lint
run: redrun lint
- name: Build
id: build
run: |
redrun build
VERSION=$(grep '"version":' package.json -m1 | cut -d\" -f4)
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to DockerHub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push io-image
uses: docker/build-push-action@v7
with:
context: .
file: docker/Dockerfile.io
platforms: linux/amd64,linux/arm64
push: true
tags: |
coderaiser/cloudcmd:io
coderaiser/cloudcmd:${{ steps.build.outputs.version }}-io
ghcr.io/${{ github.repository }}-io
ghcr.io/${{ github.repository }}:${{ steps.build.outputs.version }}-io

View file

@ -1,4 +1,6 @@
name: Docker CI name: Docker CI
permissions:
contents: write
on: on:
push: push:
tags: tags:
@ -29,24 +31,25 @@ jobs:
id: build id: build
run: | run: |
redrun build redrun build
echo "::set-output name=version::$(grep '"version":' package.json -m1 | cut -d\" -f4)" VERSION=$(grep '"version":' package.json -m1 | cut -d\" -f4)
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v4
- name: Login to DockerHub - name: Login to DockerHub
uses: docker/login-action@v3 uses: docker/login-action@v4
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }} password: ${{ secrets.DOCKER_TOKEN }}
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v3 uses: docker/login-action@v4
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.actor }} username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push base-image - name: Build and push base-image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v7
with: with:
context: . context: .
file: docker/Dockerfile file: docker/Dockerfile
@ -58,14 +61,28 @@ jobs:
ghcr.io/${{ github.repository }}:latest ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ steps.build.outputs.version }} ghcr.io/${{ github.repository }}:${{ steps.build.outputs.version }}
- name: Build and push alpine-image - name: Build and push alpine-image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v7
with: with:
context: . context: .
file: docker/Dockerfile.alpine file: docker/Dockerfile.alpine
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
push: true push: true
tags: | tags: |
coderaiser/cloudcmd:alpine
coderaiser/cloudcmd:latest-alpine coderaiser/cloudcmd:latest-alpine
coderaiser/cloudcmd:${{ steps.build.outputs.version }}-alpine coderaiser/cloudcmd:${{ steps.build.outputs.version }}-alpine
ghcr.io/${{ github.repository }}:latest-alpine ghcr.io/${{ github.repository }}:latest-alpine
ghcr.io/${{ github.repository }}:${{ steps.build.outputs.version }}-alpine ghcr.io/${{ github.repository }}:${{ steps.build.outputs.version }}-alpine
- name: Build and push slim-image
uses: docker/build-push-action@v7
with:
context: .
file: docker/Dockerfile.slim
platforms: linux/amd64,linux/arm64
push: true
tags: |
coderaiser/cloudcmd:slim
coderaiser/cloudcmd:latest-slim
coderaiser/cloudcmd:${{ steps.build.outputs.version }}-slim
ghcr.io/${{ github.repository }}-slim
ghcr.io/${{ github.repository }}:${{ steps.build.outputs.version }}-slim

View file

@ -1,6 +1,8 @@
name: Node CI name: Node CI
on: on:
- push - push
permissions:
contents: write
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -11,7 +13,7 @@ jobs:
node-version: node-version:
- 22.x - 22.x
- 24.x - 24.x
- 25.x - 26.x
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: oven-sh/setup-bun@v2 - uses: oven-sh/setup-bun@v2
@ -22,26 +24,19 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
- name: Install Redrun - name: Install Redrun
run: bun i redrun -g --no-save run: bun i redrun madrun -g --no-save
- name: Install - name: Install
run: bun i --no-save run: bun i --no-save
- name: Init Madrun
run: madrun --init
- name: Lint - name: Lint
run: redrun fix:lint run: redrun fix:lint
- uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Typos Install
run: cargo install typos-cli || echo 'already installed'
- name: Typos - name: Typos
run: typos --write-changes uses: coderaiser/typos.ai@v1.1.8
with:
key: ${{ secrets.TYPOS_AI_KEY }}
- name: Commit fixes - name: Commit fixes
uses: EndBug/add-and-commit@v9 uses: EndBug/add-and-commit@v10
continue-on-error: true continue-on-error: true
with: with:
message: "chore: ${{ env.NAME }}: actions: lint ☘️" message: "chore: ${{ env.NAME }}: actions: lint ☘️"

24
.gitignore vendored
View file

@ -1,19 +1,17 @@
package-lock.json *.swp
yarn.lock *.log
yarn-error.log *.lock
node_modules
npm-debug.log*
coverage
modules/execon
modules/emitify
.nyc_output .nyc_output
*.swp
.DS_Store .DS_Store
.idea
package-lock.json
npm-debug.log*
node_modules
coverage
modules/execon
modules/emitify
dist dist
dist-dev dist-dev
.idea

View file

@ -1,47 +1,45 @@
import process from 'node:process';
import {run, cutEnv} from 'madrun'; import {run, cutEnv} from 'madrun';
import {defineEnv} from 'supertape/env';
const testEnv = { const testEnv = defineEnv({
SUPERTAPE_TIMEOUT: 7000, timeout: 7000,
}; css: true,
});
const is17 = /^v1[789]/.test(process.version); const buildEnv = {
const is20 = process.version.startsWith('v2');
// fix for ERR_OSSL_EVP_UNSUPPORTED on node v17
// flag '--openssl-legacy-provider' not supported
// on earlier version of node.js
//
// https://stackoverflow.com/a/69746937/4536327
const buildEnv = (is17 || is20) && {
NODE_OPTIONS: '--openssl-legacy-provider',
NODE_ENV: 'production', NODE_ENV: 'production',
}; };
export default { export default {
'start': () => 'node bin/cloudcmd.mjs', 'start': () => 'node bin/cloudcmd.js',
'start:dev': async () => await run('start', null, { 'start:dev': async () => await run('start', null, {
NODE_ENV: 'development', NODE_ENV: 'development',
}), }),
'build:start': () => run(['build:client', 'start']), 'build:start': () => run(['build:client', 'start']),
'build:start:dev': () => run(['build:client:dev', 'start:dev']), 'build:start:dev': () => run([
'build:client:dev',
'start:dev',
]),
'lint:all': () => run('lint:progress'), 'lint:all': () => run('lint:progress'),
'lint': () => 'putout .', 'lint': () => 'redlint fix; putout .',
'lint:progress': () => run('lint', '-f progress'), 'lint:progress': () => run('lint', '-f progress'),
'watch:lint': () => 'nodemon -w client -w server -w test -w common -w .webpack -x "putout -s"', 'watch:lint': () => 'nodemon -w client -w server -w test -w common -w .webpack -x "putout -s"',
'fresh:lint': () => run('lint', '--fresh'), 'fresh:lint': () => run('lint', '--fresh'),
'lint:fresh': () => run('lint', '--fresh'), 'lint:fresh': () => run('lint', '--fresh'),
'fix:lint': () => run('lint', '--fix'), 'fix:lint': async () => `putout --fix . && redlint fix`,
'lint:stream': () => run('lint', '-f stream'), 'lint:stream': () => run('lint', '-f stream'),
'test': () => [testEnv, `tape 'test/**/*.{js,mjs}' '{client,static,common,server}/**/*.spec.{js,mjs}' -f fail`], 'test': () => [testEnv, `tape '{test}/**/*.js' '{bin,client,static,common,server}/**/*.spec.js' -f fail`],
'test:e2e': () => `tape 'test-e2e/**/*.js'`,
'test:client': () => `tape 'test/client/**/*.js'`, 'test:client': () => `tape 'test/client/**/*.js'`,
'test:server': () => `tape 'test/**/*.js' 'server/**/*.spec.js' 'common/**/*.spec.js'`, 'test:server': () => `tape 'test/**/*.js' 'server/**/*.spec.js' 'common/**/*.spec.js'`,
'wisdom': () => run(['lint:all', 'build', 'test']), 'wisdom': async () => await run(['lint:all', 'build', 'test'], null, {
'wisdom:type': () => 'bin/release.mjs', CI: 1,
}),
'wisdom:type': () => 'bin/release.js',
'coverage': async () => [testEnv, `c8 ${await cutEnv('test')}`], 'coverage': async () => [testEnv, `c8 ${await cutEnv('test')}`],
'coverage:report': () => 'c8 report --reporter=lcov', 'coverage:report': () => 'c8 report --reporter=lcov',
'report': () => 'c8 report --reporter=lcov', 'report': () => 'c8 report --reporter=lcov',
'6to5': () => [buildEnv, 'webpack --progress'], '6to5': () => [buildEnv, 'rspack build --config rspack.config.js'],
'6to5:client': () => run('6to5', '--mode production'), '6to5:client': () => run('6to5', '--mode production'),
'6to5:client:dev': async () => await run('6to5', '--mode development', { '6to5:client:dev': async () => await run('6to5', '--mode development', {
NODE_ENV: 'development', NODE_ENV: 'development',
@ -55,6 +53,7 @@ export default {
'watch:test:client': async () => `nodemon -w client -w test/client -x ${await run('test:client')}`, 'watch:test:client': async () => `nodemon -w client -w test/client -x ${await run('test:client')}`,
'watch:test:server': async () => `nodemon -w client -w test/client -x ${await run('test:server')}`, 'watch:test:server': async () => `nodemon -w client -w test/client -x ${await run('test:server')}`,
'watch:coverage': async () => [testEnv, `nodemon -w server -w test -w common -x ${await cutEnv('coverage')}`], 'watch:coverage': async () => [testEnv, `nodemon -w server -w test -w common -x ${await cutEnv('coverage')}`],
'watch:fix:lint': async () => `nodemon -w client -w server -w test -w common -x '${await run('fix:lint')}'`,
'build': async () => run('6to5:*'), 'build': async () => run('6to5:*'),
'build:dev': async () => run('build:client:dev'), 'build:dev': async () => run('build:client:dev'),
'build:client': () => run('6to5:client'), 'build:client': () => run('6to5:client'),

View file

@ -1,34 +1,29 @@
.*
*.spec.* *.spec.*
*.config.* *.config.*
*.fixture.js* *.fixture.js*
*.ai
*.cdr
*.eps
*.log
*.lock
.*
manifest.yml manifest.yml
docker
docker-compose.yml docker-compose.yml
test now.json
app.json
bower.json
deno.json
bin/release.*
img/logo/cloudcmd-hq.png
webpack.config.js
docker
test*
fixture fixture
fixture-* fixture-*
coverage coverage
css css
html html
yarn-error.log
yarn.lock
now.json
app.json
bower.json
manifest.yml
deno.json
bin/release.mjs
client client
img/logo/cloudcmd-hq.png
webpack.config.js
*.ai
*.cdr
*.eps
*.config.*

1
.nvmrc
View file

@ -1 +0,0 @@
v20.15.1

View file

@ -1,11 +1,11 @@
{ {
"check-coverage": false, "checkCoverage": false,
"all": false, "all": false,
"exclude": [ "exclude": [
"**/*.spec.js", "**/*.spec.js",
"**/fixture",
"**/*.*.js", "**/*.*.js",
"**/*.config.*", "**/*.config.*",
"**/fixture",
"**/test/**" "**/test/**"
], ],
"branches": 100, "branches": 100,

View file

@ -1,11 +1,11 @@
{ {
"plugins": ["cloudcmd"], "plugins": ["cloudcmd"],
"ignore": [ "ignore": [
"html", "*.md",
"fixture*",
"app.json", "app.json",
"fontello.json", "fontello.json",
"*.md" "html",
"fixture*"
], ],
"rules": { "rules": {
"package-json/add-type": "off" "package-json/add-type": "off"

View file

@ -1,21 +1,18 @@
import {env} from 'node:process'; import {env} from 'node:process';
import OptimizeCssAssetsPlugin from 'optimize-css-assets-webpack-plugin'; import {rspack} from '@rspack/core';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
const {CssExtractRspackPlugin} = rspack;
const isDev = env.NODE_ENV === 'development'; const isDev = env.NODE_ENV === 'development';
const clean = (a) => a.filter(Boolean); const plugins = [
new CssExtractRspackPlugin({
const plugins = clean([
new MiniCssExtractPlugin({
filename: '[name].css', filename: '[name].css',
}), }),
!isDev && new OptimizeCssAssetsPlugin(), ];
]);
const rules = [{ const rules = [{
test: /\.css$/i, test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, { use: [CssExtractRspackPlugin.loader, {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
url: true, url: true,
@ -27,8 +24,15 @@ const rules = [{
}]; }];
export default { export default {
mode: isDev ? 'development' : 'production',
plugins, plugins,
module: { module: {
rules, rules,
}, },
optimization: {
minimize: !isDev,
minimizer: [
new rspack.LightningCssMinimizerRspackPlugin(),
],
},
}; };

View file

@ -1,12 +1,15 @@
import {resolve, sep} from 'node:path'; import {resolve, sep} from 'node:path';
import {fileURLToPath} from 'node:url';
import {env} from 'node:process'; import {env} from 'node:process';
import webpack from 'webpack'; import {rspack} from '@rspack/core';
import WebpackBar from 'webpackbar';
const resolveModule = (a) => fileURLToPath(import.meta.resolve(a));
const { const {
EnvironmentPlugin, EnvironmentPlugin,
NormalModuleReplacementPlugin, NormalModuleReplacementPlugin,
} = webpack; ProvidePlugin,
} = rspack;
const modules = './modules'; const modules = './modules';
const dirModules = './client/modules'; const dirModules = './client/modules';
@ -22,27 +25,31 @@ const dist = resolve(rootDir, 'dist');
const distDev = resolve(rootDir, 'dist-dev'); const distDev = resolve(rootDir, 'dist-dev');
const devtool = isDev ? 'eval' : 'source-map'; const devtool = isDev ? 'eval' : 'source-map';
const notEmpty = (a) => a;
const clean = (array) => array.filter(notEmpty);
const noParse = (a) => a.endsWith('.spec.js'); const noParse = (a) => a.endsWith('.spec.js');
const options = {
babelrc: true,
};
const rules = clean([ // codegen.macro is a babel-macro (build-time codegen), not supported by
!isDev && { // Rspack's native SWC transform, so client/sw/sw.js (the only file that
test: /\.[mc]?js$/, // uses it) keeps going through babel-loader. Everything else uses
exclude: /node_modules/, // Rspack's built-in SWC loader, which is the main source of the speedup.
loader: 'babel-loader', const rules = [{
test: /sw\/sw\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
}, {
test: /\.[mc]?js$/,
exclude: [/node_modules/, /sw\/sw\.js$/],
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: {
syntax: 'ecmascript',
},
},
env: {
targets: 'defaults',
},
}, },
isDev && { }];
test: /\.[mc]?js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options,
},
]);
const plugins = [ const plugins = [
new NormalModuleReplacementPlugin(/^node:/, (resource) => { new NormalModuleReplacementPlugin(/^node:/, (resource) => {
@ -52,7 +59,9 @@ const plugins = [
new EnvironmentPlugin({ new EnvironmentPlugin({
NODE_ENV, NODE_ENV,
}), }),
new WebpackBar(), new ProvidePlugin({
process: 'process/browser',
}),
]; ];
const splitChunks = { const splitChunks = {
@ -74,6 +83,8 @@ const splitChunks = {
'themes/light', 'themes/light',
'columns/name-size', 'columns/name-size',
'columns/name-size-date', 'columns/name-size-date',
'columns/name-size-time',
'columns/name-size-date-time',
]; ];
return !lazyChunks.includes(chunk.name); return !lazyChunks.includes(chunk.name);
@ -94,8 +105,9 @@ export default {
'node:path': 'path', 'node:path': 'path',
}, },
fallback: { fallback: {
path: import.meta.resolve('path-browserify'), path: resolveModule('path-browserify'),
process: import.meta.resolve('process/browser'), process: resolveModule('process/browser'),
util: resolveModule('util'),
}, },
}, },
devtool, devtool,
@ -107,14 +119,15 @@ export default {
'themes/light': `${dirThemes}/light.css`, 'themes/light': `${dirThemes}/light.css`,
'columns/name-size': `${dirColumns}/name-size.css`, 'columns/name-size': `${dirColumns}/name-size.css`,
'columns/name-size-date': `${dirColumns}/name-size-date.css`, 'columns/name-size-date': `${dirColumns}/name-size-date.css`,
'columns/name-size-date-time': `${dirColumns}/name-size-date-time.css`,
'nojs': `${dirCss}/nojs.css`, 'nojs': `${dirCss}/nojs.css`,
'help': `${dirCss}/help.css`, 'help': `${dirCss}/help.css`,
'view': `${dirCss}/view.css`, 'view': `${dirCss}/view.css`,
'config': `${dirCss}/config.css`, 'config': `${dirCss}/config.css`,
'terminal': `${dirCss}/terminal.css`, 'terminal': `${dirCss}/terminal.css`,
'user-menu': `${dirCss}/user-menu.css`, 'user-menu': `${dirCss}/user-menu.css`,
'sw': `${dir}/sw/sw.mjs`, 'sw': `${dir}/sw/sw.js`,
'cloudcmd': `${dir}/cloudcmd.mjs`, 'cloudcmd': `${dir}/cloudcmd.js`,
[`${modules}/edit`]: `${dirModules}/edit.js`, [`${modules}/edit`]: `${dirModules}/edit.js`,
[`${modules}/edit-file`]: `${dirModules}/edit-file.js`, [`${modules}/edit-file`]: `${dirModules}/edit-file.js`,
[`${modules}/edit-file-vim`]: `${dirModules}/edit-file-vim.js`, [`${modules}/edit-file-vim`]: `${dirModules}/edit-file-vim.js`,
@ -124,10 +137,10 @@ export default {
[`${modules}/view`]: `${dirModules}/view/index.js`, [`${modules}/view`]: `${dirModules}/view/index.js`,
[`${modules}/help`]: `${dirModules}/help.js`, [`${modules}/help`]: `${dirModules}/help.js`,
[`${modules}/markdown`]: `${dirModules}/markdown.js`, [`${modules}/markdown`]: `${dirModules}/markdown.js`,
[`${modules}/config`]: `${dirModules}/config/index.mjs`, [`${modules}/config`]: `${dirModules}/config/index.js`,
[`${modules}/contact`]: `${dirModules}/contact.js`, [`${modules}/contact`]: `${dirModules}/contact.js`,
[`${modules}/upload`]: `${dirModules}/upload.js`, [`${modules}/upload`]: `${dirModules}/upload.js`,
[`${modules}/operation`]: `${dirModules}/operation/index.mjs`, [`${modules}/operation`]: `${dirModules}/operation/index.js`,
[`${modules}/konsole`]: `${dirModules}/konsole.js`, [`${modules}/konsole`]: `${dirModules}/konsole.js`,
[`${modules}/terminal`]: `${dirModules}/terminal.js`, [`${modules}/terminal`]: `${dirModules}/terminal.js`,
[`${modules}/terminal-run`]: `${dirModules}/terminal-run.js`, [`${modules}/terminal-run`]: `${dirModules}/terminal-run.js`,
@ -149,7 +162,7 @@ export default {
}, },
plugins, plugins,
performance: { performance: {
maxEntrypointSize: 600_000, maxEntrypointSize: 800_000,
maxAssetSize: 600_000, maxAssetSize: 600_000,
}, },
}; };

View file

@ -1,2 +1,2 @@
[files] [files]
extend-exclude= ["ChangeLog", "*.js"] extend-exclude = ["ChangeLog"]

689
ChangeLog
View file

@ -1,3 +1,686 @@
2026.06.15, v19.19.1
feature:
- 78b206e0 client: key: Ctrl + L -> Ctrl + Shift + L: Log out (#466)
- b1492885 docker: io: NPM_CONFIG_PACKAGE_LOCK=false
- 76d7bf4d docker: typos, shellcheck: add
2026.05.26, v19.19.0
feature:
- 4ee38db6 client: view: flac: add support
2026.05.26, v19.18.1
feature:
- 40ecef5e cloudcmd: ratelimit: X-Forwarded-For (#437)
2026.05.26, v19.18.0
fix:
- 161bede8 client: menu: @putout/bundle@5.5.
- 447d990f cloudcmd: server: rest: sendError
feature:
- 5d9628ce cloudcmd: rate limit: add support (#437)
- 2be395e6 cloudcmd: get rid of manifest: 401 basic auth
2026.05.17, v19.17.0
fix:
- d96f6c46 css: query: hide time on mobile
- e7c55e05 docker: io: XDG_CONFIG_HOME
feature:
- ae1ca0f8 cloudcmd: cssnano-preset-default v8.0.1
- 94d5096a style: owner, mode: improve
- 807f8346 cloudcmd: superc8 v12.6.0
- 67a95722 docker: io: cline: add
- 68eacb91 qword: add
- 4acd294b docker: io: tmux
- 05c80043 cloudcmd: @supertape/loader-css v1.0.0
- 800a6545 cloudcmd: eslint-plugin-n v18.0.1
- a985bb36 cloudcmd: supertape v13.0.0
- 4315ec61 docker: io XDG_CONFIG_HOME: /etc -> /usr/local/etc
2026.05.03, v19.16.0
feature:
- d82d0335 client: vim: rr for rename file
- acfa27cf docker: io: nvchad: add
- 14f009f8 docker: io: bash-completion: add
- c6c60146 docker: io: f4
- 9a6b8935 docker: io: GOPATH
- a9bc22ce cloudcmd: operation: rm useless checks
- 36bacfe9 cloudcmd: client: key: vim: cc, mm
- 591da25c cloudcmd: ponse v8.0.0
- 1e1b073c docker: io: /usr/src/cloudcmd -> /usr/local/share/cloudcmd
2026.04.28, v19.15.0
feature:
- 9d97343b cloudcmd: operation: rm useless checks
- 46a88cfa cloudcmd: client: key: vim: cc, mm
2026.04.28, v19.14.0
feature:
- 36a8b641 cloudcmd: ponse v8.0.0
- 1c263c18 docker: io: /usr/src/cloudcmd -> /usr/local/share/cloudcmd
- ea7b828c docker: io: ubuntu: resolute
- cd6c11ac docker: io: far2l
- c4beeec6 docker: io: gdu: add
2026.04.21, v19.13.1
feature:
- d5cd11e8 cloudcmd: montag v2.0.1
- dc94d2db docker: io: add latest git version
- 1637beee docker: io: /usr/local/src -> /usr/local/share
- b1bc4e73 Docker: io: pv
- 7c0dca60 docker: io: git: master
2026.04.15, v19.13.0
fix:
- 48693d9e docker: io: XDG_CACHE_HOME
feature:
- 4b2395c5 cloudcmd: Ctrl + L: logout
- 977a8aaa docker: io: strace: add
- 7d0098fd docker: io: XDG_CACHE_HOME=/tmp/cache
- a89e901b actions: docker: io: add
2026.04.12, v19.12.5
feature:
- 1cfc1a6f docker: io: only amd64
2026.04.12, v19.12.4
feature:
- 3c2b5658 docker: io: haskell
- d37f8cd3 docker: io: palabra: node
2026.04.12, v19.12.3
feature:
- cb6cabd4 docker: io: PALABRA_DIR
2026.04.11, v19.12.2
feature:
- 2ce11fa2 docker: io: get rid of haskell: to slow install
- aa741232 docker: io: rizin, yara
2026.04.09, v19.12.1
feature:
- 5bd03215 docker: io: add PREFIX
2026.04.09, v19.12.0
feature:
- 13b15b7b docker: io: palabra
2026.04.07, v19.11.14
feature:
- a31beab0 docker: io: rustup env
2026.04.07, v19.11.13
feature:
- 6a08479a docker: io: BUN_INSTALL
2026.04.06, v19.11.12
feature:
- 46c65554 docker: io: npm_config_cache
2026.04.06, v19.11.11
feature:
- ae2ce388 docker: io: $DENO_DIR
2026.04.06, v19.11.10
feature:
- 12ea14ac docker: io: nvm: node
2026.04.06, v19.11.9
feature:
- ea96d13f docker: io: net-tools
2026.04.06, v19.11.8
feature:
- 5c08565f docker: io: debian -> ubuntu
2026.04.05, v19.11.7
feature:
- 36cdef37 docker: io: bookworm
2026.04.05, v19.11.6
feature:
- 845f9bd1 cloudcmd: gritty v10.2.0
2026.04.05, v19.11.5
feature:
- f9c513cc docker: io: hexyl: add
2026.04.04, v19.11.4
feature:
- e7347d25 docker: io: neovim: apt -> github
2026.04.04, v19.11.3
feature:
- 9970ff76 docker: io: btop
- 4395a471 docker: io: $PATH: add $HOME/.local/bin
2026.04.04, v19.11.2
feature:
- c40ae8e4 docker: io: htop
- f463c5c5 docker: io: aptitude: add
- d1032f09 docker: io: remove unused
2026.04.04, v19.11.1
feature:
- 7787bfc2 cloudcmd: user-menu: runFromCDN
2026.04.04, v19.11.0
feature:
- 32f89d38 cloudcmd: user-menu: root
2026.04.04, v19.10.2
feature:
- df4fb517 cloudcmd: aleman v2.0.1
2026.04.03, v19.10.1
feature:
- ceb7ef4f docker: io: keep /var/lib/apt/lists
2026.04.02, v19.10.0
fix:
- d12e7bd0 distribute: fix event listener leak on socket disconnect (#462)
2026.04.02, v19.9.24
feature:
- c4d26c6a docker: io: apt-get upgrade
- 9ddb8c29 docker: io: get rid of nix
- e4d7d441 docker: io: nix
2026.04.01, v19.9.23
feature:
- 5a3413ce docker: io: nix
2026.03.31, v19.9.22
feature:
- b4345ed4 docker: io: DENO_DIR
2026.03.31, v19.9.21
fix:
- 5c6a9a95 css: columns: name: 40% -> 35%
2026.03.30, v19.9.20
feature:
- cd0b5554 iocmd: io: nvm
2026.03.30, v19.9.19
feature:
- 6a52b11e docker: io: go, rust
2026.03.30, v19.9.18
feature:
- 738059f2 docker: io: fzf
- 3fc8932f docker: io: less, el_GR
2026.03.30, v19.9.17
feature:
- cf424d6c docker: io: command-not-found update
2026.03.29, v19.9.16
feature:
- 19347a2b docker: io: add command-not-found
2026.03.29, v19.9.15
feature:
- ee170552 docker: io: ubuntu
- e04c4594 docker: io: net-tools: add
2026.03.29, v19.9.14
fix:
- 6c7709be docker: io: PS1
2026.03.29, v19.9.13
fix:
- 439b3710 bin: currify
- e4182841 docker: io: xterm-256color
2026.03.29, v19.9.12
feature:
- 811a47fd cloudcmd: bin: get rid of require
2026.03.29, v19.9.11
feature:
- 1f95f188 cloudcmd: get rid of simport
2026.03.29, v19.9.10
feature:
- f0deb323 docker: io: add ja_JP.UTF-8
2026.03.29, v19.9.9
fix:
- f671f798 docker: io: PS1 environment variable in Dockerfile
feature:
- cc7f9dc7 docker: io: use ubuntu
2026.03.28, v19.9.8
feature:
- 4d1cd8cd docker: io: ffmpeg
- 54b56fdc cloudcmd: vim: ESC: use only to enable, do not use to disable
2026.03.27, v19.9.7
feature:
- 110908e2 docker: io: apt-get
2026.03.26, v19.9.6
feature:
- 6450a2f8 docker: io: add UTF-8
2026.03.26, v19.9.5
fix:
- e761cacb columns: name-size-date-time: 20% -> 19%
2026.03.26, v19.9.4
feature:
- 69498ed6 docker: io: pull.rebase by default
2026.03.24, v19.9.3
feature:
- 8763788b docker: io: healthcheck
2026.03.23, v19.9.2
feature:
- 09a02074 docker: io: git config: add
- c448eaa4 docker: io: buni
2026.03.23, v19.9.1
fix:
- 6e5318fa client: modules: config: input: quote
2026.03.23, v19.9.0
feature:
- a1216cdd cloudcmd: add ability to hide port configuration
2026.03.23, v19.8.15
feature:
- 68b2aa78 docker: io: cloudcmd_vim
2026.03.23, v19.8.14
fix:
- 665ed9c2 docker: io: get back port
2026.03.23, v19.8.13
feature:
- 618a5615 docker: io: PS1
2026.03.23, v19.8.12
feature:
- 556b0150 docker: io: PS1
2026.03.23, v19.8.11
fix:
- 97672ef5 docker: io: apt-get install -> apt-get
feature:
- 67f27d84 docker: io: bun, deno
2026.03.23, v19.8.10
feature:
- 025b005e docker: io: add PS1
2026.03.23, v19.8.9
fix:
- b052cf22 cloudcmd: no time available: --.--.---- -> --:--:-- (#461)
2026.03.23, v19.8.8
feature:
- 02dbe56d server: user-menu: when error send it
2026.03.23, v19.8.7
feature:
- ecc76e8b docker: io: renamify-cli, runny, redfork
2026.03.23, v19.8.6
fix:
- 53c072ab @putout/plugin-cloudcmd: devDependencies -> dependnecies
feature:
- 4b9922bf docker: /usr/src: app -> cloudcmd
2026.03.23, v19.8.5
fix:
- 56fc8b83 docker: gritty
2026.03.22, v19.8.4
feature:
- 5000227e docker: vim nvim
2026.03.22, v19.8.3
fix:
- 01677e6a docker: io: slim -> io
feature:
- 7e35c606 docker: io: curl wget
2026.03.22, v19.8.2
feature:
- e5b221f7 docker: io: add
2026.03.22, v19.8.1
feature:
- 708a4c6b docker: slim: add
- 80613f46 docker: slim: add
2026.03.20, v19.8.0
fix:
- 59037f2c cloudcmd: bin: --show-config
feature:
- 10934b3a cloudcmd: add ability to show modification time (#230)
2026.03.18, v19.7.1
feature:
- b0c1d36c cloudcmd: @cloudcmd/fileop v9.0.7 (#460)
2026.03.17, v19.7.0
feature:
- daf83875 cloudfunc: override date format (#459)
2026.03.17, v19.6.9
feature:
- b28a070a cloudcmd: redzip v4.6.1
- 43c5a011 cloudcmd: css-minimizer-webpack-plugin v8.0.0
- 15dcae5c cloudcmd: webpack-cli v7.0.2
- 5976da81 cloudcmd: @cloudcmd/fileop v9.0.5
- 37cb83f2 cloudcmd: redzip v4.6.0
2026.02.27, v19.6.8
feature:
- 15fab514 cloudcmd: copymitter v10.3.0 (#458)
2026.02.26, v19.6.7
feature:
- 68c7d0be cloudcmd: onezip v7.0.0
2026.02.26, v19.6.6
feature:
- 3987cc82 cloudcmd: redzip v4.5.1 (#457)
2026.02.26, v19.6.5
feature:
- 964ae989 cloudcmd: redzip v4.5.0 (#457)
2026.02.25, v19.6.4
feature:
- a66eeda3 cloudcmd: copymitter v10.2.0 (coderaiser/cloudcmd#457)
- 4340533a cloudcmd: c8 v11.0.0
- 0857711f cloudcmd: redzip v4.2.0 (#457)
2026.02.24, v19.6.3
feature:
- 2234f1b4 cloudcmd: redzip v4.2.0 (#475)
2026.02.24, v19.6.2
feature:
- 321a54dd cloudcmd: @cloudcmd/fileop v9.0.2 (#457)
2026.02.24, v19.6.1
feature:
- 7c5ac408 cloudcmd: @cloudcmd/fileop v9.0.1 (#457)
2026.02.21, v19.6.0
feature:
- 6d19bf2e common: object.omit -> omit
2026.02.18, v19.5.1
feature:
- 6e1cf4ef cloudcmd: supermenu v5.0.0
2026.02.18, v19.5.0
feature:
- b20539ef common: entity: encode {,}
- 7ef134f4 cloudcmd: rendy v5.0.0
2026.02.18, v19.4.1
feature:
- 1e18d513 cloudcmd: @cloudcmd/fileop v9.0.0
2026.02.18, v19.4.0
fix:
- 45cf9baf menu: prefix (#456)
feature:
- 3e647290 cloudcmd: redlint v6.0.0
- 800ed012 cloudcmd: putout v42.0.5
- 525c17d4 cloudcmd: madrun v13.0.0
- 44247499 cloudcmd: eslint-plugin-putout v31.0.0
2026.02.15, v19.3.9
feature:
- 9ffe3ef1 cloudcmd: copymitter v10.0.0 (#457)
2026.02.15, v19.3.8
fix:
- d274a2b3 spinner (#456)
2026.02.13, v19.3.7
feature:
- 8fd79a27 cloudcmd: win32 v8.0.0
2026.02.12, v19.3.6
feature:
- ac94eccd cloudcmd: konsole: named
- 144e4a34 cloudcmd: gritty v10.0.0
- 938f9e76 cloudcmd: console-io v15.0.1
2026.02.08, v19.3.5
feature:
- fb40bd9c rm cssnano: has no sense for spinner, option disabled by default (https://svgo.dev/docs/plugins/convertPathData/)
- 76125be9 cloudcmd: eslint v10.0.0
2026.02.06, v19.3.4
feature:
- 66a08c7f cloudcmd: deepword v11.0.0
2026.02.05, v19.3.3
feature:
- 4a5a56f4 cloudcmd: dword v16.0.0
2026.02.04, v19.3.2
fix:
- 99d8435e cloudcmd: exports
- a266c145 cloudcmd: default -> named
- 6e3ba271 Closing X in editor disappeared (#455)
feature:
- 30f42e94 cloudcmd: restafary v13.0.1
- f84ce853 cloudcmd: edward v16.0.0
2026.02.03, v19.3.1
fix:
- 5661bc4f Closing X in editor disappeared (#455)
2026.02.03, v19.3.0
feature:
- 4533a25c cloudcmd: migrate to ESM
- e8a81c49 client: dom: events: migrate to ESM
- 071141bc client: terminal-run: migrate to ESM
2026.02.03, v19.2.0
feature:
- bb32f7c4 client: dom: migrate to ESM
- 457c83db client: migrate to ESM
- f8a941bd client: modules: markdown: migrate to ESM
- 9d6cffaf client: polifyll: migrate to ESM
- 5b704d06 client: edit-names: migrate to ESM
- 2c2ca8eb client: edit-file: migrate to ESM
- c9f57c5f client: modules: edit-file-vim: migrate to ESM
- 327ac9de client: modules: help: migrate to ESM
- dc34ee87 cloudcmd: @putout/plugin-cloudcmd v5.0.0
- 3cd3695b client: modules: edit-names-vim: migrate to ESM
- dfcbfd63 client: modules: terminal: migrate to ESM
2026.02.02, v19.1.21
feature:
- e3ad330e client: konsole: migrate to ESM
- 983fd9af client: edit: migrate to ESM
- ebabad94 common: entity: migrate to ESM
- c3b71653 client: dom: images -> #images
- 8cad7514 common: cloudfunc -> #common/cloudfunc
- 1f174870 client: view: migrate to ESM
- 7173f6cb cloudcmd: smalltalk v5.0.0
2026.01.31, v19.1.20
feature:
- c1014c9c client: dom: operations: rename-current: migrate to ESM
- 2e486f8b cloudcmd: restafary v13.0.0
- 6addb29f cloudcmd: redzip v4.0.0
2026.01.30, v19.1.19
feature:
- 2a0feac7 cloudcmd: @cloudcmd/modal v4.0.0
2026.01.30, v19.1.18
feature:
- 73fa4961 client: modules: user-menu: migrate to ESM
- ebfdf8c0 client: modules: operation: migrate to ESM
- ad683171 client: modules: menu: migrate to ESM
- 0054cfa3 client: dom: load-remote: migrate to ESM
- e4d0ece0 client: dom: rest: migrate to ESM
- c704ffe4 client: dom: storage: migrate to ESM
- 5182cb81 client: modules: upload: migrate to ESM
- 9543f1ad client: dom: upload-files: migrate to ESM
2026.01.29, v19.1.17
feature:
- f9c28319 client: dom: migrate to ESM
- 9d2c4e4a client: dom: cmd: move out
- 5a2aa70f client: dom: simplify require
- dee50a85 client: dom: files: migrate to ESM
- 23c0d770 client: dom: dom-tree: migrate to ESM
- cf2c6415 client: directory: migrate to ESM
- 0eb802e7 client: dom: dialog: migrate to ESM
2026.01.28, v19.1.16
fix:
- 4c242631 css: spinner: do not minify svg
2026.01.28, v19.1.15
feature:
- 265c0b49 client: key: vim: migrate to ESM
- 3bc49f02 client: set-current-by-char: migrate to ESM
2026.01.28, v19.1.14
feature:
- f8a63b5a client: key: binder: migrate to ESM
- 2cc97f33 client: cloud: migrate to ESM
2026.01.27, v19.1.13
feature:
- 41b5a96f client: load: migrate to ESM
2026.01.27, v19.1.12 2026.01.27, v19.1.12
feature: feature:
@ -7095,7 +7778,7 @@ with clicks on files.
- Removed allowed from cache property in config. - Removed allowed from cache property in config.
- Added ability to hide "Upload To" menu item if - Added ability to hide "Upload To" menu item if
no storage modules setted up in modules.json. no storage modules set up in modules.json.
- From now any file minifying only if last modified - From now any file minifying only if last modified
time was changed. time was changed.
@ -7301,7 +7984,7 @@ in any position in anyLoadOnLoad function.
- Added chainable to Cache object in DOM. - Added chainable to Cache object in DOM.
- Changed default ip to null so IP would be geted from - Changed default ip to null so IP would be geted from
config.json only if it setted up. config.json only if it set up.
- Fixed bug with starting node from other then projects dir. - Fixed bug with starting node from other then projects dir.
@ -7610,7 +8293,7 @@ time was possible.
- Fixed bug with undefined size on root directory of Cloud Commander. - Fixed bug with undefined size on root directory of Cloud Commander.
Now Cloud Commander writes size 0, if can't get size, and besides will Now Cloud Commander writes size 0, if can't get size, and besides will
setted b char: "0b". set b char: "0b".
- Added supporting of Russian language in directory names. - Added supporting of Russian language in directory names.

172
HELP.md
View file

@ -1,6 +1,6 @@
# Cloud Commander v19.1.12 # Cloud Commander v19.19.1
### [Main][MainURL] [Blog][BlogURL] [Support][SupportURL] [Demo][DemoURL] ### [Main][MainURL] [Blog][BlogURL] [Demo][DemoURL] [Deploy](#deploy)
[MainURL]: https://cloudcmd.io "Main" [MainURL]: https://cloudcmd.io "Main"
[BlogURL]: https://blog.cloudcmd.io "Blog" [BlogURL]: https://blog.cloudcmd.io "Blog"
@ -9,13 +9,17 @@
[DWORD]: https://github.com/cloudcmd/dword "Editor based on CodeMirror" [DWORD]: https://github.com/cloudcmd/dword "Editor based on CodeMirror"
[EDWARD]: https://github.com/cloudcmd/edward "Editor based on Ace" [EDWARD]: https://github.com/cloudcmd/edward "Editor based on Ace"
[DEEPWORD]: https://github.com/cloudcmd/deepword "Editor based on Monaco" [DEEPWORD]: https://github.com/cloudcmd/deepword "Editor based on Monaco"
[QWORD]: https://github.com/cloudcmd/qword "Editor based on CodeMirror 6"
[EDWARD_KEYS]: https://github.com/cloudcmd/edward/#hot-keys "Edward Hot keys" [EDWARD_KEYS]: https://github.com/cloudcmd/edward/#hot-keys "Edward Hot keys"
[TERMUX]: https://termux.com "Termux" [TERMUX]: https://termux.com "Termux"
[INLY]: https://github.com/coderaiser/node-inly "Extract archive" [INLY]: https://github.com/coderaiser/node-inly "Extract archive"
[DeployInstaPodsIMG]: https://img.shields.io/badge/deploy%20on-InstaPods-blue
[DeployInstaPodsURL]: https://app.instapods.com/dashboard/pods/create?app=cloudcmd&ref=cloudcmd
**Cloud Commander** is a file manager for the web. It includes a command-line console and a text editor. Cloud Commander helps you manage your server and work with files, directories and programs in a web browser from any computer, mobile or tablet. **Cloud Commander** is a file manager for the web. It includes a command-line console and a text editor. Cloud Commander helps you manage your server and work with files, directories and programs in a web browser from any computer, mobile or tablet.
![Cloud Commander](/img/logo/cloudcmd.png "Cloud Commander") ![Cloud Commander](https://cloudcmd.io/img/logo/cloudcmd.png "Cloud Commander")
## Benefits ## Benefits
@ -26,7 +30,7 @@
- Server works on **Windows**, **Linux**, **Mac OS** and **Android** (with help of [Termux][TERMUX]). - Server works on **Windows**, **Linux**, **Mac OS** and **Android** (with help of [Termux][TERMUX]).
- Can be used local or remotely. - Can be used local or remotely.
- Adapts to screen size. - Adapts to screen size.
- **3 built-in editors** with support of **syntax highlighting**: [Dword][DWORD], [Edward][EDWARD] and [Deepword][DEEPWORD]. - **3 built-in editors** with support of **syntax highlighting**: [Dword][DWORD], [Edward][EDWARD] [Deepword][DEEPWORD] and [Qword][QWORD].
- [Console](https://github.com/cloudcmd/console "Console") with support of the default OS command line. - [Console](https://github.com/cloudcmd/console "Console") with support of the default OS command line.
- Written in **JavaScript/Node.js**. - Written in **JavaScript/Node.js**.
- Built-in archives pack: **zip** and **tar.gz**. - Built-in archives pack: **zip** and **tar.gz**.
@ -88,6 +92,7 @@ Cloud Commander supports the following command-line parameters:
| `--contact` | enable contact | `--contact` | enable contact
| `--config-dialog` | enable config dialog | `--config-dialog` | enable config dialog
| `--config-auth` | enable auth change in config dialog | `--config-auth` | enable auth change in config dialog
| `--config-port` | enable port change in config dialog
| `--console` | enable console | `--console` | enable console
| `--sync-console-path` | sync console path | `--sync-console-path` | sync console path
| `--terminal` | enable terminal | `--terminal` | enable terminal
@ -118,6 +123,7 @@ Cloud Commander supports the following command-line parameters:
| `--no-confirm-move` | do not confirm move | `--no-confirm-move` | do not confirm move
| `--no-config-dialog` | disable config dialog | `--no-config-dialog` | disable config dialog
| `--no-config-auth` | disable auth change in config dialog | `--no-config-auth` | disable auth change in config dialog
| `--no-config-port` | disable port change in config dialog
| `--no-console` | disable console | `--no-console` | disable console
| `--no-sync-console-path` | do not sync console path | `--no-sync-console-path` | do not sync console path
| `--no-contact` | disable contact | `--no-contact` | disable contact
@ -189,6 +195,7 @@ Then, start the server again with `cloudcmd` and reload the page.
| `Ctrl + F3` | sort by name | `Ctrl + F3` | sort by name
| `Ctrl + F5` | sort by date | `Ctrl + F5` | sort by date
| `Ctrl + F6` | sort by size | `Ctrl + F6` | sort by size
| `Ctrl + Shift + L` | logout
| `Ctrl + Command + .` | show/hide dot files | `Ctrl + Command + .` | show/hide dot files
| `Up` | move cursor up | `Up` | move cursor up
| `Down` | move cursor down | `Down` | move cursor down
@ -211,24 +218,27 @@ Then, start the server again with `cloudcmd` and reload the page.
When the `--vim` option is provided, or the configuration parameter `vim` is set, the following hotkeys become available: When the `--vim` option is provided, or the configuration parameter `vim` is set, the following hotkeys become available:
|Key |Operation | Key |Operation
|:----------------------|:-------------------------------------------- |:------------|:--------------------------------------------
| `j` | navigate to next file | `j` | navigate to next file
| `k` | navigate to previous file | `k` | navigate to previous file
| `dd` | remove current file | `dd` | remove current file
| `G` or `$` | navigate to bottom file | `G` or `$` | navigate to bottom file
| `gg` or `^` | navigate to top file | `gg` or `^` | navigate to top file
| `v` | visual mode | `v` | visual mode
| `y` | copy (selected in visual mode files) | `y` | copy (selected in visual mode files)
| `p` | paste files | `p` | paste files
| `Esc` | unselect all | `Esc` | unselect all
| `/` | find file in current directory | `/` | find file in current directory
| `n` | navigate to next found file | `n` | navigate to next found file
| `N` | navigate to previous found file | `N` | navigate to previous found file
| `md` | make directory | `md` | make directory
| `mf` | make file | `mf` | make file
| `tt` | show terminal | `tt` | show terminal
| `e` | edit file | `e` | edit file
| `cc` | copy
| `mm` | move
| `rr` | rename file
Commands can be joined, for example: Commands can be joined, for example:
@ -440,6 +450,7 @@ Some config options can be overridden with environment variables, such as:
- `CLOUDCMD_CONTACT` - enable contact - `CLOUDCMD_CONTACT` - enable contact
- `CLOUDCMD_CONFIG_DIALOG` - enable config dialog - `CLOUDCMD_CONFIG_DIALOG` - enable config dialog
- `CLOUDCMD_CONFIG_AUTH` - enable auth change in config dialog - `CLOUDCMD_CONFIG_AUTH` - enable auth change in config dialog
- `CLOUDCMD_CONFIG_PORT` - enable port change in config dialog
- `CLOUDCMD_CONSOLE` - enable console - `CLOUDCMD_CONSOLE` - enable console
- `CLOUDCMD_SYNC_CONSOLE_PATH` - sync console path - `CLOUDCMD_SYNC_CONSOLE_PATH` - sync console path
- `CLOUDCMD_TERMINAL` - enable terminal - `CLOUDCMD_TERMINAL` - enable terminal
@ -688,7 +699,7 @@ And create `index.js`:
```js ```js
import http from 'node:http'; import http from 'node:http';
import cloudcmd from 'cloudcmd'; import {cloudcmd} from 'cloudcmd';
import {Server} from 'socket.io'; import {Server} from 'socket.io';
import express from 'express'; import express from 'express';
@ -922,9 +933,9 @@ ln -s ./sites-available/io.cloudcmd.io ./sites-enabled
## Deploy ## Deploy
`Cloud Commander` can be easily deployed to [Heroku](https://heroku.com/deploy?template=https://github.com/coderaiser/cloudcmd "Deploy to Heroku"). `Cloud Commander` can be easily deployed to [InstaPods][DeployInstaPodsURL]. After deploy you receive email with credentials.
[![Deploy to Heroku](https://www.herokucdn.com/deploy/button.png "Deploy to Heroku")](https://heroku.com/deploy?template=https://github.com/coderaiser/cloudcmd) [![Deploy on InstaPods](https://instapods.com/deploy-button.svg)](https://app.instapods.com/dashboard/pods/create?app=cloudcmd&ref=cloudcmd)
## Docker ## Docker
@ -1111,6 +1122,117 @@ There are a lot of ways to be involved in `Cloud Commander` development:
## Version history ## Version history
- *2026.06.15*, **[v19.19.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.19.1)**
- *2026.05.26*, **[v19.19.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.19.0)**
- *2026.05.26*, **[v19.18.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.18.1)**
- *2026.05.26*, **[v19.18.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.18.0)**
- *2026.05.17*, **[v19.17.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.17.0)**
- *2026.05.03*, **[v19.16.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.16.0)**
- *2026.04.28*, **[v19.15.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.15.0)**
- *2026.04.28*, **[v19.14.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.14.0)**
- *2026.04.21*, **[v19.13.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.13.1)**
- *2026.04.15*, **[v19.13.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.13.0)**
- *2026.04.12*, **[v19.12.5](//github.com/coderaiser/cloudcmd/releases/tag/v19.12.5)**
- *2026.04.12*, **[v19.12.4](//github.com/coderaiser/cloudcmd/releases/tag/v19.12.4)**
- *2026.04.12*, **[v19.12.3](//github.com/coderaiser/cloudcmd/releases/tag/v19.12.3)**
- *2026.04.11*, **[v19.12.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.12.2)**
- *2026.04.09*, **[v19.12.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.12.1)**
- *2026.04.09*, **[v19.12.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.12.0)**
- *2026.04.07*, **[v19.11.14](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.14)**
- *2026.04.07*, **[v19.11.13](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.13)**
- *2026.04.06*, **[v19.11.12](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.12)**
- *2026.04.06*, **[v19.11.11](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.11)**
- *2026.04.06*, **[v19.11.10](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.10)**
- *2026.04.06*, **[v19.11.9](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.9)**
- *2026.04.06*, **[v19.11.8](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.8)**
- *2026.04.05*, **[v19.11.7](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.7)**
- *2026.04.05*, **[v19.11.6](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.6)**
- *2026.04.05*, **[v19.11.5](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.5)**
- *2026.04.04*, **[v19.11.4](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.4)**
- *2026.04.04*, **[v19.11.3](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.3)**
- *2026.04.04*, **[v19.11.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.2)**
- *2026.04.04*, **[v19.11.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.1)**
- *2026.04.04*, **[v19.11.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.11.0)**
- *2026.04.04*, **[v19.10.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.10.2)**
- *2026.04.03*, **[v19.10.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.10.1)**
- *2026.04.02*, **[v19.10.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.10.0)**
- *2026.04.02*, **[v19.9.24](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.24)**
- *2026.04.01*, **[v19.9.23](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.23)**
- *2026.03.31*, **[v19.9.22](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.22)**
- *2026.03.31*, **[v19.9.21](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.21)**
- *2026.03.30*, **[v19.9.20](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.20)**
- *2026.03.30*, **[v19.9.19](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.19)**
- *2026.03.30*, **[v19.9.18](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.18)**
- *2026.03.30*, **[v19.9.17](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.17)**
- *2026.03.29*, **[v19.9.16](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.16)**
- *2026.03.29*, **[v19.9.15](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.15)**
- *2026.03.29*, **[v19.9.14](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.14)**
- *2026.03.29*, **[v19.9.13](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.13)**
- *2026.03.29*, **[v19.9.12](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.12)**
- *2026.03.29*, **[v19.9.11](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.11)**
- *2026.03.29*, **[v19.9.10](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.10)**
- *2026.03.29*, **[v19.9.9](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.9)**
- *2026.03.28*, **[v19.9.8](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.8)**
- *2026.03.27*, **[v19.9.7](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.7)**
- *2026.03.26*, **[v19.9.6](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.6)**
- *2026.03.26*, **[v19.9.5](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.5)**
- *2026.03.26*, **[v19.9.4](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.4)**
- *2026.03.24*, **[v19.9.3](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.3)**
- *2026.03.23*, **[v19.9.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.2)**
- *2026.03.23*, **[v19.9.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.1)**
- *2026.03.23*, **[v19.9.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.9.0)**
- *2026.03.23*, **[v19.8.15](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.15)**
- *2026.03.23*, **[v19.8.14](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.14)**
- *2026.03.23*, **[v19.8.13](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.13)**
- *2026.03.23*, **[v19.8.12](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.12)**
- *2026.03.23*, **[v19.8.11](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.11)**
- *2026.03.23*, **[v19.8.10](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.10)**
- *2026.03.23*, **[v19.8.9](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.9)**
- *2026.03.23*, **[v19.8.8](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.8)**
- *2026.03.23*, **[v19.8.7](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.7)**
- *2026.03.23*, **[v19.8.6](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.6)**
- *2026.03.23*, **[v19.8.5](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.5)**
- *2026.03.22*, **[v19.8.4](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.4)**
- *2026.03.22*, **[v19.8.3](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.3)**
- *2026.03.22*, **[v19.8.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.2)**
- *2026.03.22*, **[v19.8.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.1)**
- *2026.03.20*, **[v19.8.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.8.0)**
- *2026.03.18*, **[v19.7.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.7.1)**
- *2026.03.17*, **[v19.7.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.7.0)**
- *2026.03.17*, **[v19.6.9](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.9)**
- *2026.02.27*, **[v19.6.8](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.8)**
- *2026.02.26*, **[v19.6.7](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.7)**
- *2026.02.26*, **[v19.6.6](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.6)**
- *2026.02.26*, **[v19.6.5](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.5)**
- *2026.02.25*, **[v19.6.4](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.4)**
- *2026.02.24*, **[v19.6.3](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.3)**
- *2026.02.24*, **[v19.6.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.2)**
- *2026.02.24*, **[v19.6.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.1)**
- *2026.02.21*, **[v19.6.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.6.0)**
- *2026.02.18*, **[v19.5.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.5.1)**
- *2026.02.18*, **[v19.5.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.5.0)**
- *2026.02.18*, **[v19.4.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.4.1)**
- *2026.02.18*, **[v19.4.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.4.0)**
- *2026.02.15*, **[v19.3.9](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.9)**
- *2026.02.15*, **[v19.3.8](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.8)**
- *2026.02.13*, **[v19.3.7](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.7)**
- *2026.02.12*, **[v19.3.6](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.6)**
- *2026.02.08*, **[v19.3.5](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.5)**
- *2026.02.06*, **[v19.3.4](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.4)**
- *2026.02.05*, **[v19.3.3](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.3)**
- *2026.02.04*, **[v19.3.2](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.2)**
- *2026.02.03*, **[v19.3.1](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.1)**
- *2026.02.03*, **[v19.3.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.3.0)**
- *2026.02.03*, **[v19.2.0](//github.com/coderaiser/cloudcmd/releases/tag/v19.2.0)**
- *2026.02.02*, **[v19.1.21](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.21)**
- *2026.01.31*, **[v19.1.20](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.20)**
- *2026.01.30*, **[v19.1.19](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.19)**
- *2026.01.30*, **[v19.1.18](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.18)**
- *2026.01.29*, **[v19.1.17](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.17)**
- *2026.01.28*, **[v19.1.16](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.16)**
- *2026.01.28*, **[v19.1.15](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.15)**
- *2026.01.28*, **[v19.1.14](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.14)**
- *2026.01.27*, **[v19.1.13](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.13)**
- *2026.01.27*, **[v19.1.12](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.12)** - *2026.01.27*, **[v19.1.12](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.12)**
- *2026.01.25*, **[v19.1.11](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.11)** - *2026.01.25*, **[v19.1.11](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.11)**
- *2026.01.25*, **[v19.1.10](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.10)** - *2026.01.25*, **[v19.1.10](//github.com/coderaiser/cloudcmd/releases/tag/v19.1.10)**

View file

@ -1,4 +1,4 @@
# Cloud Commander v19.1.12 [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Codacy][CodacyIMG]][CodacyURL] [![Gitter][GitterIMGURL]][GitterURL] # Cloud Commander v19.19.1 [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Codacy][CodacyIMG]][CodacyURL] [![Gitter][GitterIMGURL]][GitterURL] [![Deploy on InstaPods][DeployInstaPodsIMG]][DeployInstaPodsURL]
### [Main][MainURL] [Blog][BlogURL] [Support][SupportURL] [Demo][DemoURL] ### [Main][MainURL] [Blog][BlogURL] [Support][SupportURL] [Demo][DemoURL]
@ -15,6 +15,8 @@
[GitterIMGURL]: https://img.shields.io/gitter/room/coderaiser/cloudcmd.js.svg [GitterIMGURL]: https://img.shields.io/gitter/room/coderaiser/cloudcmd.js.svg
[DeployURL]: https://heroku.com/deploy?template=https://github.com/coderaiser/cloudcmd "Deploy" [DeployURL]: https://heroku.com/deploy?template=https://github.com/coderaiser/cloudcmd "Deploy"
[DeployIMG]: https://www.herokucdn.com/deploy/button.png [DeployIMG]: https://www.herokucdn.com/deploy/button.png
[DeployInstaPodsIMG]: https://img.shields.io/badge/deploy%20on-InstaPods-blue
[DeployInstaPodsURL]: https://app.instapods.com/dashboard/pods/create?app=cloudcmd&ref=cloudcmd
**Cloud Commander** a file manager for the web with console and editor. **Cloud Commander** a file manager for the web with console and editor.
@ -69,7 +71,7 @@ And create `index.js`:
```js ```js
import http from 'node:http'; import http from 'node:http';
import cloudcmd from 'cloudcmd'; import {cloudcmd} from 'cloudcmd';
import {Server} from 'socket.io'; import {Server} from 'socket.io';
import express from 'express'; import express from 'express';

View file

@ -1,24 +1,21 @@
#!/usr/bin/env node #!/usr/bin/env node
import process from 'node:process'; import process from 'node:process';
import {createRequire} from 'node:module';
import {promisify} from 'node:util'; import {promisify} from 'node:util';
import {tryToCatch} from 'try-to-catch'; import {tryToCatch} from 'try-to-catch';
import {createSimport} from 'simport';
import parse from 'yargs-parser'; import parse from 'yargs-parser';
import exit from '../server/exit.js'; import exit from '../server/exit.js';
import {createConfig, configPath} from '../server/config.mjs'; import {createConfig, configPath} from '../server/config.js';
import * as env from '../server/env.mjs'; import * as env from '../server/env.js';
import prefixer from '../server/prefixer.js'; import prefixer from '../server/prefixer.js';
import * as validate from '../server/validate.mjs'; import * as validate from '../server/validate.js';
import Info from '../package.json' with {
type: 'json',
};
process.on('unhandledRejection', exit); process.on('unhandledRejection', exit);
const require = createRequire(import.meta.url);
const Info = require('../package.json');
const isUndefined = (a) => typeof a === 'undefined'; const isUndefined = (a) => typeof a === 'undefined';
const simport = createSimport(import.meta.url);
const choose = (a, b) => { const choose = (a, b) => {
if (isUndefined(a)) if (isUndefined(a))
@ -31,8 +28,6 @@ const config = createConfig({
configPath, configPath,
}); });
const DIR_SERVER = '../server/';
const maybeRoot = (a) => { const maybeRoot = (a) => {
if (a === '.') if (a === '.')
return process.cwd(); return process.cwd();
@ -78,6 +73,7 @@ const yargsOptions = {
'open', 'open',
'config-dialog', 'config-dialog',
'config-auth', 'config-auth',
'config-port',
'console', 'console',
'sync-console-path', 'sync-console-path',
'contact', 'contact',
@ -119,7 +115,7 @@ const yargsOptions = {
'columns': env.parse('columns') || config('columns') || '', 'columns': env.parse('columns') || config('columns') || '',
'theme': env.parse('theme') || config('theme') || '', 'theme': env.parse('theme') || config('theme') || '',
'vim': choose(env.bool('vim'), config('vim')), 'vim': choose(env.bool('vim'), config('vim')),
'log': config('log'), 'log': choose(env.bool('log'), config('log')),
'import-url': env.parse('import_url') || config('importUrl'), 'import-url': env.parse('import_url') || config('importUrl'),
'import-listen': choose(env.bool('import_listen'), config('importListen')), 'import-listen': choose(env.bool('import_listen'), config('importListen')),
@ -132,6 +128,7 @@ const yargsOptions = {
'sync-console-path': choose(env.bool('sync_console_path'), config('syncConsolePath')), 'sync-console-path': choose(env.bool('sync_console_path'), config('syncConsolePath')),
'config-dialog': choose(env.bool('config_dialog'), config('configDialog')), 'config-dialog': choose(env.bool('config_dialog'), config('configDialog')),
'config-auth': choose(env.bool('config_auth'), config('configAuth')), 'config-auth': choose(env.bool('config_auth'), config('configAuth')),
'config-port': choose(env.bool('config_port'), config('configPort')),
'terminal-path': env.parse('terminal_path') || config('terminalPath'), 'terminal-path': env.parse('terminal_path') || config('terminalPath'),
'terminal-command': env.parse('terminal_command') || config('terminalCommand'), 'terminal-command': env.parse('terminal_command') || config('terminalCommand'),
'terminal-auto-restart': choose(env.bool('terminal_auto_restart'), config('terminalAutoRestart')), 'terminal-auto-restart': choose(env.bool('terminal_auto_restart'), config('terminalAutoRestart')),
@ -168,7 +165,7 @@ else
main(); main();
async function main() { async function main() {
const {validateArgs} = await simport('@putout/cli-validate-args'); const {validateArgs} = await import('@putout/cli-validate-args');
const error = await validateArgs(args, [ const error = await validateArgs(args, [
...yargsOptions.boolean, ...yargsOptions.boolean,
@ -179,7 +176,7 @@ async function main() {
return exit(error); return exit(error);
if (args.repl) if (args.repl)
repl(); await repl();
validate.columns(args.columns); validate.columns(args.columns);
validate.theme(args.theme); validate.theme(args.theme);
@ -214,6 +211,7 @@ async function main() {
config('oneFilePanel', args.oneFilePanel); config('oneFilePanel', args.oneFilePanel);
config('configDialog', args.configDialog); config('configDialog', args.configDialog);
config('configAuth', args.configAuth); config('configAuth', args.configAuth);
config('configPort', args.configPort);
config('keysPanel', args.keysPanel); config('keysPanel', args.keysPanel);
config('export', args.export); config('export', args.export);
config('exportToken', args.exportToken); config('exportToken', args.exportToken);
@ -248,7 +246,7 @@ async function main() {
if (args.showConfig) if (args.showConfig)
await showConfig(); await showConfig();
const {distributeImport} = await simport('../server/distribute/import.mjs'); const {distributeImport} = await import('../server/distribute/import.js');
const importConfig = promisify(distributeImport); const importConfig = promisify(distributeImport);
await start(options, config); await start(options, config);
@ -266,11 +264,12 @@ function validateRoot(root, config) {
if (root === '/') if (root === '/')
return; return;
console.log(`root: ${root}`); if (config('log'))
console.log(`root: ${root}`);
} }
async function getPassword(password) { async function getPassword(password) {
const criton = await simport('criton'); const {default: criton} = await import('criton');
return criton(password, config('algo')); return criton(password, config('algo'));
} }
@ -279,12 +278,10 @@ function version() {
} }
async function start(options, config) { async function start(options, config) {
const SERVER = `${DIR_SERVER}server.mjs`;
if (!args.server) if (!args.server)
return; return;
const server = await simport(SERVER); const {default: server} = await import('../server/server.js');
server(options, config); server(options, config);
} }
@ -298,8 +295,8 @@ function port(arg) {
} }
async function showConfig() { async function showConfig() {
const show = await simport('../server/show-config'); const {showConfig} = await import('../server/show-config.js');
const data = show(config('*')); const data = showConfig(config('*'));
console.log(data); console.log(data);
} }
@ -308,13 +305,13 @@ async function readConfig(name) {
if (!name) if (!name)
return; return;
const tryToCatch = await simport('try-to-catch'); const {default: forEachKey} = await import('for-each-key');
const forEachKey = await simport('for-each-key');
const [error, data] = await tryToCatch(simport, name); const data = await import(name, {
with: {
if (error) type: 'json',
return exit(error.message); },
});
forEachKey(config, data); forEachKey(config, data);
} }
@ -326,8 +323,8 @@ async function help() {
}, },
}); });
const forEachKey = await simport('for-each-key'); const {default: forEachKey} = await import('for-each-key');
const currify = await simport('currify'); const {default: currify} = await import('currify');
const usage = 'Usage: cloudcmd [options]'; const usage = 'Usage: cloudcmd [options]';
const url = Info.homepage; const url = Info.homepage;
@ -339,15 +336,15 @@ async function help() {
console.log('\nGeneral help using Cloud Commander: <%s>', url); console.log('\nGeneral help using Cloud Commander: <%s>', url);
} }
function repl() { async function repl() {
console.log('REPL mode enabled (telnet localhost 1337)'); console.log('REPL mode enabled (telnet localhost 1337)');
require(`${DIR_SERVER}repl`); await import('../server/repl.js');
} }
async function checkUpdate() { async function checkUpdate() {
const load = await simport('package-json'); const {default: load} = await import('package-json');
const {version} = await load(Info.name, 'latest'); const {version} = await load(Info.name, 'latest');
await showUpdateInfo(version); await showUpdateInfo(version);
} }
@ -355,7 +352,7 @@ async function showUpdateInfo(version) {
if (version === Info.version) if (version === Info.version)
return; return;
const chalk = await simport('chalk'); const {default: chalk} = await import('chalk');
const latestVersion = chalk.green.bold(`v${version}`); const latestVersion = chalk.green.bold(`v${version}`);
const latest = `update available: ${latestVersion}`; const latest = `update available: ${latestVersion}`;

26
bin/cloudcmd.spec.js Normal file
View file

@ -0,0 +1,26 @@
import {spawnSync} from 'node:child_process';
import {test} from 'supertape';
import info from '../package.json' with {
type: 'json',
};
const cliPath = new URL('cloudcmd.js', import.meta.url).pathname;
test('cloudcmd: bin: cli: -h', (t) => {
const {stdout} = spawnSync(cliPath, ['-h'], {
encoding: 'utf8',
});
t.match(stdout, `Options`);
t.end();
});
test('cloudcmd: bin: cli: -v', (t) => {
const {version} = info;
const {stdout} = spawnSync(cliPath, ['-v'], {
encoding: 'utf8',
});
t.match(stdout, `v${version}`);
t.end();
});

View file

@ -3,26 +3,27 @@
import {promisify} from 'node:util'; import {promisify} from 'node:util';
import process from 'node:process'; import process from 'node:process';
import {tryToCatch} from 'try-to-catch'; import {tryToCatch} from 'try-to-catch';
import {createSimport} from 'simport';
import minor from 'minor'; import minor from 'minor';
import _place from 'place'; import _place from 'place';
import rendy from 'rendy'; import {rendy} from 'rendy';
import shortdate from 'shortdate'; import shortdate from 'shortdate';
import Info from '../package.json' with {
type: 'json',
};
const simport = createSimport(import.meta.url);
const place = promisify(_place); const place = promisify(_place);
const Info = await simport('../package.json');
await main(); await main();
async function main() { async function main() {
const history = '## Version history\n\n'; const history = '## Version history\n\n';
const link = '//github.com/coderaiser/cloudcmd/releases/tag/'; const link = '//github.com/coderaiser/cloudcmd/releases/tag/';
const template = '- ' + const template = '- ' +
'*{{ date }}*, ' + '*{{ date }}*, ' +
'**[v{{ version }}]' + '**[v{{ version }}]' +
'(' + link + '(' +
link +
'v{{ version }})**\n'; 'v{{ version }})**\n';
const {version} = Info; const {version} = Info;
@ -35,10 +36,11 @@ async function main() {
await replaceVersion('README.md', version, versionNew); await replaceVersion('README.md', version, versionNew);
await replaceVersion('HELP.md', version, versionNew); await replaceVersion('HELP.md', version, versionNew);
const historyNew = history + rendy(template, { const historyNew = history +
date: shortdate(), rendy(template, {
version: versionNew, date: shortdate(),
}); version: versionNew,
});
await replaceVersion('HELP.md', history, historyNew); await replaceVersion('HELP.md', history, historyNew);
} }

View file

@ -1,24 +1,22 @@
import process from 'node:process'; import process from 'node:process';
/* global DOM */
import Emitify from 'emitify'; import Emitify from 'emitify';
import inherits from 'inherits'; import inherits from 'inherits';
import rendy from 'rendy'; import {rendy} from 'rendy';
import load from 'load.js'; import load from 'load.js';
import {tryToCatch} from 'try-to-catch'; import {tryToCatch} from 'try-to-catch';
import {addSlashToEnd} from 'format-io'; import {addSlashToEnd} from 'format-io';
import pascalCase from 'just-pascal-case'; import pascalCase from 'just-pascal-case';
import currify from 'currify'; import currify from 'currify';
import * as Images from './dom/images.mjs';
import {unregisterSW} from './sw/register.mjs';
import {getJsonFromFileTable} from './get-json-from-file-table.mjs';
import {Key} from './key/index.mjs';
import { import {
apiURL, apiURL,
formatMsg, formatMsg,
buildFromJSON, buildFromJSON,
} from '../common/cloudfunc.mjs'; } from '#common/cloudfunc';
import {loadModule} from './load-module.mjs'; import * as Images from '#dom/images';
import {unregisterSW} from './sw/register.js';
import {getJsonFromFileTable} from './get-json-from-file-table.js';
import {Key} from './key/index.js';
import {loadModule} from './load-module.js';
const noJS = (a) => a.replace(/.js$/, ''); const noJS = (a) => a.replace(/.js$/, '');
@ -350,7 +348,12 @@ function CloudCmdProto({DOM, Listeners}) {
'pathLink', 'pathLink',
]; ];
const [error, [file, path, link, pathLink]] = await tryToCatch(Files.get, names); const [error, [
file,
path,
link,
pathLink,
]] = await tryToCatch(Files.get, names);
if (error) if (error)
return DOM.Dialog.alert(error.responseText); return DOM.Dialog.alert(error.responseText);

View file

@ -1,14 +1,14 @@
import '../css/main.css';
import process from 'node:process'; import process from 'node:process';
import wraptile from 'wraptile'; import wraptile from 'wraptile';
import load from 'load.js'; import load from 'load.js';
import '../css/main.css'; import * as Util from '#common/util';
import {registerSW, listenSW} from './sw/register.mjs'; import * as CloudFunc from '#common/cloudfunc';
import {initSortPanel, sortPanel} from './sort.mjs'; import DOM from '#dom';
import Util from '../common/util.js'; import {registerSW, listenSW} from './sw/register.js';
import * as CloudFunc from '../common/cloudfunc.mjs'; import {initSortPanel, sortPanel} from './sort.js';
import DOM from './dom/index.js'; import {createCloudCmd} from './client.js';
import {createCloudCmd} from './client.mjs'; import * as Listeners from './listeners/index.js';
import * as Listeners from './listeners/index.mjs';
const isDev = process.env.NODE_ENV === 'development'; const isDev = process.env.NODE_ENV === 'development';
@ -36,7 +36,7 @@ async function init(config) {
if (globalThis.CloudCmd.config('menu') === 'aleman') if (globalThis.CloudCmd.config('menu') === 'aleman')
setTimeout(() => { setTimeout(() => {
import('https://esm.sh/@putout/processor-html'); import('https://esm.sh/@putout/processor-html');
import('https://esm.sh/@putout/bundle'); import('https://esm.sh/@putout/bundle@5.5');
}, 100); }, 100);
} }

View file

@ -1,6 +1,6 @@
/* global CloudCmd*/ /* global CloudCmd*/
import * as Storage from '#dom/storage';
import tryToPromiseAll from '../../common/try-to-promise-all.js'; import tryToPromiseAll from '../../common/try-to-promise-all.js';
import Storage from './storage.js';
const CLASS = 'cut-file'; const CLASS = 'cut-file';
const COPY = 'copy'; const COPY = 'copy';

83
client/dom/cmd.js Normal file
View file

@ -0,0 +1,83 @@
/* global DOM */
const SELECTED_FILE = 'selected-file';
const Cmd = {
getSelectedFiles,
isSelected,
unselectFile,
selectFile,
selectAllFiles,
toggleSelectedFile,
toggleAllSelectedFiles,
};
/**
* selected file check
*
* @param currentFile
*/
export function isSelected(currentFile) {
if (!currentFile)
return false;
return DOM.isContainClass(currentFile, SELECTED_FILE);
}
/**
* select current file
* @param currentFile
*/
export function selectFile(currentFile) {
const current = currentFile || DOM.getCurrentFile();
current.classList.add(SELECTED_FILE);
return Cmd;
}
export function unselectFile(currentFile) {
const current = currentFile || DOM.getCurrentFile();
current.classList.remove(SELECTED_FILE);
return Cmd;
}
export function toggleSelectedFile(currentFile) {
const current = currentFile || DOM.getCurrentFile();
const name = DOM.getCurrentName(current);
if (name === '..')
return Cmd;
current.classList.toggle(SELECTED_FILE);
return Cmd;
}
export function toggleAllSelectedFiles() {
DOM
.getAllFiles()
.map(DOM.toggleSelectedFile);
return Cmd;
}
export function selectAllFiles() {
DOM
.getAllFiles()
.map(DOM.selectFile);
return Cmd;
}
/**
* unified way to get selected files
*
* @currentFile
*/
export function getSelectedFiles() {
const panel = DOM.getPanel();
const selected = DOM.getByClassAll(SELECTED_FILE, panel);
return Array.from(selected);
}

View file

@ -1,8 +1,8 @@
/* global DOM */ /* global DOM */
/* global CloudCmd */ /* global CloudCmd */
import createElement from '@cloudcmd/create-element'; import createElement from '@cloudcmd/create-element';
import {encode, decode} from '../../common/entity.js'; import {getTitle, FS} from '#common/cloudfunc';
import {getTitle, FS} from '../../common/cloudfunc.mjs'; import {encode, decode} from '#common/entity';
let Title; let Title;
@ -77,7 +77,7 @@ const parseHrefAttribute = (prefix, attribute) => {
export const _parseHrefAttribute = parseHrefAttribute; export const _parseHrefAttribute = parseHrefAttribute;
/** /**
* get current direcotory path * get current directory path
*/ */
export const getCurrentDirPath = (panel = DOM.getPanel()) => { export const getCurrentDirPath = (panel = DOM.getPanel()) => {
const path = DOM.getByDataName('js-path', panel); const path = DOM.getByDataName('js-path', panel);
@ -98,7 +98,7 @@ export const getCurrentPath = (currentFile) => {
}; };
/** /**
* get current direcotory name * get current directory name
*/ */
export const getCurrentDirName = () => { export const getCurrentDirName = () => {
const href = DOM const href = DOM
@ -111,7 +111,7 @@ export const getCurrentDirName = () => {
}; };
/** /**
* get current direcotory path * get current directory path
*/ */
export const getParentDirPath = (panel) => { export const getParentDirPath = (panel) => {
const path = DOM.getCurrentDirPath(panel); const path = DOM.getCurrentDirPath(panel);
@ -125,7 +125,7 @@ export const getParentDirPath = (panel) => {
}; };
/** /**
* get not current direcotory path * get not current directory path
*/ */
export const getNotCurrentDirPath = () => { export const getNotCurrentDirPath = () => {
const panel = DOM.getPanel({ const panel = DOM.getPanel({
@ -153,7 +153,7 @@ export const getCurrentByName = (name, panel = DOM.CurrentInfo.panel) => {
}; };
/** /**
* private function thet unset currentfile * private function that unset currentFile
* *
* @currentFile * @currentFile
*/ */
@ -302,6 +302,7 @@ export const isCurrentIsDir = (currentFile) => {
export const getCurrentType = (currentFile) => { export const getCurrentType = (currentFile) => {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
const el = DOM.getByDataName('js-type', current); const el = DOM.getByDataName('js-type', current);
const type = el.className const type = el.className
.split(' ') .split(' ')
.pop(); .pop();

View file

@ -1,7 +1,7 @@
import {test, stub} from 'supertape'; import {test, stub} from 'supertape';
import {create} from 'auto-globals'; import {create} from 'auto-globals';
import wraptile from 'wraptile'; import wraptile from 'wraptile';
import * as currentFile from './current-file.mjs'; import * as currentFile from './current-file.js';
const id = (a) => a; const id = (a) => a;
@ -19,11 +19,13 @@ test('current-file: setCurrentName: setAttribute', (t) => {
currentFile.setCurrentName('hello', current); currentFile.setCurrentName('hello', current);
t.calledWith(setAttribute, ['data-name', 'js-file-aGVsbG8='], 'should call setAttribute');
globalThis.DOM = DOM; globalThis.DOM = DOM;
globalThis.CloudCmd = CloudCmd; globalThis.CloudCmd = CloudCmd;
t.calledWith(setAttribute, [
'data-name',
'js-file-aGVsbG8=',
], 'should call setAttribute');
t.end(); t.end();
}); });
@ -38,11 +40,13 @@ test('current-file: setCurrentName: setAttribute: cyrillic', (t) => {
currentFile.setCurrentName('ай', current); currentFile.setCurrentName('ай', current);
t.calledWith(setAttribute, ['data-name', 'js-file-JUQwJUIwJUQwJUI5'], 'should call setAttribute');
globalThis.DOM = DOM; globalThis.DOM = DOM;
globalThis.CloudCmd = CloudCmd; globalThis.CloudCmd = CloudCmd;
t.calledWith(setAttribute, [
'data-name',
'js-file-JUQwJUIwJUQwJUI5',
], 'should call setAttribute');
t.end(); t.end();
}); });
@ -70,11 +74,10 @@ test('current-file: emit', (t) => {
currentFile.setCurrentName('hello', current); currentFile.setCurrentName('hello', current);
t.calledWith(emit, ['current-file', current], 'should call emit');
globalThis.DOM = DOM; globalThis.DOM = DOM;
globalThis.CloudCmd = CloudCmd; globalThis.CloudCmd = CloudCmd;
t.calledWith(emit, ['current-file', current], 'should call emit');
t.end(); t.end();
}); });
@ -90,14 +93,12 @@ test('current-file: setCurrentName: return', (t) => {
globalThis.CloudCmd = getCloudCmd(); globalThis.CloudCmd = getCloudCmd();
const current = create(); const current = create();
const result = currentFile.setCurrentName('hello', current); const result = currentFile.setCurrentName('hello', current);
t.equal(result, link, 'should return link');
globalThis.DOM = DOM; globalThis.DOM = DOM;
globalThis.CloudCmd = CloudCmd; globalThis.CloudCmd = CloudCmd;
t.equal(result, link, 'should return link');
t.end(); t.end();
}); });

View file

@ -1,26 +1,18 @@
'use strict'; import {tryToCatch} from 'try-to-catch';
import * as smalltalk from 'smalltalk';
const {tryToCatch} = require('try-to-catch');
const {
alert,
prompt,
confirm,
progress,
} = require('smalltalk');
const title = 'Cloud Commander'; const title = 'Cloud Commander';
module.exports.alert = (...a) => alert(title, ...a, { export const alert = (...a) => smalltalk.alert(title, ...a, {
cancel: false, cancel: false,
}); });
module.exports.prompt = (...a) => tryToCatch(prompt, title, ...a); export const prompt = (...a) => tryToCatch(smalltalk.prompt, title, ...a);
module.exports.confirm = (...a) => tryToCatch(confirm, title, ...a); export const confirm = (...a) => tryToCatch(smalltalk.confirm, title, ...a);
module.exports.progress = (...a) => progress(title, ...a); export const progress = (...a) => smalltalk.progress(title, ...a);
module.exports.alert.noFiles = () => { alert.noFiles = () => {
return alert(title, 'No files selected!', { return smalltalk.alert(title, 'No files selected!', {
cancel: false, cancel: false,
}); });
}; };

View file

@ -1,16 +1,10 @@
'use strict'; /* global DOM, CloudCmd */
import philip from 'philip';
import * as Dialog from '#dom/dialog';
import {FS} from '#common/cloudfunc';
import * as Images from '#dom/images';
/* global CloudCmd */ export const uploadDirectory = (items) => {
const philip = require('philip');
const Images = require('./images.mjs');
const {FS} = require('../../common/cloudfunc.mjs');
const DOM = require('.');
const Dialog = require('./dialog');
const {getCurrentDirPath: getPathWhenRootEmpty} = DOM;
module.exports = (items) => {
if (items.length) if (items.length)
Images.show('top'); Images.show('top');
@ -18,7 +12,7 @@ module.exports = (items) => {
.from(items) .from(items)
.map((item) => item.webkitGetAsEntry()); .map((item) => item.webkitGetAsEntry());
const dirPath = getPathWhenRootEmpty(); const dirPath = DOM.getCurrentDirPath();
const path = dirPath.replace(/\/$/, ''); const path = dirPath.replace(/\/$/, '');
const progress = Dialog.progress('Uploading...'); const progress = Dialog.progress('Uploading...');

View file

@ -1,8 +1,15 @@
'use strict'; import currify from 'currify';
const currify = require('currify'); const DOM = {
show,
const DOM = module.exports; hide,
getByClass,
getByClassAll,
getByDataName,
getById,
getByTag,
isContainClass,
};
/** /**
* check class of element * check class of element
@ -10,7 +17,7 @@ const DOM = module.exports;
* @param element * @param element
* @param className * @param className
*/ */
const isContainClass = (element, className) => { export function isContainClass(element, className) {
if (!element) if (!element)
throw Error('element could not be empty!'); throw Error('element could not be empty!');
@ -26,58 +33,60 @@ const isContainClass = (element, className) => {
const {classList} = element; const {classList} = element;
return classList.contains(className); return classList.contains(className);
}; }
module.exports.isContainClass = isContainClass;
/** /**
* Function search element by tag * Function search element by tag
* @param tag - className * @param tag - className
* @param element - element * @param element - element
*/ */
module.exports.getByTag = (tag, element = document) => { export function getByTag(tag, element = document) {
return element.getElementsByTagName(tag); return element.getElementsByTagName(tag);
}; }
/** /**
* Function search element by id * Function search element by id
* @param Id - id * @param id
* @param element
*/ */
module.exports.getById = (id, element = document) => { export function getById(id, element = document) {
return element.querySelector(`#${id}`); return element.querySelector(`#${id}`);
}; }
/** /**
* Function search first element by class name * Function search first element by class name
* @param className - className * @param className - className
* @param element - element * @param element - element
*/ */
module.exports.getByClass = (className, element = document) => DOM.getByClassAll(className, element)[0]; export function getByClass(className, element = document) {
return DOM.getByClassAll(className, element)[0];
}
module.exports.getByDataName = (attribute, element = document) => { export function getByDataName(attribute, element = document) {
const selector = '[' + 'data-name="' + attribute + '"]'; const selector = '[' + 'data-name="' + attribute + '"]';
return element.querySelector(selector); return element.querySelector(selector);
}; }
/** /**
* Function search element by class name * Function search element by class name
* @param pClass - className * @param className
* @param element - element * @param element
*/ */
module.exports.getByClassAll = (className, element) => { export function getByClassAll(className, element) {
return (element || document).getElementsByClassName(className); return (element || document).getElementsByClassName(className);
}; }
/** /**
* add class=hidden to element * add class=hidden to element
* *
* @param element * @param element
*/ */
module.exports.hide = (element) => { export function hide(element) {
element.classList.add('hidden'); element.classList.add('hidden');
return DOM; return DOM;
}; }
module.exports.show = (element) => { export function show(element) {
element.classList.remove('hidden'); element.classList.remove('hidden');
return DOM; return DOM;
}; }

View file

@ -1,10 +1,16 @@
'use strict'; import {test, stub} from 'supertape';
import {create} from 'auto-globals';
const test = require('supertape'); import {tryCatch} from 'try-catch';
const {create} = require('auto-globals'); import {
const {tryCatch} = require('try-catch'); isContainClass,
getByTag,
const {isContainClass} = require('./dom-tree'); getById,
getByClass,
getByDataName,
getByClassAll,
hide,
show,
} from './dom-tree.js';
test('dom: isContainClass: no element', (t) => { test('dom: isContainClass: no element', (t) => {
const [e] = tryCatch(isContainClass); const [e] = tryCatch(isContainClass);
@ -41,3 +47,106 @@ test('dom: isContainClass: contains: array', (t) => {
t.calledWith(contains, [className], 'should call contains'); t.calledWith(contains, [className], 'should call contains');
t.end(); t.end();
}); });
test('dom: getByTag', (t) => {
const getElementsByTagName = stub();
const element = {
getElementsByTagName,
};
getByTag('div', element);
t.calledWith(getElementsByTagName, ['div'], 'should call getElementsByTagName');
t.end();
});
test('dom: getById', (t) => {
const querySelector = stub();
const element = {
querySelector,
};
getById('my-id', element);
t.calledWith(querySelector, ['#my-id'], 'should call querySelector with id selector');
t.end();
});
test('dom: getByClassAll', (t) => {
const getElementsByClassName = stub();
const element = {
getElementsByClassName,
};
getByClassAll('my-class', element);
t.calledWith(getElementsByClassName, ['my-class'], 'should call getElementsByClassName');
t.end();
});
test('dom: getByClass: calls getByClassAll', (t) => {
const element = {
getElementsByClassName: stub().returns(['first']),
};
const result = getByClass('my-class', element);
t.equal(result, 'first', 'should return first element from class list');
t.end();
});
test('dom: getByDataName', (t) => {
const querySelector = stub();
const element = {
querySelector,
};
getByDataName('hello', element);
t.calledWith(querySelector, ['[data-name="hello"]'], 'should call querySelector with data-name selector');
t.end();
});
test('dom: hide', (t) => {
const add = stub();
const element = {
classList: {
add,
},
};
hide(element);
t.calledWith(add, ['hidden'], 'should add hidden class');
t.end();
});
test('dom: show', (t) => {
const remove = stub();
const element = {
classList: {
remove,
},
};
show(element);
t.calledWith(remove, ['hidden'], 'should remove hidden class');
t.end();
});
test('dom: getByClassAll: without element uses document', (t) => {
const getElementsByClassName = stub();
const prevDocument = globalThis.document;
globalThis.document = {
getElementsByClassName,
};
getByClassAll('my-class');
globalThis.document = prevDocument;
t.calledWith(getElementsByClassName, ['my-class'], 'should fallback to document when no element');
t.end();
});

View file

@ -1,8 +1,6 @@
'use strict';
let list = []; let list = [];
module.exports.add = (el, name, fn) => { export const add = (el, name, fn) => {
list.push([ list.push([
el, el,
name, name,
@ -10,8 +8,8 @@ module.exports.add = (el, name, fn) => {
]); ]);
}; };
module.exports.clear = () => { export const clear = () => {
list = []; list = [];
}; };
module.exports.get = () => list; export const get = () => list;

View file

@ -1,7 +1,5 @@
'use strict'; import {test} from 'supertape';
import * as eventStore from './event-store.js';
const test = require('supertape');
const eventStore = require('./event-store');
test('event-store: get', (t) => { test('event-store: get', (t) => {
const el = {}; const el = {};

View file

@ -1,5 +1,5 @@
import itype from 'itype'; import itype from 'itype';
import EventStore from './event-store.js'; import * as EventStore from './event-store.js';
/** /**
* safe add event listener * safe add event listener

View file

@ -1,11 +1,8 @@
'use strict';
/* global CloudCmd */ /* global CloudCmd */
const itype = require('itype'); import itype from 'itype';
const {promisify} = require('es6-promisify'); import {promisify} from 'es6-promisify';
import * as load from '#dom/load';
const load = require('./load'); import * as RESTful from '#dom/rest';
const RESTful = require('./rest');
const Promises = {}; const Promises = {};
const FILES_JSON = 'config|modules'; const FILES_JSON = 'config|modules';
@ -16,7 +13,7 @@ const DIR_HTML_FS = `${DIR_HTML}fs/`;
const DIR_JSON = '/json/'; const DIR_JSON = '/json/';
const timeout = getTimeoutOnce(2000); const timeout = getTimeoutOnce(2000);
module.exports.get = getFile; export const get = getFile;
function getFile(name) { function getFile(name) {
const type = itype(name); const type = itype(name);

View file

@ -102,13 +102,13 @@ export function show(position, panel) {
/** /**
* hide load image * hide load image
*/ */
export const hide = () => { export function hide() {
const element = Images.get(); const element = Images.get();
DOM.hide(element); DOM.hide(element);
return Images; return Images;
}; }
export const setProgress = (value, title) => { export const setProgress = (value, title) => {
const DATA = 'data-progress'; const DATA = 'data-progress';

View file

@ -1,70 +1,121 @@
'use strict';
/* global CloudCmd */ /* global CloudCmd */
const Util = require('../../common/util'); import * as load from '#dom/load';
import * as Files from '#dom/files';
import * as Dialog from '#dom/dialog';
import * as Events from '#dom/events';
import {getExt} from '#common/util';
import * as Storage from '#dom/storage';
import * as RESTful from '#dom/rest';
import * as Images from '#dom/images';
import renameCurrent from './operations/rename-current.js';
import * as CurrentFile from './current-file.js';
import * as DOMTree from './dom-tree.js';
import * as Cmd from './cmd.js';
import * as IO from './io/index.js';
import {uploadDirectory} from './directory.js';
import * as Buffer from './buffer.js';
import {loadRemote as _loadRemote} from './load-remote.js';
import {selectByPattern} from './select-by-pattern.js';
const Images = require('./images.mjs'); const {assign} = Object;
const RESTful = require('./rest');
const Storage = require('./storage');
const renameCurrent = require('./operations/rename-current');
const CurrentFile = require('./current-file.mjs');
const DOMTree = require('./dom-tree');
const Cmd = module.exports;
const DOM = { const DOM = {
getCurrentDirName,
getNotCurrentDirPath,
getParentDirPath,
loadRemote,
loadSocket,
promptNewDir,
promptNewFile,
unselectFiles,
getActiveFiles,
getCurrentDate,
getCurrentSize,
loadCurrentSize,
loadCurrentHash,
setCurrentSize,
getCurrentMode,
getCurrentOwner,
getCurrentData,
getRefreshButton,
getAllFiles,
expandSelection,
shrinkSelection,
setHistory,
getCurrentLink,
getFilenames,
checkStorageHash,
saveDataToStorage,
getFM,
getPanelPosition,
getCSSVar,
getPanel,
getFiles,
showPanel,
hidePanel,
remove,
deleteCurrent,
deleteSelected,
renameCurrent,
scrollIntoViewIfNeeded,
scrollByPages,
changePanel,
getPackerExt,
goToDirectory,
duplicatePanel,
swapPanels,
updateCurrentInfo,
};
assign(DOM, {
...DOMTree, ...DOMTree,
...CurrentFile, ...CurrentFile,
...Cmd, ...Cmd,
}; });
const CurrentInfo = {}; export const CurrentInfo = {};
DOM.Images = Images; DOM.Images = Images;
DOM.load = require('./load'); DOM.load = load;
DOM.Files = require('./files'); DOM.Files = Files;
DOM.RESTful = RESTful; DOM.RESTful = RESTful;
DOM.IO = require('./io'); DOM.IO = IO;
DOM.Storage = Storage; DOM.Storage = Storage;
DOM.Dialog = require('./dialog'); DOM.Dialog = Dialog;
DOM.CurrentInfo = CurrentInfo; DOM.CurrentInfo = CurrentInfo;
module.exports = DOM; export default DOM;
DOM.uploadDirectory = require('./directory'); DOM.uploadDirectory = uploadDirectory;
DOM.Buffer = require('./buffer.mjs'); DOM.Buffer = Buffer;
DOM.Events = require('#dom/events'); DOM.Events = Events;
const loadRemote = require('./load-remote');
const selectByPattern = require('./select-by-pattern');
const isString = (a) => typeof a === 'string'; const isString = (a) => typeof a === 'string';
const SELECTED_FILE = 'selected-file';
const TabPanel = { const TabPanel = {
'js-left': null, 'js-left': null,
'js-right': null, 'js-right': null,
}; };
module.exports.loadRemote = (name, options, callback) => { export function loadRemote(name, options, callback) {
loadRemote(name, options, callback); _loadRemote(name, options, callback);
return DOM; return DOM;
}; }
module.exports.loadSocket = (callback) => { export function loadSocket(callback) {
DOM.loadRemote('socket', { DOM.loadRemote('socket', {
name: 'io', name: 'io',
}, callback); }, callback);
return DOM; return DOM;
}; }
/** /**
* create new folder * create new folder
* *
*/ */
module.exports.promptNewDir = async function() { export async function promptNewDir() {
await promptNew('directory'); await promptNew('directory');
}; }
/** /**
* create new file * create new file
@ -72,9 +123,9 @@ module.exports.promptNewDir = async function() {
* @typeName * @typeName
* @type * @type
*/ */
module.exports.promptNewFile = async () => { export async function promptNewFile() {
await promptNew('file'); await promptNew('file');
}; }
async function promptNew(typeName) { async function promptNew(typeName) {
const {Dialog} = DOM; const {Dialog} = DOM;
@ -109,9 +160,9 @@ async function promptNew(typeName) {
} }
/** /**
* get current direcotory name * get current directory name
*/ */
module.exports.getCurrentDirName = () => { export function getCurrentDirName() {
const href = DOM const href = DOM
.getCurrentDirPath() .getCurrentDirPath()
.replace(/\/$/, ''); .replace(/\/$/, '');
@ -119,12 +170,12 @@ module.exports.getCurrentDirName = () => {
const substr = href.substr(href, href.lastIndexOf('/')); const substr = href.substr(href, href.lastIndexOf('/'));
return href.replace(`${substr}/`, '') || '/'; return href.replace(`${substr}/`, '') || '/';
}; }
/** /**
* get current direcotory path * get current directory path
*/ */
module.exports.getParentDirPath = (panel) => { export function getParentDirPath(panel) {
const path = DOM.getCurrentDirPath(panel); const path = DOM.getCurrentDirPath(panel);
const dirName = DOM.getCurrentDirName() + '/'; const dirName = DOM.getCurrentDirName() + '/';
const index = path.lastIndexOf(dirName); const index = path.lastIndexOf(dirName);
@ -133,48 +184,36 @@ module.exports.getParentDirPath = (panel) => {
return path.slice(0, index); return path.slice(0, index);
return path; return path;
}; }
/** /**
* get not current direcotory path * get not current directory path
*/ */
module.exports.getNotCurrentDirPath = () => { export function getNotCurrentDirPath() {
const panel = DOM.getPanel({ const panel = DOM.getPanel({
active: false, active: false,
}); });
return DOM.getCurrentDirPath(panel); return DOM.getCurrentDirPath(panel);
}; }
/**
* unified way to get selected files
*
* @currentFile
*/
module.exports.getSelectedFiles = () => {
const panel = DOM.getPanel();
const selected = DOM.getByClassAll(SELECTED_FILE, panel);
return Array.from(selected);
};
/* /*
* unselect all files * unselect all files
*/ */
module.exports.unselectFiles = (files) => { export function unselectFiles(files) {
files = files || DOM.getSelectedFiles(); files = files || DOM.getSelectedFiles();
Array Array
.from(files) .from(files)
.forEach(DOM.toggleSelectedFile); .forEach(DOM.toggleSelectedFile);
}; }
/** /**
* get all selected files or current when none selected * get all selected files or current when none selected
* *
* @currentFile * @currentFile
*/ */
module.exports.getActiveFiles = () => { export function getActiveFiles() {
const current = DOM.getCurrentFile(); const current = DOM.getCurrentFile();
const files = DOM.getSelectedFiles(); const files = DOM.getSelectedFiles();
const name = DOM.getCurrentName(current); const name = DOM.getCurrentName(current);
@ -183,19 +222,19 @@ module.exports.getActiveFiles = () => {
return [current]; return [current];
return files; return files;
}; }
module.exports.getCurrentDate = (currentFile) => { export function getCurrentDate(currentFile) {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
return DOM.getByDataName('js-date', current).textContent; return DOM.getByDataName('js-date', current).textContent;
}; }
/** /**
* get size * get size
* @currentFile * @currentFile
*/ */
module.exports.getCurrentSize = (currentFile) => { export function getCurrentSize(currentFile) {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
/* если это папка - возвращаем слово dir вместо размера*/ /* если это папка - возвращаем слово dir вместо размера*/
@ -205,13 +244,13 @@ module.exports.getCurrentSize = (currentFile) => {
.replace(/^<|>$/g, ''); .replace(/^<|>$/g, '');
return size; return size;
}; }
/** /**
* get size * get size
* @currentFile * @currentFile
*/ */
module.exports.loadCurrentSize = async (currentFile) => { export async function loadCurrentSize(currentFile) {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
const query = '?size'; const query = '?size';
const link = DOM.getCurrentPath(current); const link = DOM.getCurrentPath(current);
@ -227,14 +266,14 @@ module.exports.loadCurrentSize = async (currentFile) => {
Images.hide(); Images.hide();
return current; return current;
}; }
/** /**
* load hash * load hash
* @callback * @callback
* @currentFile * @currentFile
*/ */
module.exports.loadCurrentHash = async (currentFile) => { export async function loadCurrentHash(currentFile) {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
const query = '?hash'; const query = '?hash';
const link = DOM.getCurrentPath(current); const link = DOM.getCurrentPath(current);
@ -242,45 +281,45 @@ module.exports.loadCurrentHash = async (currentFile) => {
const [, data] = await RESTful.read(link + query); const [, data] = await RESTful.read(link + query);
return data; return data;
}; }
/** /**
* set size * set size
* @currentFile * @currentFile
*/ */
module.exports.setCurrentSize = (size, currentFile) => { export function setCurrentSize(size, currentFile) {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
const sizeElement = DOM.getByDataName('js-size', current); const sizeElement = DOM.getByDataName('js-size', current);
sizeElement.textContent = size; sizeElement.textContent = size;
}; }
/** /**
* @currentFile * @currentFile
*/ */
module.exports.getCurrentMode = (currentFile) => { export function getCurrentMode(currentFile) {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
const mode = DOM.getByDataName('js-mode', current); const mode = DOM.getByDataName('js-mode', current);
return mode.textContent; return mode.textContent;
}; }
/** /**
* @currentFile * @currentFile
*/ */
module.exports.getCurrentOwner = (currentFile) => { export function getCurrentOwner(currentFile) {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
const owner = DOM.getByDataName('js-owner', current); const owner = DOM.getByDataName('js-owner', current);
return owner.textContent; return owner.textContent;
}; }
/** /**
* unified way to get current file content * unified way to get current file content
* *
* @param currentFile * @param currentFile
*/ */
module.exports.getCurrentData = async (currentFile) => { export async function getCurrentData(currentFile) {
const {Dialog} = DOM; const {Dialog} = DOM;
const Info = DOM.CurrentInfo; const Info = DOM.CurrentInfo;
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
@ -322,64 +361,16 @@ module.exports.getCurrentData = async (currentFile) => {
await DOM.saveDataToStorage(path, data, hashNew); await DOM.saveDataToStorage(path, data, hashNew);
return [null, data]; return [null, data];
}; }
/** /**
* unified way to get RefreshButton * unified way to get RefreshButton
*/ */
module.exports.getRefreshButton = (panel = DOM.getPanel()) => { export function getRefreshButton(panel = DOM.getPanel()) {
return DOM.getByDataName('js-refresh', panel); return DOM.getByDataName('js-refresh', panel);
}; }
/** export function getAllFiles() {
* select current file
* @param currentFile
*/
module.exports.selectFile = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
current.classList.add(SELECTED_FILE);
return Cmd;
};
module.exports.unselectFile = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
current.classList.remove(SELECTED_FILE);
return Cmd;
};
module.exports.toggleSelectedFile = (currentFile) => {
const current = currentFile || DOM.getCurrentFile();
const name = DOM.getCurrentName(current);
if (name === '..')
return Cmd;
current.classList.toggle(SELECTED_FILE);
return Cmd;
};
module.exports.toggleAllSelectedFiles = () => {
DOM
.getAllFiles()
.map(DOM.toggleSelectedFile);
return Cmd;
};
module.exports.selectAllFiles = () => {
DOM
.getAllFiles()
.map(DOM.selectFile);
return Cmd;
};
module.exports.getAllFiles = () => {
const panel = DOM.getPanel(); const panel = DOM.getPanel();
const files = DOM.getFiles(panel); const files = DOM.getFiles(panel);
const name = DOM.getCurrentName(files[0]); const name = DOM.getCurrentName(files[0]);
@ -390,32 +381,32 @@ module.exports.getAllFiles = () => {
return Array return Array
.from(files) .from(files)
.slice(i); .slice(i);
}; }
/** /**
* open dialog with expand selection * open dialog with expand selection
*/ */
module.exports.expandSelection = () => { export async function expandSelection() {
const msg = 'expand'; const msg = 'expand';
const {files} = CurrentInfo; const {files} = CurrentInfo;
selectByPattern(msg, files); await selectByPattern(msg, files);
}; }
/** /**
* open dialog with shrink selection * open dialog with shrink selection
*/ */
module.exports.shrinkSelection = () => { export async function shrinkSelection() {
const msg = 'shrink'; const msg = 'shrink';
const {files} = CurrentInfo; const {files} = CurrentInfo;
selectByPattern(msg, files); await selectByPattern(msg, files);
}; }
/** /**
* setting history wrapper * setting history wrapper
*/ */
module.exports.setHistory = (data, title, url) => { export function setHistory(data, title, url) {
const ret = globalThis.history; const ret = globalThis.history;
const {prefix} = CloudCmd; const {prefix} = CloudCmd;
@ -425,33 +416,21 @@ module.exports.setHistory = (data, title, url) => {
history.pushState(data, title, url); history.pushState(data, title, url);
return ret; return ret;
}; }
/**
* selected file check
*
* @param currentFile
*/
module.exports.isSelected = (selected) => {
if (!selected)
return false;
return DOM.isContainClass(selected, SELECTED_FILE);
};
/** /**
* get link from current (or param) file * get link from current (or param) file
* *
* @param currentFile - current file by default * @param currentFile - current file by default
*/ */
module.exports.getCurrentLink = (currentFile) => { export function getCurrentLink(currentFile) {
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
const link = DOM.getByTag('a', current); const link = DOM.getByTag('a', current);
return link[0]; return link[0];
}; }
module.exports.getFilenames = (files) => { export function getFilenames(files) {
if (!files) if (!files)
throw Error('AllFiles could not be empty'); throw Error('AllFiles could not be empty');
@ -463,17 +442,13 @@ module.exports.getFilenames = (files) => {
if (name === '..') if (name === '..')
allFiles.shift(); allFiles.shift();
const names = allFiles.map((current) => { return allFiles.map(DOM.getCurrentName);
return DOM.getCurrentName(current); }
});
return names;
};
/** /**
* check storage hash * check storage hash
*/ */
module.exports.checkStorageHash = async (name) => { export async function checkStorageHash(name) {
const nameHash = `${name}-hash`; const nameHash = `${name}-hash`;
if (!isString(name)) if (!isString(name))
@ -485,7 +460,7 @@ module.exports.checkStorageHash = async (name) => {
]); ]);
return [loadHash, storeHash]; return [loadHash, storeHash];
}; }
/** /**
* save data to storage * save data to storage
@ -493,9 +468,8 @@ module.exports.checkStorageHash = async (name) => {
* @param name * @param name
* @param data * @param data
* @param hash * @param hash
* @param callback
*/ */
module.exports.saveDataToStorage = async (name, data, hash) => { export async function saveDataToStorage(name, data, hash) {
const isDir = DOM.isCurrentIsDir(); const isDir = DOM.isCurrentIsDir();
if (isDir) if (isDir)
@ -510,25 +484,28 @@ module.exports.saveDataToStorage = async (name, data, hash) => {
await Storage.set(nameData, data); await Storage.set(nameData, data);
return hash; return hash;
}; }
module.exports.getFM = () => DOM.getPanel().parentElement; export function getFM() {
const {parentElement} = DOM.getPanel();
return parentElement;
}
module.exports.getPanelPosition = (panel) => { export function getPanelPosition(panel) {
panel = panel || DOM.getPanel(); panel = panel || DOM.getPanel();
return panel.dataset.name.replace('js-', ''); return panel.dataset.name.replace('js-', '');
}; }
module.exports.getCSSVar = (name, {body = document.body} = {}) => { export function getCSSVar(name, {body = document.body} = {}) {
const bodyStyle = getComputedStyle(body); const bodyStyle = getComputedStyle(body);
return bodyStyle.getPropertyValue(`--${name}`); return bodyStyle.getPropertyValue(`--${name}`);
}; }
/** function getting panel active, or passive /** function getting panel active, or passive
* @param options = {active: true} * @param options = {active: true}
*/ */
module.exports.getPanel = (options) => { export function getPanel(options) {
let files; let files;
let panel; let panel;
let isLeft; let isLeft;
@ -561,17 +538,17 @@ module.exports.getPanel = (options) => {
throw Error('can not find Active Panel!'); throw Error('can not find Active Panel!');
return panel; return panel;
}; }
module.exports.getFiles = (element) => { export function getFiles(element) {
const files = DOM.getByDataName('js-files', element); const files = DOM.getByDataName('js-files', element);
return files.children || []; return files.children || [];
}; }
/** /**
* shows panel right or left (or active) * shows panel right or left (or active)
*/ */
module.exports.showPanel = (active) => { export function showPanel(active) {
const panel = DOM.getPanel({ const panel = DOM.getPanel({
active, active,
}); });
@ -582,12 +559,12 @@ module.exports.showPanel = (active) => {
DOM.show(panel); DOM.show(panel);
return true; return true;
}; }
/** /**
* hides panel right or left (or active) * hides panel right or left (or active)
*/ */
module.exports.hidePanel = (active) => { export function hidePanel(active) {
const panel = DOM.getPanel({ const panel = DOM.getPanel({
active, active,
}); });
@ -596,27 +573,27 @@ module.exports.hidePanel = (active) => {
return false; return false;
return DOM.hide(panel); return DOM.hide(panel);
}; }
/** /**
* remove child of element * remove child of element
* @param pChild * @param child
* @param element * @param element
*/ */
module.exports.remove = (child, element) => { export function remove(child, element) {
const parent = element || document.body; const parent = element || document.body;
parent.removeChild(child); parent.removeChild(child);
return DOM; return DOM;
}; }
/** /**
* remove current file from file table * remove current file from file table
* @param current * @param current
* *
*/ */
module.exports.deleteCurrent = (current) => { export function deleteCurrent(current) {
if (!current) if (!current)
DOM.getCurrentFile(); DOM.getCurrentFile();
@ -630,51 +607,44 @@ module.exports.deleteCurrent = (current) => {
DOM.setCurrentFile(next || prev); DOM.setCurrentFile(next || prev);
parent.removeChild(current); parent.removeChild(current);
} }
}; }
/** /**
* remove selected files from file table * remove selected files from file table
* @Selected * @Selected
*/ */
module.exports.deleteSelected = (selected) => { export function deleteSelected(selected) {
selected = selected || DOM.getSelectedFiles(); selected = selected || DOM.getSelectedFiles();
if (!selected) if (!selected)
return; return;
selected.map(DOM.deleteCurrent); selected.map(DOM.deleteCurrent);
}; }
/** /**
* rename current file * rename current file
* *
* @currentFile * @currentFile
*/ */
module.exports.renameCurrent = renameCurrent; export function scrollIntoViewIfNeeded(element, center = false) {
/**
* unified way to scrollIntoViewIfNeeded
* (native suporte by webkit only)
* @param element
* @param center - to scroll as small as possible param should be false
*/
module.exports.scrollIntoViewIfNeeded = (element, center = false) => {
if (!element || !element.scrollIntoViewIfNeeded) if (!element || !element.scrollIntoViewIfNeeded)
return; return;
element.scrollIntoViewIfNeeded(center); element.scrollIntoViewIfNeeded(center);
}; }
/* scroll on one page */ /* scroll on one page */
module.exports.scrollByPages = (element, pPages) => { export function scrollByPages(element, pPages) {
const ret = element?.scrollByPages && pPages; const ret = element?.scrollByPages && pPages;
if (ret) if (ret)
element.scrollByPages(pPages); element.scrollByPages(pPages);
return ret; return ret;
}; }
module.exports.changePanel = () => { export function changePanel() {
const Info = CurrentInfo; const Info = CurrentInfo;
let panel = DOM.getPanel(); let panel = DOM.getPanel();
@ -720,18 +690,21 @@ module.exports.changePanel = () => {
CloudCmd.emit('active-dir', Info.dirPath); CloudCmd.emit('active-dir', Info.dirPath);
return DOM; return DOM;
}; }
module.exports.getPackerExt = (type) => { export function getPackerExt(type) {
if (type === 'zip') if (type === 'zip')
return '.zip'; return '.zip';
return '.tar.gz'; return '.tar.gz';
}; }
module.exports.goToDirectory = async (overrides = {}) => { export async function goToDirectory(overrides = {}) {
const {Dialog} = DOM; const {Dialog} = DOM;
const {prompt = Dialog.prompt, changeDir = CloudCmd.changeDir} = overrides; const {
prompt = Dialog.prompt,
changeDir = CloudCmd.changeDir,
} = overrides;
const msg = 'Go to directory:'; const msg = 'Go to directory:';
const {dirPath} = CurrentInfo; const {dirPath} = CurrentInfo;
@ -742,9 +715,9 @@ module.exports.goToDirectory = async (overrides = {}) => {
return; return;
await changeDir(path); await changeDir(path);
}; }
module.exports.duplicatePanel = async () => { export async function duplicatePanel() {
const Info = CurrentInfo; const Info = CurrentInfo;
const {isDir} = Info; const {isDir} = Info;
const panel = Info.panelPassive; const panel = Info.panelPassive;
@ -763,9 +736,9 @@ module.exports.duplicatePanel = async () => {
panel, panel,
noCurrent, noCurrent,
}); });
}; }
module.exports.swapPanels = async () => { export async function swapPanels() {
const Info = CurrentInfo; const Info = CurrentInfo;
const { const {
panel, panel,
@ -796,11 +769,9 @@ module.exports.swapPanels = async () => {
const el = Info.files[currentIndex]; const el = Info.files[currentIndex];
DOM.setCurrentFile(el); DOM.setCurrentFile(el);
}; }
module.exports.CurrentInfo = CurrentInfo; export function updateCurrentInfo(currentFile) {
module.exports.updateCurrentInfo = (currentFile) => {
const info = DOM.CurrentInfo; const info = DOM.CurrentInfo;
const current = currentFile || DOM.getCurrentFile(); const current = currentFile || DOM.getCurrentFile();
const files = current.parentElement; const files = current.parentElement;
@ -816,7 +787,7 @@ module.exports.updateCurrentInfo = (currentFile) => {
info.dirPath = DOM.getCurrentDirPath(); info.dirPath = DOM.getCurrentDirPath();
info.parentDirPath = DOM.getParentDirPath(); info.parentDirPath = DOM.getParentDirPath();
info.element = current; info.element = current;
info.ext = Util.getExt(name); info.ext = getExt(name);
info.files = Array.from(files.children); info.files = Array.from(files.children);
info.filesPassive = Array.from(filesPassive); info.filesPassive = Array.from(filesPassive);
info.first = files.firstChild; info.first = files.firstChild;
@ -837,4 +808,4 @@ module.exports.updateCurrentInfo = (currentFile) => {
.name .name
.replace('js-', ''); .replace('js-', '');
info.isOnePanel = info.panel.getAttribute('data-name') === info.panelPassive.getAttribute('data-name'); info.isOnePanel = info.panel.getAttribute('data-name') === info.panelPassive.getAttribute('data-name');
}; }

View file

@ -1,9 +1,5 @@
'use strict'; import {test, stub} from 'supertape';
import {getCSSVar, goToDirectory} from '#dom';
require('css-modules-require-hook/preset');
const {test, stub} = require('supertape');
const {getCSSVar, goToDirectory} = require('./index');
globalThis.CloudCmd = {}; globalThis.CloudCmd = {};

View file

@ -1,24 +1,35 @@
'use strict'; import {FS} from '#common/cloudfunc';
import {sendRequest as _sendRequest} from './send-request.js';
const {FS} = require('../../../common/cloudfunc.mjs'); const {assign} = Object;
const _sendRequest = require('./send-request');
const imgPosition = { const imgPosition = {
top: true, top: true,
}; };
module.exports.delete = async (url, data) => { export const remove = async (url, data, overrides = {}) => {
return await _sendRequest({ const {
sendRequest = _sendRequest,
} = overrides;
const request = {
method: 'DELETE', method: 'DELETE',
url: FS + url, url: FS + url,
data,
imgPosition: { imgPosition: {
top: Boolean(data), top: Boolean(data),
}, },
}); };
if (data)
assign(request, {
data,
url: `${request.url}?files`,
});
return await sendRequest(request);
}; };
module.exports.patch = async (url, data) => { export const patch = async (url, data) => {
return await _sendRequest({ return await _sendRequest({
method: 'PATCH', method: 'PATCH',
url: FS + url, url: FS + url,
@ -27,7 +38,7 @@ module.exports.patch = async (url, data) => {
}); });
}; };
module.exports.write = async (url, data) => { export const write = async (url, data) => {
return await _sendRequest({ return await _sendRequest({
method: 'PUT', method: 'PUT',
url: FS + url, url: FS + url,
@ -36,7 +47,7 @@ module.exports.write = async (url, data) => {
}); });
}; };
module.exports.createDirectory = async (url, overrides = {}) => { export const createDirectory = async (url, overrides = {}) => {
const { const {
sendRequest = _sendRequest, sendRequest = _sendRequest,
} = overrides; } = overrides;
@ -48,7 +59,7 @@ module.exports.createDirectory = async (url, overrides = {}) => {
}); });
}; };
module.exports.read = async (url, dataType = 'text') => { export const read = async (url, dataType = 'text') => {
const notLog = !url.includes('?'); const notLog = !url.includes('?');
return await _sendRequest({ return await _sendRequest({
@ -59,7 +70,7 @@ module.exports.read = async (url, dataType = 'text') => {
}); });
}; };
module.exports.copy = async (from, to, names) => { export const copy = async (from, to, names) => {
return await _sendRequest({ return await _sendRequest({
method: 'PUT', method: 'PUT',
url: '/copy', url: '/copy',
@ -72,7 +83,7 @@ module.exports.copy = async (from, to, names) => {
}); });
}; };
module.exports.pack = async (data) => { export const pack = async (data) => {
return await _sendRequest({ return await _sendRequest({
method: 'PUT', method: 'PUT',
url: '/pack', url: '/pack',
@ -80,7 +91,7 @@ module.exports.pack = async (data) => {
}); });
}; };
module.exports.extract = async (data) => { export const extract = async (data) => {
return await _sendRequest({ return await _sendRequest({
method: 'PUT', method: 'PUT',
url: '/extract', url: '/extract',
@ -88,7 +99,7 @@ module.exports.extract = async (data) => {
}); });
}; };
module.exports.move = async (from, to, names) => { export const move = async (from, to, names) => {
return await _sendRequest({ return await _sendRequest({
method: 'PUT', method: 'PUT',
url: '/move', url: '/move',
@ -101,7 +112,7 @@ module.exports.move = async (from, to, names) => {
}); });
}; };
module.exports.rename = async (from, to) => { export const rename = async (from, to) => {
return await _sendRequest({ return await _sendRequest({
method: 'PUT', method: 'PUT',
url: '/rename', url: '/rename',
@ -113,7 +124,7 @@ module.exports.rename = async (from, to) => {
}); });
}; };
module.exports.Config = { export const Config = {
read: async () => { read: async () => {
return await _sendRequest({ return await _sendRequest({
method: 'GET', method: 'GET',
@ -133,7 +144,7 @@ module.exports.Config = {
}, },
}; };
module.exports.Markdown = { export const Markdown = {
read: async (url) => { read: async (url) => {
return await _sendRequest({ return await _sendRequest({
method: 'GET', method: 'GET',

View file

@ -1,7 +1,5 @@
'use strict'; import {test, stub} from 'supertape';
import * as io from './index.js';
const {test, stub} = require('supertape');
const io = require('.');
test('client: dom: io', (t) => { test('client: dom: io', (t) => {
const sendRequest = stub(); const sendRequest = stub();
@ -21,3 +19,43 @@ test('client: dom: io', (t) => {
t.calledWith(sendRequest, [expected]); t.calledWith(sendRequest, [expected]);
t.end(); t.end();
}); });
test('client: dom: io: remove: no files', async (t) => {
const sendRequest = stub();
await io.remove('/hello', null, {
sendRequest,
});
const expected = {
imgPosition: {
top: false,
},
method: 'DELETE',
url: '/fs/hello',
};
t.calledWith(sendRequest, [expected]);
t.end();
});
test('client: dom: io: remove: files', async (t) => {
const sendRequest = stub();
const files = ['world'];
await io.remove('/hello', files, {
sendRequest,
});
const expected = {
imgPosition: {
top: true,
},
data: ['world'],
method: 'DELETE',
url: '/fs/hello?files',
};
t.calledWith(sendRequest, [expected]);
t.end();
});

View file

@ -1,12 +1,9 @@
'use strict';
/* global CloudCmd */ /* global CloudCmd */
const {promisify} = require('es6-promisify'); import {promisify} from 'es6-promisify';
import * as Images from '#dom/images';
import * as load from '#dom/load';
const Images = require('../images.mjs'); export const sendRequest = promisify((params, callback) => {
const load = require('../load');
module.exports = promisify((params, callback) => {
const p = params; const p = params;
const {prefixURL} = CloudCmd; const {prefixURL} = CloudCmd;
@ -40,7 +37,8 @@ module.exports = promisify((params, callback) => {
}); });
}); });
module.exports._replaceHash = replaceHash; export const _replaceHash = replaceHash;
function replaceHash(url) { function replaceHash(url) {
/* /*
* if we send ajax request - * if we send ajax request -

View file

@ -1,7 +1,5 @@
'use strict'; import {test} from 'supertape';
import {_replaceHash} from './send-request.js';
const test = require('supertape');
const {_replaceHash} = require('./send-request');
test('cloudcmd: client: io: replaceHash', (t) => { test('cloudcmd: client: io: replaceHash', (t) => {
const url = '/hello/####world'; const url = '/hello/####world';

View file

@ -1,56 +1,58 @@
'use strict';
/* global CloudCmd */ /* global CloudCmd */
const rendy = require('rendy'); import {callbackify} from 'node:util';
const itype = require('itype'); import {rendy} from 'rendy';
const load = require('load.js'); import itype from 'itype';
const {tryToCatch} = require('try-to-catch'); import * as load from 'load.js';
import {tryToCatch} from 'try-to-catch';
import {findObjByNameInArr} from '#common/util';
import * as Files from '#dom/files';
const {findObjByNameInArr} = require('../../common/util'); export const loadRemote = callbackify(async (name, options) => {
const Files = require('./files');
module.exports = (name, options, callback = options) => {
const {prefix, config} = CloudCmd; const {prefix, config} = CloudCmd;
const o = options; const o = options;
if (o.name && window[o.name]) if (o.name && window[o.name])
return callback(); return;
Files.get('modules').then(async (modules) => { const modules = await Files.get('modules');
const online = config('online') && navigator.onLine;
const module = findObjByNameInArr(modules.remote, name); const online = config('online') && navigator.onLine;
const module = findObjByNameInArr(modules.remote, name);
const isArray = itype.array(module.local);
const {version} = module;
let remoteTmpls;
let local;
if (isArray) {
remoteTmpls = module.remote;
({local} = module);
} else {
remoteTmpls = [module.remote];
local = [module.local];
}
const localURL = [];
for (const url of local) {
localURL.push(prefix + url);
}
const remoteURL = [];
for (const tmpl of remoteTmpls) {
remoteURL.push(rendy(tmpl, {
version,
}));
}
if (online) {
const [e] = await tryToCatch(load.parallel, remoteURL);
const isArray = itype.array(module.local); if (!e)
const {version} = module; return;
}
let remoteTmpls;
let local; await load.parallel(localURL);
});
if (isArray) {
remoteTmpls = module.remote;
({local} = module);
} else {
remoteTmpls = [module.remote];
local = [module.local];
}
const localURL = local.map((url) => prefix + url);
const remoteURL = remoteTmpls.map((tmpl) => {
return rendy(tmpl, {
version,
});
});
if (online) {
const [e] = await tryToCatch(load.parallel, remoteURL);
if (!e)
return callback();
}
const [e] = await tryToCatch(load.parallel, localURL);
callback(e);
});
};

View file

@ -1,19 +1,16 @@
'use strict'; import itype from 'itype';
import jonny from 'jonny';
import Emitify from 'emitify';
import exec from 'execon';
import * as Images from '#dom/images';
const itype = require('itype');
const jonny = require('jonny');
const Emitify = require('emitify');
const exec = require('execon');
const Images = require('./images.mjs');
module.exports.getIdBySrc = getIdBySrc;
/** /**
* Function gets id by src * Function gets id by src
* @param src * @param src
* *
* Example: http://domain.com/1.js -> 1_js * Example: http://domain.com/1.js -> 1_js
*/ */
function getIdBySrc(src) { export function getIdBySrc(src) {
const isStr = itype.string(src); const isStr = itype.string(src);
if (!isStr) if (!isStr)
@ -37,7 +34,7 @@ function getIdBySrc(src) {
* *
* @param params * @param params
*/ */
module.exports.ajax = (params) => { export const ajax = (params) => {
const p = params; const p = params;
const isObject = itype.object(p.data); const isObject = itype.object(p.data);
const isArray = itype.array(p.data); const isArray = itype.array(p.data);
@ -94,11 +91,11 @@ module.exports.ajax = (params) => {
xhr.send(data); xhr.send(data);
}; };
module.exports.put = (url, body) => { export const put = (url, body) => {
const emitter = Emitify(); const emitter = Emitify();
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
url = encodeURI(url).replace(/#/g, '%23'); url = encodeURI(url).replace(/#/g, '#');
xhr.open('put', url, true); xhr.open('put', url, true);

View file

@ -1,15 +1,11 @@
'use strict';
/* global CloudCmd */ /* global CloudCmd */
const capitalize = require('just-capitalize'); import capitalize from 'just-capitalize';
import * as _Dialog from '#dom/dialog';
import * as Storage from '#dom/storage';
import * as RESTful from '#dom/rest';
import * as _currentFile from '../current-file.js';
const _Dialog = require('../dialog'); export default async (current, overrides = {}) => {
const Storage = require('../storage');
const RESTful = require('../rest');
const _currentFile = require('../current-file.mjs');
module.exports = async (current, overrides = {}) => {
const { const {
refresh = CloudCmd.refresh, refresh = CloudCmd.refresh,
Dialog = _Dialog, Dialog = _Dialog,

View file

@ -1,8 +1,5 @@
'use strict'; import {test, stub} from 'supertape';
import renameCurrent from './rename-current.js';
const {test, stub} = require('supertape');
const renameCurrent = require('./rename-current');
test('cloudcmd: client: dom: renameCurrent: isCurrentFile', async (t) => { test('cloudcmd: client: dom: renameCurrent: isCurrentFile', async (t) => {
const current = {}; const current = {};

View file

@ -1,12 +1,8 @@
'use strict'; import {tryToCatch} from 'try-to-catch';
import * as Dialog from '#dom/dialog';
const {tryToCatch} = require('try-to-catch'); import * as Images from '#dom/images';
import {encode} from '#common/entity';
const {encode} = require('../../common/entity'); import * as IO from './io/index.js';
const Images = require('./images.mjs');
const IO = require('./io');
const Dialog = require('./dialog');
const handleError = (promise) => async (...args) => { const handleError = (promise) => async (...args) => {
const [e, data] = await tryToCatch(promise, ...args); const [e, data] = await tryToCatch(promise, ...args);
@ -22,23 +18,23 @@ const handleError = (promise) => async (...args) => {
return [e, data]; return [e, data];
}; };
module.exports.delete = handleError(IO.delete); export const remove = handleError(IO.remove);
module.exports.patch = handleError(IO.patch); export const patch = handleError(IO.patch);
module.exports.write = handleError(IO.write); export const write = handleError(IO.write);
module.exports.createDirectory = handleError(IO.createDirectory); export const createDirectory = handleError(IO.createDirectory);
module.exports.read = handleError(IO.read); export const read = handleError(IO.read);
module.exports.copy = handleError(IO.copy); export const copy = handleError(IO.copy);
module.exports.pack = handleError(IO.pack); export const pack = handleError(IO.pack);
module.exports.extract = handleError(IO.extract); export const extract = handleError(IO.extract);
module.exports.move = handleError(IO.move); export const move = handleError(IO.move);
module.exports.rename = handleError(IO.rename); export const rename = handleError(IO.rename);
module.exports.Config = { export const Config = {
read: handleError(IO.Config.read), read: handleError(IO.Config.read),
write: handleError(IO.Config.write), write: handleError(IO.Config.write),
}; };
module.exports.Markdown = { export const Markdown = {
read: handleError(IO.Markdown.read), read: handleError(IO.Markdown.read),
render: handleError(IO.Markdown.render), render: handleError(IO.Markdown.render),
}; };

View file

@ -1,13 +1,14 @@
'use strict'; import {alert, prompt} from '#dom/dialog';
import {getRegExp} from '#common/util';
import {getCurrentName} from './current-file.js';
import {
isSelected,
toggleSelectedFile,
} from './cmd.js';
let SelectType = '*.*'; let SelectType = '*.*';
const {getRegExp} = require('../../common/util'); export const selectByPattern = async (msg, files) => {
const {alert, prompt} = require('./dialog');
const DOM = require('.');
module.exports = async (msg, files) => {
if (!files) if (!files)
return; return;
@ -23,21 +24,21 @@ module.exports = async (msg, files) => {
let matches = 0; let matches = 0;
for (const current of files) { for (const current of files) {
const name = DOM.getCurrentName(current); const name = getCurrentName(current);
if (name === '..' || !regExp.test(name)) if (name === '..' || !regExp.test(name))
continue; continue;
++matches; ++matches;
let isSelected = DOM.isSelected(current); let selected = isSelected(current);
const shouldSel = msg === 'expand'; const shouldSel = msg === 'expand';
if (shouldSel) if (shouldSel)
isSelected = !isSelected; selected = !selected;
if (isSelected) if (selected)
DOM.toggleSelectedFile(current); toggleSelectedFile(current);
} }
if (!matches) if (!matches)

View file

@ -1,28 +1,26 @@
'use strict';
const {parse, stringify} = JSON; const {parse, stringify} = JSON;
module.exports.set = async (name, data) => { export const set = (name, data) => {
localStorage.setItem(name, data); localStorage.setItem(name, data);
}; };
module.exports.setJson = async (name, data) => { export const setJson = (name, data) => {
localStorage.setItem(name, stringify(data)); localStorage.setItem(name, stringify(data));
}; };
module.exports.get = async (name) => { export const get = (name) => {
return localStorage.getItem(name); return localStorage.getItem(name);
}; };
module.exports.getJson = async (name) => { export const getJson = (name) => {
const data = localStorage.getItem(name); const data = localStorage.getItem(name);
return parse(data); return parse(data);
}; };
module.exports.clear = () => { export const clear = () => {
localStorage.clear(); localStorage.clear();
}; };
module.exports.remove = (item) => { export const remove = (item) => {
localStorage.removeItem(item); localStorage.removeItem(item);
}; };

View file

@ -1,8 +1,5 @@
'use strict'; import {test, stub} from 'supertape';
import * as storage from '#dom/storage';
const {test, stub} = require('supertape');
const storage = require('./storage');
const {stringify} = JSON; const {stringify} = JSON;

View file

@ -1,24 +1,19 @@
'use strict';
/* global CloudCmd */ /* global CloudCmd */
const {eachSeries} = require('execon'); import {eachSeries} from 'execon';
const wraptile = require('wraptile'); import wraptile from 'wraptile';
import * as load from '#dom/load';
import {alert} from '#dom/dialog';
import {FS} from '#common/cloudfunc';
import * as Images from '#dom/images';
import {getCurrentDirPath} from './current-file.js';
const load = require('./load');
const Images = require('./images.mjs');
const {alert} = require('./dialog');
const {FS} = require('../../common/cloudfunc.mjs');
const {getCurrentDirPath: getPathWhenRootEmpty} = require('.');
const loadFile = wraptile(_loadFile); const loadFile = wraptile(_loadFile);
const onEnd = wraptile(_onEnd); const onEnd = wraptile(_onEnd);
module.exports = (dir, files) => { export const uploadFiles = (dir, files) => {
if (!files) { if (!files) {
files = dir; files = dir;
dir = getPathWhenRootEmpty(); dir = getCurrentDirPath();
} }
const n = files.length; const n = files.length;

View file

@ -1,6 +1,4 @@
'use strict'; export const createBinder = () => {
module.exports.createBinder = () => {
let binded = false; let binded = false;
return { return {

28
client/key/binder.spec.js Normal file
View file

@ -0,0 +1,28 @@
import {test} from 'supertape';
import {createBinder} from './binder.js';
test('client: key: binder: isBind: default', (t) => {
const binder = createBinder();
t.notOk(binder.isBind(), 'should not be bind by default');
t.end();
});
test('client: key: binder: setBind', (t) => {
const binder = createBinder();
binder.setBind();
t.ok(binder.isBind(), 'should be bind');
t.end();
});
test('client: key: binder: unsetBind', (t) => {
const binder = createBinder();
binder.setBind();
binder.unsetBind();
t.notOk(binder.isBind(), 'should not be bind');
t.end();
});

View file

@ -2,8 +2,8 @@
import clipboard from '@cloudcmd/clipboard'; import clipboard from '@cloudcmd/clipboard';
import {fullstore} from 'fullstore'; import {fullstore} from 'fullstore';
import * as Events from '#dom/events'; import * as Events from '#dom/events';
import * as Buffer from '../dom/buffer.mjs'; import * as Buffer from '../dom/buffer.js';
import * as KEY from './key.mjs'; import * as KEY from './key.js';
import _vim from './vim/index.js'; import _vim from './vim/index.js';
import setCurrentByChar from './set-current-by-char.js'; import setCurrentByChar from './set-current-by-char.js';
import {createBinder} from './binder.js'; import {createBinder} from './binder.js';
@ -13,8 +13,8 @@ const Chars = fullstore();
const toggleVim = (keyCode, overrides = {}) => { const toggleVim = (keyCode, overrides = {}) => {
const {_config, config} = overrides; const {_config, config} = overrides;
if (keyCode === KEY.ESC) if (!config('vim') && keyCode === KEY.ESC)
_config('vim', !config('vim')); _config('vim', true);
}; };
const isUndefined = (a) => typeof a === 'undefined'; const isUndefined = (a) => typeof a === 'undefined';
@ -63,7 +63,7 @@ async function listener(event, overrides = {}) {
const {keyCode} = event; const {keyCode} = event;
// strange chrome bug calles listener twice // strange chrome bug calls listener twice
// in second time event misses a lot fields // in second time event misses a lot fields
if (isUndefined(event.altKey)) if (isUndefined(event.altKey))
return; return;
@ -442,6 +442,14 @@ async function _switchKey(event) {
break; break;
case KEY.L:
if (ctrlMeta && shift) {
CloudCmd.logOut();
event.preventDefault();
}
break;
case KEY.M: case KEY.M:
if (ctrlMeta) { if (ctrlMeta) {
if (config('vim')) if (config('vim'))

View file

@ -1,15 +1,9 @@
'use strict'; import autoGlobals from 'auto-globals';
import supertape from 'supertape';
import {ESC} from './key.js';
import {Key, _listener} from './index.js';
import {getDOM, getCloudCmd} from './vim/globals.fixture.js';
require('css-modules-require-hook/preset');
const autoGlobals = require('auto-globals');
const supertape = require('supertape');
const {ESC} = require('./key.mjs');
const {Key, _listener} = require('./index.mjs');
const {getDOM, getCloudCmd} = require('./vim/globals.fixture');
const test = autoGlobals(supertape); const test = autoGlobals(supertape);
const {stub} = supertape; const {stub} = supertape;
@ -43,6 +37,7 @@ test('cloudcmd: client: key: enable vim', async (t) => {
test('cloudcmd: client: key: disable vim', async (t) => { test('cloudcmd: client: key: disable vim', async (t) => {
const _config = stub(); const _config = stub();
const config = stub(); const config = stub();
const event = { const event = {
keyCode: ESC, keyCode: ESC,
key: 'Escape', key: 'Escape',

View file

@ -22,6 +22,7 @@ export const D = 68;
export const G = 71; export const G = 71;
export const J = 74; export const J = 74;
export const K = 75; export const K = 75;
export const L = 76;
export const M = 77; export const M = 77;
export const O = 79; export const O = 79;
export const P = 80; export const P = 80;

View file

@ -1,14 +1,11 @@
/* global DOM */ /* global DOM */
import {escapeRegExp} from '#common/util';
'use strict'; export default function setCurrentByChar(char, charStore) {
const {escapeRegExp} = require('../../common/util');
module.exports = function setCurrentByChar(char, charStore) {
const Info = DOM.CurrentInfo; const Info = DOM.CurrentInfo;
let firstByName; let firstByName;
let skipCount = 0; let skipCount = 0;
let setted = false; let set = false;
let i = 0; let i = 0;
const escapeChar = escapeRegExp(char); const escapeChar = escapeRegExp(char);
@ -36,7 +33,7 @@ module.exports = function setCurrentByChar(char, charStore) {
const byName = DOM.getCurrentByName(name); const byName = DOM.getCurrentByName(name);
if (!skipCount) { if (!skipCount) {
setted = true; set = true;
DOM.setCurrentFile(byName); DOM.setCurrentFile(byName);
return true; return true;
@ -53,8 +50,8 @@ module.exports = function setCurrentByChar(char, charStore) {
.filter(not(isRoot)) .filter(not(isRoot))
.some(setCurrent); .some(setCurrent);
if (!setted) { if (!set) {
DOM.setCurrentFile(firstByName); DOM.setCurrentFile(firstByName);
charStore([char]); charStore([char]);
} }
}; }

View file

@ -1,12 +1,10 @@
'use strict'; import {fullstore} from 'fullstore';
import limier from 'limier';
const {fullstore} = require('fullstore');
const limier = require('limier');
const searchStore = fullstore([]); const searchStore = fullstore([]);
const searchIndex = fullstore(0); const searchIndex = fullstore(0);
module.exports.find = (value, names) => { export const find = (value, names) => {
const result = limier(value, names); const result = limier(value, names);
searchStore(result); searchStore(result);
@ -15,7 +13,7 @@ module.exports.find = (value, names) => {
return result; return result;
}; };
module.exports.findNext = () => { export const findNext = () => {
const names = searchStore(); const names = searchStore();
const index = next(searchIndex(), names.length); const index = next(searchIndex(), names.length);
@ -23,7 +21,7 @@ module.exports.findNext = () => {
return names[searchIndex()]; return names[searchIndex()];
}; };
module.exports.findPrevious = () => { export const findPrevious = () => {
const names = searchStore(); const names = searchStore();
const index = previous(searchIndex(), names.length); const index = previous(searchIndex(), names.length);
@ -31,8 +29,8 @@ module.exports.findPrevious = () => {
return names[index]; return names[index];
}; };
module.exports._next = next; export const _next = next;
module.exports._previous = previous; export const _previous = previous;
function next(index, length) { function next(index, length) {
if (index === length - 1) if (index === length - 1)

View file

@ -1,14 +1,15 @@
'use strict'; import test from 'supertape';
import {getDOM} from './globals.fixture.js';
const test = require('supertape'); import {
const dir = './'; _next,
_previous,
const {getDOM} = require('./globals.fixture'); find,
findNext,
findPrevious,
} from './find.js';
globalThis.DOM = getDOM(); globalThis.DOM = getDOM();
const {_next, _previous} = require(`${dir}find`);
test('cloudcmd: client: vim: _next', (t) => { test('cloudcmd: client: vim: _next', (t) => {
const result = _next(1, 2); const result = _next(1, 2);
@ -16,9 +17,39 @@ test('cloudcmd: client: vim: _next', (t) => {
t.end(); t.end();
}); });
test('cloudcmd: client: vim: _next: increment', (t) => {
const result = _next(0, 2);
t.equal(result, 1, 'should return 1');
t.end();
});
test('cloudcmd: client: vim: _previous', (t) => { test('cloudcmd: client: vim: _previous', (t) => {
const result = _previous(0, 2); const result = _previous(0, 2);
t.equal(result, 1, 'should return 1'); t.equal(result, 1, 'should return 1');
t.end(); t.end();
}); });
test('cloudcmd: client: vim: _previous: decrement', (t) => {
const result = _previous(1, 2);
t.equal(result, 0, 'should return 0');
t.end();
});
test('cloudcmd: client: vim: findNext: after find', (t) => {
find('a', ['alpha', 'beta', 'apple']);
const result = findNext();
t.equal(result, 'beta', 'should return next found name');
t.end();
});
test('cloudcmd: client: vim: findPrevious: after find', (t) => {
find('a', ['alpha', 'beta', 'apple']);
const result = findPrevious();
t.equal(result, 'apple', 'should return previous found name');
t.end();
});

View file

@ -1,8 +1,6 @@
'use strict';
const noop = () => {}; const noop = () => {};
module.exports.getDOM = () => { export const getDOM = () => {
const prompt = Promise.resolve.bind(Promise); const prompt = Promise.resolve.bind(Promise);
const CurrentInfo = { const CurrentInfo = {
element: {}, element: {},
@ -34,7 +32,7 @@ module.exports.getDOM = () => {
}; };
}; };
module.exports.getCloudCmd = () => { export const getCloudCmd = () => {
const show = () => {}; const show = () => {};
return { return {

View file

@ -1,15 +1,11 @@
'use strict'; import vim from './vim.js';
import * as finder from './find.js';
/* global CloudCmd */ import {
/* global DOM */
const vim = require('./vim');
const finder = require('./find');
const {
setCurrent, setCurrent,
selectFileNotParent, selectFileNotParent,
} = require('./set-current'); } from './set-current.js';
module.exports = (key, event, overrides = {}) => { export default (key, event, overrides = {}) => {
const defaults = { const defaults = {
...globalThis.DOM, ...globalThis.DOM,
...globalThis.CloudCmd, ...globalThis.CloudCmd,
@ -37,13 +33,13 @@ const getOperations = (event, deps) => {
prompt = globalThis.DOM.Dialog.prompt, prompt = globalThis.DOM.Dialog.prompt,
preventDefault = event?.preventDefault?.bind(event), preventDefault = event?.preventDefault?.bind(event),
stopImmediatePropagation = event?.preventDefault?.bind(event), stopImmediatePropagation = event?.preventDefault?.bind(event),
promptNewFile = DOM.promptNewFile, promptNewFile = globalThis.DOM.promptNewFile,
toggleSelectedFile, toggleSelectedFile,
Buffer = {}, Buffer = {},
createFindNext = _createFindNext, createFindNext = _createFindNext,
createFindPrevious = _createFindPrevious, createFindPrevious = _createFindPrevious,
createMakeFile = _createMakeFile, createMakeFile = _createMakeFile,
renameCurrent,
} = deps; } = deps;
return { return {
@ -59,15 +55,26 @@ const getOperations = (event, deps) => {
setCurrentByName, setCurrentByName,
}), }),
escape: unselectFiles, escape: unselectFiles,
rename: () => {
event.preventDefault();
renameCurrent();
},
remove: () => { remove: () => {
Operation.show('delete'); Operation.show('delete');
}, },
operationCopy: () => {
event.preventDefault();
Operation.show('copy');
},
operationMove: () => {
event.preventDefault();
Operation.show('move');
},
makeDirectory: () => { makeDirectory: () => {
event.stopImmediatePropagation(); event.stopImmediatePropagation();
event.preventDefault(); event.preventDefault();
DOM.promptNewDir(); globalThis.DOM.promptNewDir();
}, },
terminal: () => { terminal: () => {
@ -131,7 +138,7 @@ const getOperations = (event, deps) => {
}; };
}; };
module.exports.selectFile = selectFileNotParent; export const selectFile = selectFileNotParent;
const _createFindPrevious = (overrides = {}) => () => { const _createFindPrevious = (overrides = {}) => () => {
const {setCurrentByName} = overrides; const {setCurrentByName} = overrides;

View file

@ -1,25 +1,15 @@
'use strict'; import {test, stub} from 'supertape';
import {getDOM, getCloudCmd} from './globals.fixture.js';
const {join} = require('node:path'); import vim, {selectFile as vimSelectFile} from './index.js';
const {test, stub} = require('supertape'); import * as finder from './find.js';
const dir = '../';
const pathVim = join(dir, 'vim');
const {getDOM, getCloudCmd} = require('./globals.fixture');
globalThis.DOM = getDOM(); globalThis.DOM = getDOM();
globalThis.CloudCmd = getCloudCmd(); globalThis.CloudCmd = getCloudCmd();
const vim = require('./index.js');
const {assign} = Object; const {assign} = Object;
const {DOM} = globalThis; const {DOM} = globalThis;
const {Buffer} = DOM; const {Buffer} = DOM;
const {reRequire, stopAll} = require('mock-require');
test('cloudcmd: client: key: set next file: no', (t) => { test('cloudcmd: client: key: set next file: no', (t) => {
const element = {}; const element = {};
const setCurrentFile = stub(); const setCurrentFile = stub();
@ -319,7 +309,7 @@ test('cloudcmd: client: key: selectFile: ..', (t) => {
const selectFile = stub(); const selectFile = stub();
const current = {}; const current = {};
vim.selectFile(current, { vimSelectFile(current, {
selectFile, selectFile,
getCurrentName, getCurrentName,
}); });
@ -333,7 +323,7 @@ test('cloudcmd: client: key: selectFile', (t) => {
const getCurrentName = stub().returns('x'); const getCurrentName = stub().returns('x');
const current = {}; const current = {};
vim.selectFile(current, { vimSelectFile(current, {
selectFile, selectFile,
getCurrentName, getCurrentName,
}); });
@ -458,6 +448,7 @@ test('cloudcmd: client: key: set first file current: ^', async (t) => {
test('cloudcmd: client: key: visual', (t) => { test('cloudcmd: client: key: visual', (t) => {
const element = {}; const element = {};
const toggleSelectedFile = stub(); const toggleSelectedFile = stub();
const Info = { const Info = {
element, element,
}; };
@ -474,6 +465,7 @@ test('cloudcmd: client: key: visual', (t) => {
test('cloudcmd: client: key: ESC', (t) => { test('cloudcmd: client: key: ESC', (t) => {
const element = {}; const element = {};
const unselectFiles = stub(); const unselectFiles = stub();
const Info = { const Info = {
element, element,
}; };
@ -519,6 +511,7 @@ test('cloudcmd: client: key: Enter', async (t) => {
test('cloudcmd: client: key: /', (t) => { test('cloudcmd: client: key: /', (t) => {
const preventDefault = stub(); const preventDefault = stub();
const element = {}; const element = {};
const Info = { const Info = {
element, element,
files: [], files: [],
@ -553,16 +546,12 @@ test('cloudcmd: client: find', (t) => {
setCurrentByName, setCurrentByName,
}); });
const vim = reRequire(pathVim);
const event = { const event = {
preventDefault: stub(), preventDefault: stub(),
}; };
vim('/', event); vim('/', event);
stopAll();
t.notCalled(setCurrentByName); t.notCalled(setCurrentByName);
t.end(); t.end();
}); });
@ -595,7 +584,6 @@ test('cloudcmd: client: key: N', (t) => {
}); });
test('cloudcmd: client: key: make directory', async (t) => { test('cloudcmd: client: key: make directory', async (t) => {
const vim = reRequire(pathVim);
const {DOM} = globalThis; const {DOM} = globalThis;
assign(DOM, { assign(DOM, {
@ -670,3 +658,99 @@ test('cloudcmd: client: vim: edit', async (t) => {
t.calledWithNoArgs(CloudCmd.EditFileVim.show); t.calledWithNoArgs(CloudCmd.EditFileVim.show);
t.end(); t.end();
}); });
test('cloudcmd: client: vim: rename', async (t) => {
const DOM = getDOM();
const renameCurrent = stub();
assign(DOM, {
renameCurrent,
});
const event = {
preventDefault: stub(),
};
await vim('rr', event, DOM);
t.calledWithNoArgs(renameCurrent);
t.end();
});
test('cloudcmd: client: key: cc: operationCopy', (t) => {
const show = stub();
const preventDefault = stub();
const Operation = {
show,
};
const event = {
preventDefault,
};
vim('c', event, {
Operation,
});
vim('c', event, {
Operation,
});
t.calledWith(show, ['copy'], 'should show copy operation');
t.end();
});
test('cloudcmd: client: key: mm: operationMove', (t) => {
const show = stub();
const preventDefault = stub();
const Operation = {
show,
};
const event = {
preventDefault,
};
vim('m', event, {
Operation,
});
vim('m', event, {
Operation,
});
t.calledWith(show, ['move'], 'should show move operation');
t.end();
});
test('cloudcmd: client: key: n: findNext: real', (t) => {
const setCurrentByName = stub();
finder.find('a', ['alpha', 'beta', 'apple']);
const event = {};
vim('n', event, {
setCurrentByName,
});
t.calledWith(setCurrentByName, ['beta'], 'should set current by next found name');
t.end();
});
test('cloudcmd: client: key: N: findPrevious: real', (t) => {
const setCurrentByName = stub();
finder.find('a', ['alpha', 'beta', 'apple']);
const event = {};
vim('N', event, {
setCurrentByName,
});
t.calledWith(setCurrentByName, ['apple'], 'should set current by previous found name');
t.end();
});

View file

@ -1,8 +1,5 @@
'use strict';
/* global DOM */ /* global DOM */
module.exports.selectFileNotParent = selectFileNotParent; export function selectFileNotParent(current, {getCurrentName, selectFile} = DOM) {
function selectFileNotParent(current, {getCurrentName, selectFile} = DOM) {
const name = getCurrentName(current); const name = getCurrentName(current);
if (name === '..') if (name === '..')
@ -11,7 +8,7 @@ function selectFileNotParent(current, {getCurrentName, selectFile} = DOM) {
selectFile(current); selectFile(current);
} }
module.exports.setCurrent = (sibling, {count, isVisual, isDelete}, {Info, setCurrentFile, unselectFiles, Operation}) => { export const setCurrent = (sibling, {count, isVisual, isDelete}, {Info, setCurrentFile, unselectFiles, Operation}) => {
let current = Info.element; let current = Info.element;
const select = isVisual ? selectFileNotParent : unselectFiles; const select = isVisual ? selectFileNotParent : unselectFiles;

View file

@ -1,6 +1,5 @@
'use strict'; import {fullstore} from 'fullstore';
const {fullstore} = require('fullstore');
const store = fullstore(''); const store = fullstore('');
const visual = fullstore(false); const visual = fullstore(false);
@ -21,7 +20,7 @@ const rmFirst = (a) => {
const noop = () => {}; const noop = () => {};
module.exports = (key, operations = {}) => { export default (key, operations = {}) => {
const prevStore = store(); const prevStore = store();
const isVisual = visual(); const isVisual = visual();
const value = store(prevStore.concat(key)); const value = store(prevStore.concat(key));
@ -41,6 +40,9 @@ module.exports = (key, operations = {}) => {
makeDirectory = noop, makeDirectory = noop,
terminal = noop, terminal = noop,
edit = noop, edit = noop,
operationCopy = noop,
operationMove = noop,
rename = noop,
} = operations; } = operations;
if (key === 'Enter') if (key === 'Enter')
@ -112,11 +114,26 @@ module.exports = (key, operations = {}) => {
return end(); return end();
} }
if (value === 'cc') {
operationCopy();
return end();
}
if (value === 'mm') {
operationMove();
return end();
}
if (value === 'mf') { if (value === 'mf') {
makeFile(); makeFile();
return end(); return end();
} }
if (value === 'rr') {
rename();
return end();
}
if (key === 'd' && (visual() || prevStore === 'd')) { if (key === 'd' && (visual() || prevStore === 'd')) {
stopVisual(); stopVisual();
remove(); remove();

View file

@ -1,8 +1,5 @@
'use strict'; import {test, stub} from 'supertape';
import vim from './vim.js';
const {test, stub} = require('supertape');
const vim = require('./vim');
test('vim: no operations', (t) => { test('vim: no operations', (t) => {
const result = vim('hello', {}); const result = vim('hello', {});
@ -46,6 +43,28 @@ test('vim: ^', (t) => {
t.end(); t.end();
}); });
test('vim: cc', (t) => {
const operationCopy = stub();
vim('cc', {
operationCopy,
});
t.calledWithNoArgs(operationCopy);
t.end();
});
test('vim: mm', (t) => {
const operationMove = stub();
vim('mm', {
operationMove,
});
t.calledWithNoArgs(operationMove);
t.end();
});
test('vim: w', (t) => { test('vim: w', (t) => {
const moveNext = stub(); const moveNext = stub();

View file

@ -1,5 +1,5 @@
import test from 'supertape'; import test from 'supertape';
import {getIndex} from './get-index.mjs'; import {getIndex} from './get-index.js';
test('cloudcmd: client: listeners: getIndex: not found', (t) => { test('cloudcmd: client: listeners: getIndex: not found', (t) => {
const array = ['hello']; const array = ['hello'];

View file

@ -1,5 +1,5 @@
import test from 'supertape'; import test from 'supertape';
import {getRange} from './get-range.mjs'; import {getRange} from './get-range.js';
test('cloudcmd: client: listeners: getRange: direct', (t) => { test('cloudcmd: client: listeners: getRange: direct', (t) => {
const expected = [ const expected = [

View file

@ -5,15 +5,15 @@ import currify from 'currify';
import {tryToCatch} from 'try-to-catch'; import {tryToCatch} from 'try-to-catch';
import clipboard from '@cloudcmd/clipboard'; import clipboard from '@cloudcmd/clipboard';
import * as Events from '#dom/events'; import * as Events from '#dom/events';
import {getRange} from './get-range.mjs'; import {uploadFiles} from '#dom/upload-files';
import uploadFiles from '../dom/upload-files.js'; import {FS} from '#common/cloudfunc';
import {FS} from '../../common/cloudfunc.mjs'; import {getRange} from './get-range.js';
import {getIndex} from './get-index.mjs'; import {getIndex} from './get-index.js';
const NBSP_REG = RegExp(String.fromCharCode(160), 'g'); const NBSP_REG = RegExp(String.fromCharCode(160), 'g');
const SPACE = ' '; const SPACE = ' ';
export const init = async () => { export async function init() {
contextMenu(); contextMenu();
dragndrop(); dragndrop();
unload(); unload();
@ -21,7 +21,7 @@ export const init = async () => {
resize(); resize();
header(); header();
await config(); await config();
}; }
const unselect = (event) => { const unselect = (event) => {
const isMac = /Mac/.test(globalThis.navigator.platform); const isMac = /Mac/.test(globalThis.navigator.platform);
@ -55,6 +55,7 @@ let EXT;
function header() { function header() {
const fm = DOM.getFM(); const fm = DOM.getFM();
const isDataset = (el) => el.dataset; const isDataset = (el) => el.dataset;
const isPanel = (el) => { const isPanel = (el) => {
return /^js-(left|right)$/.test(el.dataset.name); return /^js-(left|right)$/.test(el.dataset.name);
}; };
@ -309,8 +310,12 @@ function onDragStart(event) {
link.href = prefixURL + '/pack' + Info.path + EXT; link.href = prefixURL + '/pack' + Info.path + EXT;
} }
event.dataTransfer.setData('DownloadURL', 'application/octet-stream' + ':' + name + event.dataTransfer.setData(
':' + link); 'DownloadURL',
'application/octet-stream' + ':' + name +
':' +
link,
);
} }
function getLIElement(element) { function getLIElement(element) {

View file

@ -1,32 +1,32 @@
/* global CloudCmd, filepicker */ /* global CloudCmd, filepicker */
import exec from 'execon';
import currify from 'currify';
import load from 'load.js';
import {ajax} from '#dom/load';
import * as Files from '#dom/files';
import * as Images from '#dom/images';
'use strict';
const exec = require('execon');
const currify = require('currify');
const load = require('load.js');
const {ajax} = require('../dom/load');
const Files = require('../dom/files');
const Images = require('../dom/images.mjs');
const {log} = CloudCmd; const {log} = CloudCmd;
const upload = currify(_upload); const upload = currify(_upload);
const Name = 'Cloud'; const Name = 'Cloud';
CloudCmd[Name] = module.exports; CloudCmd[Name] = {
init,
uploadFile,
saveFile,
};
module.exports.init = async () => { export async function init() {
const [modules] = await loadFiles(); const [modules] = await loadFiles();
const {key} = modules.data.FilePicker; const {key} = modules.data.FilePicker;
filepicker.setKey(key); filepicker.setKey(key);
Images.hide(); Images.hide();
}; }
module.exports.uploadFile = (filename, data) => { export function uploadFile(filename, data) {
const mimetype = ''; const mimetype = '';
filepicker.store(data, { filepicker.store(data, {
@ -35,11 +35,11 @@ module.exports.uploadFile = (filename, data) => {
}, (fpFile) => { }, (fpFile) => {
filepicker.exportFile(fpFile, log, log); filepicker.exportFile(fpFile, log, log);
}); });
}; }
module.exports.saveFile = (callback) => { export function saveFile(callback) {
filepicker.pick(upload(callback)); filepicker.pick(upload(callback));
}; }
function _upload(callback, file) { function _upload(callback, file) {
const {url, filename} = file; const {url, filename} = file;

View file

@ -1,18 +1,14 @@
'use strict';
/* global CloudCmd */ /* global CloudCmd */
CloudCmd.CommandLine = exports; import * as Dialog from '#dom/dialog';
const Dialog = require('../dom/dialog'); export function init() {}
CloudCmd.CommandLine = {
init,
show,
hide,
};
const noop = () => {}; export async function show() {
module.exports.init = noop;
module.exports.show = show;
module.exports.hide = hide;
async function show() {
const [, cmd] = await Dialog.prompt('Command Line', ''); const [, cmd] = await Dialog.prompt('Command Line', '');
const TERMINAL = '^(t|terminal)'; const TERMINAL = '^(t|terminal)';
@ -32,4 +28,4 @@ async function show() {
} }
} }
function hide() {} export function hide() {}

View file

@ -1,5 +1,5 @@
/* global CloudCmd, DOM, io */ import '../../../css/config.css';
import rendy from 'rendy'; import {rendy} from 'rendy';
import currify from 'currify'; import currify from 'currify';
import wraptile from 'wraptile'; import wraptile from 'wraptile';
import squad from 'squad'; import squad from 'squad';
@ -8,11 +8,12 @@ import {tryToCatch} from 'try-to-catch';
import load from 'load.js'; import load from 'load.js';
import createElement from '@cloudcmd/create-element'; import createElement from '@cloudcmd/create-element';
import * as Events from '#dom/events'; import * as Events from '#dom/events';
import '../../../css/config.css'; import * as Files from '#dom/files';
import * as input from './input.mjs'; import {getTitle} from '#common/cloudfunc';
import * as Images from '../../dom/images.mjs'; import * as Images from '#dom/images';
import Files from '../../dom/files.js'; import * as input from './input.js';
import {getTitle} from '../../../common/cloudfunc.mjs';
const {CloudCmd, DOM} = globalThis;
const {Dialog, setTitle} = DOM; const {Dialog, setTitle} = DOM;
@ -40,7 +41,7 @@ let Template;
const loadCSS = load.css; const loadCSS = load.css;
export const init = async () => { export async function init() {
if (!CloudCmd.config('configDialog')) if (!CloudCmd.config('configDialog'))
return; return;
@ -56,7 +57,7 @@ export const init = async () => {
]); ]);
initSocket(); initSocket();
}; }
const {config, Key} = CloudCmd; const {config, Key} = CloudCmd;
@ -78,7 +79,7 @@ function initSocket() {
const ONE_MINUTE = 60 * 1000; const ONE_MINUTE = 60 * 1000;
const socket = io.connect(href + prefixSocket + '/config', { const socket = globalThis.io.connect(href + prefixSocket + '/config', {
reconnectionAttempts: Infinity, reconnectionAttempts: Infinity,
reconnectionDelay: ONE_MINUTE, reconnectionDelay: ONE_MINUTE,
path: `${prefix}/socket.io`, path: `${prefix}/socket.io`,
@ -132,6 +133,7 @@ async function fillTemplate() {
columns, columns,
theme, theme,
configAuth, configAuth,
configPort,
...obj ...obj
} = input.convert(config); } = input.convert(config);
@ -141,6 +143,7 @@ async function fillTemplate() {
obj[`${columns}-selected`] = 'selected'; obj[`${columns}-selected`] = 'selected';
obj[`${theme}-selected`] = 'selected'; obj[`${theme}-selected`] = 'selected';
obj.configAuth = configAuth ? '' : 'hidden'; obj.configAuth = configAuth ? '' : 'hidden';
obj.configPort = configPort ? '' : 'hidden';
const innerHTML = rendy(Template, obj); const innerHTML = rendy(Template, obj);

View file

@ -1,7 +1,9 @@
import currify from 'currify'; import {encode} from '#common/entity';
const isType = currify((type, object, name) => type === typeof object[name]); const isBool = (a) => typeof a === 'boolean';
const isBool = isType('boolean'); const isString = (a) => typeof a === 'string';
const {keys} = Object;
export function getElementByName(selector, element) { export function getElementByName(selector, element) {
const str = `[data-name="js-${selector}"]`; const str = `[data-name="js-${selector}"]`;
@ -19,13 +21,19 @@ export const getName = (element) => {
export const convert = (config) => { export const convert = (config) => {
const result = config; const result = config;
const array = Object.keys(config);
const filtered = array.filter(isBool(config)); for (const name of keys(config)) {
for (const name of filtered) {
const item = config[name]; const item = config[name];
result[name] = setState(item);
if (isBool(item)) {
result[name] = setState(item);
continue;
}
if (isString(item)) {
result[name] = encode(item);
continue;
}
} }
return result; return result;

View file

@ -0,0 +1,140 @@
import {test, stub} from 'supertape';
import {
convert,
getName,
getValue,
setValue,
} from './input.js';
test('cloudcmd: client: config: input: convert', (t) => {
const result = convert({
name: 'hello <world>',
});
const expected = {
name: 'hello &lt;world&gt;',
};
t.deepEqual(result, expected);
t.end();
});
test('cloudcmd: client: config: input: convert: bool', (t) => {
const result = convert({
auth: true,
});
const expected = {
auth: ' checked',
};
t.deepEqual(result, expected);
t.end();
});
test('cloudcmd: client: config: input: convert: bool false', (t) => {
const result = convert({
auth: false,
});
const expected = {
auth: '',
};
t.deepEqual(result, expected);
t.end();
});
test('cloudcmd: client: config: input: getName', (t) => {
const getAttribute = stub().returns('js-hello');
const element = {
getAttribute,
};
const result = getName(element);
t.equal(result, 'hello', 'should strip js- prefix');
t.end();
});
test('cloudcmd: client: config: input: getValue: checkbox', (t) => {
const querySelector = stub().returns({
type: 'checkbox',
checked: true,
});
const element = {
querySelector,
};
const result = getValue('auth', element);
t.ok(result, 'should return checked value');
t.end();
});
test('cloudcmd: client: config: input: getValue: number', (t) => {
const querySelector = stub().returns({
type: 'number',
value: '42',
});
const element = {
querySelector,
};
const result = getValue('port', element);
t.equal(result, 42, 'should return number');
t.end();
});
test('cloudcmd: client: config: input: getValue: default', (t) => {
const querySelector = stub().returns({
type: 'text',
value: 'hello',
});
const element = {
querySelector,
};
const result = getValue('name', element);
t.equal(result, 'hello', 'should return value as is');
t.end();
});
test('cloudcmd: client: config: input: setValue: checkbox', (t) => {
const el = {
type: 'checkbox',
checked: false,
};
const querySelector = stub().returns(el);
const element = {
querySelector,
};
setValue('auth', true, element);
t.ok(el.checked, 'should set checked');
t.end();
});
test('cloudcmd: client: config: input: setValue: default', (t) => {
const el = {
type: 'text',
value: 'old',
};
const querySelector = stub().returns(el);
const element = {
querySelector,
};
setValue('name', 'new', element);
t.equal(el.value, 'new', 'should set value');
t.end();
});

View file

@ -1,36 +1,34 @@
/* global CloudCmd */ /* global CloudCmd */
/* global DOM */ /* global DOM */
import olark from '@cloudcmd/olark';
import * as Images from '#dom/images';
'use strict'; CloudCmd.Contact = {
init,
CloudCmd.Contact = exports; show,
hide,
const olark = require('@cloudcmd/olark'); };
const Images = require('../dom/images.mjs');
const {Events} = DOM; const {Events} = DOM;
const {Key} = CloudCmd; const {Key} = CloudCmd;
module.exports.show = show; export function init() {
module.exports.hide = hide;
module.exports.init = () => {
Events.addKey(onKey); Events.addKey(onKey);
olark.identify('6216-545-10-4223'); olark.identify('6216-545-10-4223');
olark('api.box.onExpand', show); olark('api.box.onExpand', show);
olark('api.box.onShow', show); olark('api.box.onShow', show);
olark('api.box.onShrink', hide); olark('api.box.onShrink', hide);
}; }
function show() { export function show() {
Key.unsetBind(); Key.unsetBind();
Images.hide(); Images.hide();
olark('api.box.expand'); olark('api.box.expand');
} }
function hide() { export function hide() {
Key.setBind(); Key.setBind();
olark('api.box.hide'); olark('api.box.hide');
} }

View file

@ -1,9 +1,12 @@
'use strict'; import * as Events from '#dom/events';
/* global CloudCmd */ const {CloudCmd} = globalThis;
CloudCmd.EditFileVim = exports;
const Events = require('#dom/events'); CloudCmd.EditFileVim = {
init,
show,
hide,
};
const {Key} = CloudCmd; const {Key} = CloudCmd;
@ -15,11 +18,11 @@ const ConfigView = {
}, },
}; };
module.exports.init = async () => { export async function init() {
await CloudCmd.EditFile(); await CloudCmd.EditFile();
}; }
module.exports.show = async () => { export async function show() {
Events.addKey(listener); Events.addKey(listener);
const editFile = await CloudCmd.EditFile.show(ConfigView); const editFile = await CloudCmd.EditFile.show(ConfigView);
@ -27,11 +30,9 @@ module.exports.show = async () => {
editFile editFile
.getEditor() .getEditor()
.setKeyMap('vim'); .setKeyMap('vim');
}; }
module.exports.hide = hide; export function hide() {
function hide() {
CloudCmd.Edit.hide(); CloudCmd.Edit.hide();
} }

View file

@ -1,12 +1,15 @@
'use strict';
/* global CloudCmd, DOM*/ /* global CloudCmd, DOM*/
CloudCmd.EditFile = exports; import Format from 'format-io';
import {fullstore} from 'fullstore';
import exec from 'execon';
import {supermenu} from 'supermenu';
const Format = require('format-io'); CloudCmd.EditFile = {
const {fullstore} = require('fullstore'); init,
const exec = require('execon'); show,
const supermenu = require('supermenu'); hide,
isChanged,
};
const Info = DOM.CurrentInfo; const Info = DOM.CurrentInfo;
@ -26,7 +29,7 @@ const ConfigView = {
}, },
}; };
module.exports.init = async () => { export async function init() {
isLoading(true); isLoading(true);
await CloudCmd.Edit(); await CloudCmd.Edit();
@ -36,7 +39,7 @@ module.exports.init = async () => {
setListeners(editor); setListeners(editor);
isLoading(false); isLoading(false);
}; }
function getName() { function getName() {
const {name, isDir} = Info; const {name, isDir} = Info;
@ -47,7 +50,7 @@ function getName() {
return name; return name;
} }
module.exports.show = async (options) => { export async function show(options) {
if (isLoading()) if (isLoading())
return; return;
@ -86,11 +89,9 @@ module.exports.show = async (options) => {
CloudCmd.Edit.show(optionsEdit); CloudCmd.Edit.show(optionsEdit);
return CloudCmd.Edit; return CloudCmd.Edit;
}; }
module.exports.hide = hide; export function hide() {
function hide() {
CloudCmd.Edit.hide(); CloudCmd.Edit.hide();
} }
@ -176,9 +177,7 @@ function setMsgChanged(name) {
MSG_CHANGED = `Do you want to save changes to ${name}?`; MSG_CHANGED = `Do you want to save changes to ${name}?`;
} }
module.exports.isChanged = isChanged; export async function isChanged() {
async function isChanged() {
const editor = CloudCmd.Edit.getEditor(); const editor = CloudCmd.Edit.getEditor();
const is = editor.isChanged(); const is = editor.isChanged();

View file

@ -1,9 +1,12 @@
'use strict'; import * as Events from '#dom/events';
/* global CloudCmd */ const {CloudCmd} = globalThis;
CloudCmd.EditNamesVim = exports;
const Events = require('#dom/events'); CloudCmd.EditNamesVim = {
init,
show,
hide,
};
const {Key} = CloudCmd; const {Key} = CloudCmd;
const ConfigView = { const ConfigView = {
@ -14,22 +17,20 @@ const ConfigView = {
}, },
}; };
module.exports.init = async () => { export async function init() {
await CloudCmd.EditNames(); await CloudCmd.EditNames();
}; }
module.exports.show = () => { export function show() {
Events.addKey(listener); Events.addKey(listener);
CloudCmd.EditNames CloudCmd.EditNames
.show(ConfigView) .show(ConfigView)
.getEditor() .getEditor()
.setKeyMap('vim'); .setKeyMap('vim');
}; }
module.exports.hide = hide; export function hide() {
function hide() {
CloudCmd.Edit.hide(); CloudCmd.Edit.hide();
} }

View file

@ -1,13 +1,16 @@
'use strict'; import {tryToCatch} from 'try-to-catch';
import exec from 'execon';
import {supermenu} from 'supermenu';
import {multiRename} from 'multi-rename';
const {tryToCatch} = require('try-to-catch'); const {CloudCmd, DOM} = globalThis;
/* global CloudCmd, DOM */ CloudCmd.EditNames = {
CloudCmd.EditNames = exports; init,
show,
const exec = require('execon'); hide,
const supermenu = require('supermenu'); isChanged,
const {multiRename} = require('multi-rename'); };
const Info = DOM.CurrentInfo; const Info = DOM.CurrentInfo;
const {Dialog} = DOM; const {Dialog} = DOM;
@ -22,13 +25,13 @@ const ConfigView = {
}, },
}; };
module.exports.init = async () => { export async function init() {
await CloudCmd.Edit(); await CloudCmd.Edit();
setListeners(); setListeners();
}; }
module.exports.show = (options) => { export function show(options) {
const names = getActiveNames().join('\n'); const names = getActiveNames().join('\n');
const config = { const config = {
...ConfigView, ...ConfigView,
@ -50,7 +53,7 @@ module.exports.show = (options) => {
CloudCmd.Edit.show(config); CloudCmd.Edit.show(config);
return CloudCmd.Edit; return CloudCmd.Edit;
}; }
async function keyListener(event) { async function keyListener(event) {
const ctrl = event.ctrlKey; const ctrl = event.ctrlKey;
@ -60,7 +63,10 @@ async function keyListener(event) {
if (ctrlMeta && event.keyCode === Key.S) { if (ctrlMeta && event.keyCode === Key.S) {
hide(); hide();
} else if (ctrlMeta && event.keyCode === Key.P) { return;
}
if (ctrlMeta && event.keyCode === Key.P) {
const [, pattern] = await Dialog.prompt('Apply pattern:', '[n][e]'); const [, pattern] = await Dialog.prompt('Apply pattern:', '[n][e]');
pattern && applyPattern(pattern); pattern && applyPattern(pattern);
} }
@ -77,9 +83,7 @@ function getActiveNames() {
return DOM.getFilenames(DOM.getActiveFiles()); return DOM.getFilenames(DOM.getActiveFiles());
} }
module.exports.hide = hide; export function hide() {
function hide() {
CloudCmd.Edit.hide(); CloudCmd.Edit.hide();
} }
@ -201,9 +205,7 @@ function setMenu(event) {
Menu.show(position.x, position.y); Menu.show(position.x, position.y);
} }
module.exports.isChanged = isChanged; export async function isChanged() {
async function isChanged() {
const editor = CloudCmd.Edit.getEditor(); const editor = CloudCmd.Edit.getEditor();
const msg = 'Apply new names?'; const msg = 'Apply new names?';

View file

@ -1,23 +1,28 @@
/* global CloudCmd */ /* global CloudCmd */
import {montag} from 'montag';
import {promisify} from 'es6-promisify';
import {tryToCatch} from 'try-to-catch';
import createElement from '@cloudcmd/create-element';
import load from 'load.js';
import {MAX_FILE_SIZE as maxSize} from '#common/cloudfunc';
import {time, timeEnd} from '#common/util';
'use strict'; export function getEditor() {
return editor;
}
const montag = require('montag');
const {promisify} = require('es6-promisify');
const {tryToCatch} = require('try-to-catch');
const createElement = require('@cloudcmd/create-element');
const load = require('load.js');
const {MAX_FILE_SIZE: maxSize} = require('../../common/cloudfunc.mjs');
const {time, timeEnd} = require('../../common/util');
const getEditor = () => editor;
const isFn = (a) => typeof a === 'function'; const isFn = (a) => typeof a === 'function';
const loadJS = load.js; const loadJS = load.js;
const Name = 'Edit'; const Name = 'Edit';
CloudCmd[Name] = exports; CloudCmd[Name] = {
init,
show,
hide,
getEditor,
getElement,
};
const EditorName = CloudCmd.config('editor'); const EditorName = CloudCmd.config('editor');
@ -33,12 +38,12 @@ const ConfigView = {
}, },
}; };
module.exports.init = async () => { export async function init() {
const element = create(); const element = create();
await CloudCmd.View(); await CloudCmd.View();
await loadFiles(element); await loadFiles(element);
}; }
function create() { function create() {
const element = createElement('div', { const element = createElement('div', {
@ -79,7 +84,7 @@ function initConfig(options = {}) {
return config; return config;
} }
module.exports.show = (options) => { export function show(options) {
if (Loading) if (Loading)
return; return;
@ -88,15 +93,15 @@ module.exports.show = (options) => {
getEditor().setOptions({ getEditor().setOptions({
fontSize: 16, fontSize: 16,
}); });
}; }
module.exports.getEditor = getEditor; export function getElement() {
return Element;
}
module.exports.getElement = () => Element; export function hide() {
module.exports.hide = () => {
CloudCmd.View.hide(); CloudCmd.View.hide();
}; }
const loadFiles = async (element) => { const loadFiles = async (element) => {
const prefix = `${CloudCmd.prefix}/${EditorName}`; const prefix = `${CloudCmd.prefix}/${EditorName}`;

View file

@ -1,18 +1,18 @@
'use strict'; import * as Images from '#dom/images';
/* global CloudCmd */ const {CloudCmd} = globalThis;
CloudCmd.Help = exports;
const Images = require('../dom/images.mjs'); CloudCmd.Help = {
init,
module.exports.init = () => { show,
Images.show.load('top'); hide,
}; };
module.exports.show = show; export function init() {
module.exports.hide = hide; Images.show.load('top');
}
function show() { export function show() {
const positionLoad = 'top'; const positionLoad = 'top';
const relative = true; const relative = true;
@ -22,6 +22,6 @@ function show() {
}); });
} }
function hide() { export function hide() {
CloudCmd.View.hide(); CloudCmd.View.hide();
} }

View file

@ -1,18 +1,20 @@
'use strict';
/* global CloudCmd */ /* global CloudCmd */
/* global Util */ /* global Util */
/* global DOM */ /* global DOM */
/* global Console */ /* global Console */
CloudCmd.Konsole = exports; import exec from 'execon';
import currify from 'currify';
import {tryToCatch} from 'try-to-catch';
import {js as loadJS} from 'load.js';
import createElement from '@cloudcmd/create-element';
import * as Images from '#dom/images';
const exec = require('execon'); CloudCmd.Konsole = {
const currify = require('currify'); init,
const {tryToCatch} = require('try-to-catch'); show,
const loadJS = require('load.js').js; hide,
const createElement = require('@cloudcmd/create-element'); };
const Images = require('../dom/images.mjs');
const {Dialog, CurrentInfo: Info} = DOM; const {Dialog, CurrentInfo: Info} = DOM;
const rmLastSlash = (a) => a.replace(/\/$/, '') || '/'; const rmLastSlash = (a) => a.replace(/\/$/, '') || '/';
@ -27,7 +29,7 @@ const Name = 'Konsole';
let Element; let Element;
let Loaded; let Loaded;
module.exports.init = async () => { export async function init() {
if (!config('console')) if (!config('console'))
return; return;
@ -36,13 +38,13 @@ module.exports.init = async () => {
await CloudCmd.View(); await CloudCmd.View();
await load(); await load();
await create(); await create();
}; }
module.exports.hide = () => { export function hide() {
CloudCmd.View.hide(); CloudCmd.View.hide();
}; }
module.exports.clear = () => { export const clear = () => {
konsole.clear(); konsole.clear();
}; };
@ -109,7 +111,7 @@ function authCheck(konsole) {
}); });
} }
module.exports.show = (callback) => { export function show(callback) {
if (!Loaded) if (!Loaded)
return; return;
@ -122,7 +124,7 @@ module.exports.show = (callback) => {
exec(callback); exec(callback);
}, },
}); });
}; }
const load = async () => { const load = async () => {
Util.time(`${Name} load`); Util.time(`${Name} load`);

View file

@ -1,26 +1,26 @@
'use strict'; import createElement from '@cloudcmd/create-element';
import * as Images from '#dom/images';
import {Markdown} from '#dom/rest';
import {alert} from '#dom/dialog';
/* global CloudCmd */ const {CloudCmd} = globalThis;
CloudCmd.Markdown = exports;
const createElement = require('@cloudcmd/create-element'); CloudCmd.Markdown = {
init,
show,
hide,
};
const Images = require('../dom/images.mjs'); export async function init() {
const {Markdown} = require('../dom/rest');
const {alert} = require('../dom/dialog');
module.exports.init = async () => {
Images.show.load('top'); Images.show.load('top');
await CloudCmd.View(); await CloudCmd.View();
}; }
module.exports.show = show; export function hide() {
module.exports.hide = () => {
CloudCmd.View.hide(); CloudCmd.View.hide();
}; }
async function show(name, options = {}) { export async function show(name, options = {}) {
const {positionLoad, relative} = options; const {positionLoad, relative} = options;
Images.show.load(positionLoad); Images.show.load(positionLoad);

View file

@ -1,4 +1,4 @@
import supermenu from 'supermenu'; import {supermenu} from 'supermenu';
const noop = () => {}; const noop = () => {};
const {CloudCmd} = globalThis; const {CloudCmd} = globalThis;
@ -14,8 +14,9 @@ export const createCloudMenu = async (fm, options, menuData) => {
async function loadMenu() { async function loadMenu() {
if (CloudCmd.config('menu') === 'aleman') { if (CloudCmd.config('menu') === 'aleman') {
const {prefix} = CloudCmd;
const {host, protocol} = globalThis.location; const {host, protocol} = globalThis.location;
const url = `${protocol}//${host}/node_modules/aleman/menu/menu.js`; const url = `${protocol}//${host}${prefix}/node_modules/aleman/menu/menu.js`;
const {createMenu} = await import(/* webpackIgnore: true */url); const {createMenu} = await import(/* webpackIgnore: true */url);
return createMenu; return createMenu;

View file

@ -1,15 +1,11 @@
/* global CloudCmd, DOM */ import exec from 'execon';
import wrap from 'wraptile';
'use strict'; import createElement from '@cloudcmd/create-element';
import {getIdBySrc} from '#dom/load';
const exec = require('execon'); import * as RESTful from '#dom/rest';
const wrap = require('wraptile'); import {FS} from '#common/cloudfunc';
const createElement = require('@cloudcmd/create-element');
const {FS} = require('../../../common/cloudfunc.mjs');
const {getIdBySrc} = require('../../dom/load');
const RESTful = require('../../dom/rest');
const {CloudCmd, DOM} = globalThis;
const {config, Key} = CloudCmd; const {config, Key} = CloudCmd;
const { const {
@ -27,11 +23,15 @@ let MenuShowedName;
let MenuContext; let MenuContext;
let MenuContextFile; let MenuContextFile;
module.exports.ENABLED = false; export const ENABLED = false;
CloudCmd.Menu = exports; CloudCmd.Menu = {
init,
show,
hide,
};
module.exports.init = async () => { export async function init() {
const {isAuth, menuDataFile} = getFileMenuData(); const {isAuth, menuDataFile} = getFileMenuData();
const fm = DOM.getFM(); const fm = DOM.getFM();
@ -45,7 +45,7 @@ module.exports.init = async () => {
type: 'file', type: 'file',
}); });
const {createCloudMenu} = await import('./cloudmenu.mjs'); const {createCloudMenu} = await import('./cloudmenu.js');
const {name} = fm.dataset; const {name} = fm.dataset;
@ -56,23 +56,21 @@ module.exports.init = async () => {
MenuContextFile.addContextMenuListener(); MenuContextFile.addContextMenuListener();
Events.addKey(listener); Events.addKey(listener);
}; }
module.exports.hide = hide; export function hide() {
function hide() {
MenuContext.hide(); MenuContext.hide();
MenuContextFile.hide(); MenuContextFile.hide();
} }
module.exports.show = (position) => { export function show(position) {
const {x, y} = getPosition(position); const {x, y} = getPosition(position);
MenuContext.show(x, y); MenuContext.show(x, y);
MenuContextFile.show(x, y); MenuContextFile.show(x, y);
Images.hide(); Images.hide();
}; }
function getPosition(position) { function getPosition(position) {
if (position) if (position)
@ -298,7 +296,7 @@ function download(type) {
* no need in hash so we escape # * no need in hash so we escape #
* and all other characters, like "%" * and all other characters, like "%"
*/ */
const encodedPath = encodeURI(path).replace(/#/g, '%23'); const encodedPath = encodeURI(path).replace(/#/g, '#');
const id = getIdBySrc(path); const id = getIdBySrc(path);
let src; let src;

View file

@ -1,6 +1,4 @@
'use strict'; export const format = (operation, from, to) => {
module.exports = (operation, from, to) => {
if (!to) if (!to)
return `${operation} ${from}`; return `${operation} ${from}`;

View file

@ -1,11 +1,9 @@
'use strict'; import currify from 'currify';
const currify = require('currify');
const not = currify((array, value) => !array.includes(value)); const not = currify((array, value) => !array.includes(value));
const notOneOf = currify((a, b) => a.filter(not(b))); const notOneOf = currify((a, b) => a.filter(not(b)));
module.exports = (currentName, names, removedNames) => { export const getNextCurrentName = (currentName, names, removedNames) => {
const i = names.indexOf(currentName); const i = names.indexOf(currentName);
const nextNames = notOneOf(names, removedNames); const nextNames = notOneOf(names, removedNames);

View file

@ -4,10 +4,10 @@ import {promisify} from 'es6-promisify';
import exec from 'execon'; import exec from 'execon';
import load from 'load.js'; import load from 'load.js';
import {tryToCatch} from 'try-to-catch'; import {tryToCatch} from 'try-to-catch';
import {encode} from '../../../common/entity.js'; import {encode} from '#common/entity';
import removeExtension from './remove-extension.js'; import {removeExtension} from './remove-extension.js';
import {setListeners} from './set-listeners.mjs'; import {setListeners} from './set-listeners.js';
import getNextCurrentName from './get-next-current-name.js'; import {getNextCurrentName} from './get-next-current-name.js';
const {DOM, CloudCmd} = globalThis; const {DOM, CloudCmd} = globalThis;
@ -190,11 +190,11 @@ function getPacker(type) {
return packTarFn; return packTarFn;
} }
export const hide = () => { export function hide() {
CloudCmd.View.hide(); CloudCmd.View.hide();
}; }
export const show = (operation, data) => { export function show(operation, data) {
if (!Loaded) if (!Loaded)
return; return;
@ -215,7 +215,7 @@ export const show = (operation, data) => {
if (operation === 'extract') if (operation === 'extract')
return Operation.extract(); return Operation.extract();
}; }
Operation.copy = processFiles({ Operation.copy = processFiles({
type: 'copy', type: 'copy',

View file

@ -1,8 +1,6 @@
'use strict'; import {getExt} from '#common/util';
const {getExt} = require('../../../common/util'); export const removeExtension = (name) => {
module.exports = (name) => {
const ext = getExtension(name); const ext = getExtension(name);
return name.replace(ext, ''); return name.replace(ext, '');

View file

@ -1,7 +1,5 @@
'use strict'; import test from 'supertape';
import {removeExtension} from './remove-extension.js';
const test = require('supertape');
const removeExtension = require(`./remove-extension`);
test('cloudcmd: client: modules: operation: removeExtension: .tar.gz', (t) => { test('cloudcmd: client: modules: operation: removeExtension: .tar.gz', (t) => {
const name = 'hello'; const name = 'hello';

View file

@ -1,7 +1,7 @@
/* global DOM */ /* global DOM */
import forEachKey from 'for-each-key'; import forEachKey from 'for-each-key';
import wraptile from 'wraptile'; import wraptile from 'wraptile';
import format from './format.js'; import {format} from './format.js';
const {Dialog, Images} = DOM; const {Dialog, Images} = DOM;
@ -15,15 +15,12 @@ export const setListeners = (options) => (emitter) => {
} = options; } = options;
let done; let done;
let lastError;
const onAbort = wraptile(({emitter, operation}) => { const onAbort = wraptile(({emitter, operation}) => {
emitter.abort(); emitter.abort();
const msg = `${operation} aborted`; const msg = `${operation} aborted`;
lastError = true;
Dialog.alert(msg, { Dialog.alert(msg, {
cancel: false, cancel: false,
}); });
@ -40,13 +37,10 @@ export const setListeners = (options) => (emitter) => {
operation, operation,
})); }));
let noProgress = true;
const listeners = { const listeners = {
progress: (value) => { progress: (value) => {
done = value === 100; done = value === 100;
progress.setProgress(value); progress.setProgress(value);
noProgress = false;
}, },
end: () => { end: () => {
@ -54,13 +48,10 @@ export const setListeners = (options) => (emitter) => {
forEachKey(removeListener, listeners); forEachKey(removeListener, listeners);
progress.remove(); progress.remove();
if (lastError || done || noProgress) callback();
callback();
}, },
error: async (error) => { error: async (error) => {
lastError = error;
if (noContinue) { if (noContinue) {
listeners.end(error); listeners.end(error);
Dialog.alert(error); Dialog.alert(error);

View file

@ -1,12 +1,8 @@
'use strict'; import _scrollIntoViewIfNeeded from 'scroll-into-view-if-needed';
require('domtokenlist-shim');
const _scrollIntoViewIfNeeded = require('scroll-into-view-if-needed');
globalThis.DOM = globalThis.DOM || {}; globalThis.DOM = globalThis.DOM || {};
const scrollIntoViewIfNeeded = (el, overrides = {}) => { export const scrollIntoViewIfNeeded = (el, overrides = {}) => {
const { const {
scroll = _scrollIntoViewIfNeeded, scroll = _scrollIntoViewIfNeeded,
} = overrides; } = overrides;
@ -17,4 +13,3 @@ const scrollIntoViewIfNeeded = (el, overrides = {}) => {
}; };
globalThis.DOM.scrollIntoViewIfNeeded = scrollIntoViewIfNeeded; globalThis.DOM.scrollIntoViewIfNeeded = scrollIntoViewIfNeeded;
module.exports.scrollIntoViewIfNeeded = scrollIntoViewIfNeeded;

View file

@ -1,9 +1,7 @@
'use strict'; import {test, stub} from 'supertape';
import {scrollIntoViewIfNeeded} from './polyfill.js';
const {test, stub} = require('supertape'); test('cloudcmd: client: polyfill: scrollIntoViewIfNeeded', (t) => {
const {scrollIntoViewIfNeeded} = require('./polyfill');
test('cloudcmd: client: polyfill: scrollIntoViewIfNeaded', (t) => {
const scroll = stub(); const scroll = stub();
const el = {}; const el = {};
@ -17,6 +15,6 @@ test('cloudcmd: client: polyfill: scrollIntoViewIfNeaded', (t) => {
}, },
]; ];
t.calledWith(scroll, args, 'should call scrollIntoViewIfNeaded'); t.calledWith(scroll, args, 'should call scrollIntoViewIfNeeded');
t.end(); t.end();
}); });

View file

@ -1,21 +1,21 @@
'use strict'; import '../../css/terminal.css';
import {promisify} from 'es6-promisify';
/* global CloudCmd, gritty */ import {tryToCatch} from 'try-to-catch';
const {promisify} = require('es6-promisify'); import {fullstore} from 'fullstore';
const {tryToCatch} = require('try-to-catch'); import exec from 'execon';
const {fullstore} = require('fullstore'); import load from 'load.js';
import DOM from '#dom';
require('../../css/terminal.css'); import * as Images from '#dom/images';
const exec = require('execon');
const load = require('load.js');
const DOM = require('../dom');
const Images = require('../dom/images.mjs');
const {Dialog} = DOM; const {Dialog} = DOM;
const {CloudCmd} = globalThis;
const {Key, config} = CloudCmd; const {Key, config} = CloudCmd;
CloudCmd.TerminalRun = exports; CloudCmd.TerminalRun = {
init,
show,
hide,
};
let Loaded; let Loaded;
let Terminal; let Terminal;
@ -40,7 +40,7 @@ const loadAll = async () => {
Loaded = true; Loaded = true;
}; };
module.exports.init = async () => { export async function init() {
if (!config('terminal')) if (!config('terminal'))
return; return;
@ -48,9 +48,13 @@ module.exports.init = async () => {
await CloudCmd.View(); await CloudCmd.View();
await loadAll(); await loadAll();
}; }
module.exports.show = promisify((options = {}, fn) => { export async function show(options = {}) {
return await runTerminal(options);
}
const runTerminal = promisify((options, fn) => {
if (!Loaded) if (!Loaded)
return fn(null, -1); return fn(null, -1);
@ -69,9 +73,7 @@ module.exports.show = promisify((options = {}, fn) => {
}); });
}); });
module.exports.hide = hide; export function hide() {
function hide() {
CloudCmd.View.hide(); CloudCmd.View.hide();
} }
@ -108,7 +110,7 @@ function create(createOptions) {
let commandExit = false; let commandExit = false;
const {socket, terminal} = gritty(document.body, options); const {socket, terminal} = globalThis.gritty(document.body, options);
Socket = socket; Socket = socket;
Terminal = terminal; Terminal = terminal;

View file

@ -1,22 +1,22 @@
'use strict'; import '#css/terminal.css';
import {tryToCatch} from 'try-to-catch';
/* global CloudCmd */ import exec from 'execon';
/* global gritty */ import load from 'load.js';
const {tryToCatch} = require('try-to-catch'); import * as Images from '#dom/images';
import DOM from '#dom';
require('../../css/terminal.css');
const exec = require('execon');
const load = require('load.js');
const DOM = require('../dom');
const Images = require('../dom/images.mjs');
const loadParallel = load.parallel; const loadParallel = load.parallel;
const {Dialog} = DOM; const {CloudCmd} = globalThis;
const {Key, config} = CloudCmd;
CloudCmd.Terminal = exports; const {Dialog} = DOM;
const {Key, config} = globalThis.CloudCmd;
CloudCmd.Terminal = {
init,
show,
hide,
};
let Loaded; let Loaded;
let Terminal; let Terminal;
@ -39,7 +39,7 @@ const loadAll = async () => {
Loaded = true; Loaded = true;
}; };
module.exports.init = async () => { export async function init() {
if (!config('terminal')) if (!config('terminal'))
return; return;
@ -48,12 +48,9 @@ module.exports.init = async () => {
await CloudCmd.View(); await CloudCmd.View();
await loadAll(); await loadAll();
create(); create();
}; }
module.exports.show = show; export function hide() {
module.exports.hide = hide;
function hide() {
CloudCmd.View.hide(); CloudCmd.View.hide();
} }
@ -78,7 +75,7 @@ function create() {
fontFamily: 'Droid Sans Mono', fontFamily: 'Droid Sans Mono',
}; };
const {socket, terminal} = gritty(document.body, options); const {socket, terminal} = globalThis.gritty(document.body, options);
Socket = socket; Socket = socket;
Terminal = terminal; Terminal = terminal;
@ -101,7 +98,7 @@ function authCheck(spawn) {
}); });
} }
function show() { export function show() {
if (!Loaded) if (!Loaded)
return; return;

View file

@ -1,23 +1,21 @@
/* global CloudCmd, DOM */ /* global CloudCmd, DOM */
import createElement from '@cloudcmd/create-element';
import * as Files from '#dom/files';
import {uploadFiles} from '#dom/upload-files';
import * as Images from '#dom/images';
'use strict'; CloudCmd.Upload = {
init,
CloudCmd.Upload = exports; show,
hide,
const createElement = require('@cloudcmd/create-element');
const Files = require('../dom/files');
const Images = require('../dom/images.mjs');
const uploadFiles = require('../dom/upload-files');
module.exports.init = async () => {
Images.show.load('top');
await CloudCmd.View();
}; };
module.exports.show = show; export async function init() {
module.exports.hide = hide; Images.show.load('top');
await CloudCmd.View();
}
async function show() { export async function show() {
Images.show.load('top'); Images.show.load('top');
const innerHTML = await Files.get('upload'); const innerHTML = await Files.get('upload');
@ -49,7 +47,7 @@ async function show() {
}); });
} }
function hide() { export function hide() {
CloudCmd.View.hide(); CloudCmd.View.hide();
} }

View file

@ -1,6 +1,4 @@
'use strict'; export const getUserMenu = (menuFn) => {
module.exports = (menuFn) => {
const module = {}; const module = {};
const fn = Function('module', menuFn); const fn = Function('module', menuFn);

View file

@ -1,7 +1,5 @@
'use strict'; import test from 'supertape';
import {getUserMenu} from './get-user-menu.js';
const test = require('supertape');
const getUserMenu = require('./get-user-menu');
test('user-menu: getUserMenu', (t) => { test('user-menu: getUserMenu', (t) => {
const menu = `module.exports = { const menu = `module.exports = {

Some files were not shown because too many files have changed in this diff Show more