Compare commits
396 Commits
1.408-vsc1
...
2.1662-vsc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
766efd6079 | ||
|
|
87485948ad | ||
|
|
7e4a73ce2d | ||
|
|
2f0878d9b7 | ||
|
|
f65c9b23fc | ||
|
|
cd859d117f | ||
|
|
e22964915a | ||
|
|
197d0b6ca9 | ||
|
|
422503ef98 | ||
|
|
ea36345d2c | ||
|
|
a89d83cbba | ||
|
|
83ff31b620 | ||
|
|
3a9b032c72 | ||
|
|
f73e9225b4 | ||
|
|
168ccb0dfc | ||
|
|
58f7f5b769 | ||
|
|
b8e6369fbe | ||
|
|
d81d5f499f | ||
|
|
4be178d234 | ||
|
|
9c40466b4b | ||
|
|
95693fb58e | ||
|
|
e7945bea94 | ||
|
|
91f49e1efd | ||
|
|
eea9c1618c | ||
|
|
f1b38e4e48 | ||
|
|
ff99a1d768 | ||
|
|
7f07b8f66c | ||
|
|
faae03da6b | ||
|
|
a6e4f96737 | ||
|
|
cc7585bbc2 | ||
|
|
14a0cd3ffd | ||
|
|
3ff83eda45 | ||
|
|
f133b00851 | ||
|
|
ece840834d | ||
|
|
76f6ff4145 | ||
|
|
2458cde498 | ||
|
|
82e2b8a169 | ||
|
|
5aa2abaf9f | ||
|
|
fdb2308c62 | ||
|
|
4cd2f2cd52 | ||
|
|
88cef85f62 | ||
|
|
bdd11f741b | ||
|
|
56ce780522 | ||
|
|
567010e163 | ||
|
|
4ae2c81157 | ||
|
|
ae43e2016f | ||
|
|
3f6cbfa4dd | ||
|
|
1c50b5285e | ||
|
|
ea9c511db8 | ||
|
|
e1e3f32643 | ||
|
|
4290cffe3b | ||
|
|
548d095611 | ||
|
|
846dcbb947 | ||
|
|
d7d3368cc2 | ||
|
|
134040fea3 | ||
|
|
65caa26d40 | ||
|
|
7812f6b75a | ||
|
|
637e58f255 | ||
|
|
6135630fc0 | ||
|
|
22058c5f86 | ||
|
|
616bdb35f3 | ||
|
|
42f7b5d12b | ||
|
|
53818b0e36 | ||
|
|
6f08b13540 | ||
|
|
d36526b1c8 | ||
|
|
1252eb6a8a | ||
|
|
4733c31a2f | ||
|
|
17c5173d8b | ||
|
|
d0a08f6dd7 | ||
|
|
7b5d6d186b | ||
|
|
3851927396 | ||
|
|
7eececead6 | ||
|
|
b8c3d96fcd | ||
|
|
a2ee6c8e73 | ||
|
|
ef069d9b0e | ||
|
|
6a864f9f47 | ||
|
|
5c16399810 | ||
|
|
0141ded35d | ||
|
|
bb46e80d44 | ||
|
|
1bd5eca73d | ||
|
|
48a97abe1d | ||
|
|
0ff8a11c7f | ||
|
|
8b1cdaa4a1 | ||
|
|
0bbaa9763b | ||
|
|
dbe5f23e21 | ||
|
|
7353be413c | ||
|
|
398bc2ff41 | ||
|
|
ae1126d43f | ||
|
|
46d16811b9 | ||
|
|
f8635a124f | ||
|
|
c3c50e9a6a | ||
|
|
cb0f9c58d2 | ||
|
|
8643bdc9d7 | ||
|
|
5b51999df7 | ||
|
|
64cc2895f3 | ||
|
|
51a82655a9 | ||
|
|
0e1fed3c24 | ||
|
|
e9fce801a0 | ||
|
|
1164801376 | ||
|
|
12e608468b | ||
|
|
ed3e9d31f4 | ||
|
|
44000459da | ||
|
|
9d8906d250 | ||
|
|
a26844ea45 | ||
|
|
da7d8b04a8 | ||
|
|
12bc26b6b4 | ||
|
|
976a326f47 | ||
|
|
b901043bfc | ||
|
|
624a4c08b9 | ||
|
|
c9ce9ebb2e | ||
|
|
a3ee7c96a0 | ||
|
|
d33b2d2af9 | ||
|
|
830ccfe245 | ||
|
|
78b6b3afdf | ||
|
|
c4fd725875 | ||
|
|
4800ec6392 | ||
|
|
3e2d12a224 | ||
|
|
ddd5a9ae79 | ||
|
|
950dad9489 | ||
|
|
c19223b7fe | ||
|
|
80050d0d9d | ||
|
|
c2be0ec71b | ||
|
|
ccc4f87ada | ||
|
|
534600c1ff | ||
|
|
0f1bbc3161 | ||
|
|
615948c73f | ||
|
|
b9fc40409a | ||
|
|
e53d6bce68 | ||
|
|
ce3b7dfb1e | ||
|
|
19541c27ff | ||
|
|
c94761f312 | ||
|
|
b4e1a62cb4 | ||
|
|
7caef7f49c | ||
|
|
6737384d27 | ||
|
|
f61a0ae78a | ||
|
|
d1662d7658 | ||
|
|
72fe124e30 | ||
|
|
a48c2fb119 | ||
|
|
07ec4ca63e | ||
|
|
83f86a45b6 | ||
|
|
45ad7f020a | ||
|
|
2470081789 | ||
|
|
c11d5fe9e6 | ||
|
|
90e8714e71 | ||
|
|
5539519691 | ||
|
|
b566b66590 | ||
|
|
7389d9e2cb | ||
|
|
1d61cbe536 | ||
|
|
2807ce495e | ||
|
|
ba7285192c | ||
|
|
8c39e085f4 | ||
|
|
b257c60636 | ||
|
|
6b579d65ef | ||
|
|
d4ed2efa71 | ||
|
|
3667b16cba | ||
|
|
2b3e8e1a89 | ||
|
|
f5a6f14ade | ||
|
|
01a9ab332e | ||
|
|
9d688e0894 | ||
|
|
7d35144952 | ||
|
|
7e794bd134 | ||
|
|
dc333d4321 | ||
|
|
590f699687 | ||
|
|
dde683d911 | ||
|
|
950bfce420 | ||
|
|
5b64cb3400 | ||
|
|
712274d912 | ||
|
|
bdd9d65146 | ||
|
|
60ed0653bc | ||
|
|
bce0cac48f | ||
|
|
bd0f1d024b | ||
|
|
5944b842de | ||
|
|
12af311ce7 | ||
|
|
62719ab544 | ||
|
|
0315b004a7 | ||
|
|
87be3ac235 | ||
|
|
011530e11b | ||
|
|
4bfa686433 | ||
|
|
c67844d356 | ||
|
|
8ded89e8d4 | ||
|
|
4c4a179bce | ||
|
|
a4f21fb0d4 | ||
|
|
329acbb251 | ||
|
|
fd55139c82 | ||
|
|
7b7f5b542e | ||
|
|
92daabc75c | ||
|
|
068e07bd5d | ||
|
|
436ef7bd5c | ||
|
|
09cd1e8540 | ||
|
|
cd54aec2f9 | ||
|
|
078af59fd8 | ||
|
|
36b8731cfe | ||
|
|
9fdfacb314 | ||
|
|
e8cb6ffaa0 | ||
|
|
2be452d83e | ||
|
|
b0e6c1cc4e | ||
|
|
45d348b03d | ||
|
|
4b0cceb91a | ||
|
|
db41f106bc | ||
|
|
b6fdb7d0e7 | ||
|
|
1a3fc86894 | ||
|
|
83819cb3f9 | ||
|
|
feabfc86fa | ||
|
|
9b0b337dc0 | ||
|
|
9446cc8245 | ||
|
|
68c62087dc | ||
|
|
8dcc1e3567 | ||
|
|
e22791ec88 | ||
|
|
286f9a8978 | ||
|
|
97167e75ff | ||
|
|
2b2aa9a211 | ||
|
|
81862d4fa1 | ||
|
|
2fdf09e6e7 | ||
|
|
09e3cfd881 | ||
|
|
54ffd1d351 | ||
|
|
86e8ba12e7 | ||
|
|
f482087475 | ||
|
|
fe1d609d1a | ||
|
|
a20fa4a97a | ||
|
|
f51751ad21 | ||
|
|
197d8dba93 | ||
|
|
3ca90a5f89 | ||
|
|
6156eb9ff4 | ||
|
|
f8f4bfd76f | ||
|
|
5677ff2edf | ||
|
|
61c281ec6b | ||
|
|
770e0db7b8 | ||
|
|
6a35ab1dc0 | ||
|
|
3a78c0964f | ||
|
|
4685f6793d | ||
|
|
2e77c9d449 | ||
|
|
a6703ecb98 | ||
|
|
57a8186e88 | ||
|
|
d808bfaec6 | ||
|
|
7072bf1e83 | ||
|
|
4e0a6d2941 | ||
|
|
0d618bb1ef | ||
|
|
a0121f2f0c | ||
|
|
98f001395c | ||
|
|
68fe085aa3 | ||
|
|
4861405683 | ||
|
|
310bfe509e | ||
|
|
f25a614333 | ||
|
|
0ae8c1820a | ||
|
|
e776f18192 | ||
|
|
72d71664b3 | ||
|
|
1046fc192e | ||
|
|
c48a275d33 | ||
|
|
79e08c74ed | ||
|
|
3f2ad7b719 | ||
|
|
5e8c3f8ff3 | ||
|
|
ddab1a0626 | ||
|
|
d950e3c9de | ||
|
|
46298c7675 | ||
|
|
14d917179c | ||
|
|
a65773338c | ||
|
|
9b5a43e4bd | ||
|
|
46207cfe10 | ||
|
|
242bb6ffa2 | ||
|
|
e6713db677 | ||
|
|
11784e55b2 | ||
|
|
a72e8a698d | ||
|
|
28c93612e6 | ||
|
|
a9d17882e7 | ||
|
|
cf63bbd003 | ||
|
|
02f62882b8 | ||
|
|
362715bbeb | ||
|
|
ec70ea6994 | ||
|
|
04adf14146 | ||
|
|
406ec0ba71 | ||
|
|
e2eaa0aa4e | ||
|
|
a2ad3d4ff4 | ||
|
|
4a29cd1664 | ||
|
|
0462a93f11 | ||
|
|
db39eacfa1 | ||
|
|
91bcbe496b | ||
|
|
c020cd2f2c | ||
|
|
81bbfa7fbe | ||
|
|
aa1474b675 | ||
|
|
8256252967 | ||
|
|
07342bbee7 | ||
|
|
72152f74ab | ||
|
|
420ca76f54 | ||
|
|
31503fc853 | ||
|
|
cf399ef6ac | ||
|
|
bb5836ec61 | ||
|
|
f36235e03f | ||
|
|
6ef1628acb | ||
|
|
ab8f8a0a22 | ||
|
|
cdb900aca8 | ||
|
|
1622fd4152 | ||
|
|
6c972e855f | ||
|
|
e332882a88 | ||
|
|
d0142e2536 | ||
|
|
e8c8fba91d | ||
|
|
01a63a7241 | ||
|
|
a2e0638c6a | ||
|
|
4e62f938a9 | ||
|
|
4c5bb83fc1 | ||
|
|
a3ac4567e3 | ||
|
|
58cf109a83 | ||
|
|
fab45dedcd | ||
|
|
446573809c | ||
|
|
5ad9398b01 | ||
|
|
bcdbd90197 | ||
|
|
0de7247868 | ||
|
|
c9f91e77cd | ||
|
|
30b8565e2d | ||
|
|
6b887dcc9c | ||
|
|
41c7d98b7b | ||
|
|
b055a26dc3 | ||
|
|
2bc6e1a457 | ||
|
|
e61ea796c6 | ||
|
|
d073622629 | ||
|
|
5f40ebb845 | ||
|
|
c56e2797cc | ||
|
|
166efcb17e | ||
|
|
206e107a9a | ||
|
|
12c8b5d337 | ||
|
|
4aa20fd864 | ||
|
|
0cd4e46055 | ||
|
|
f51823b51f | ||
|
|
55bfeab208 | ||
|
|
309d15cefd | ||
|
|
95006a435a | ||
|
|
4d576ab4d4 | ||
|
|
d5b03ef60e | ||
|
|
cdc5b55a9d | ||
|
|
c3a38e3fea | ||
|
|
cc8c7e2cee | ||
|
|
e0f1787ce6 | ||
|
|
50e6108012 | ||
|
|
630ccfcacc | ||
|
|
c4c26058ef | ||
|
|
8a4da542ae | ||
|
|
e907dbe7e6 | ||
|
|
22b485acd9 | ||
|
|
b8f222acf2 | ||
|
|
aabb2ecda7 | ||
|
|
dfabc070b9 | ||
|
|
da420cdda9 | ||
|
|
c6a46e4753 | ||
|
|
742dd6f597 | ||
|
|
6c3ff1d6f0 | ||
|
|
db57aa229f | ||
|
|
f7342ede69 | ||
|
|
b781ccde9c | ||
|
|
8f62b2bff2 | ||
|
|
7047be859c | ||
|
|
2785e2219a | ||
|
|
4b217fba00 | ||
|
|
3fae68bbab | ||
|
|
a2f20aa25c | ||
|
|
94b8b9a5cf | ||
|
|
bbd8b27fc7 | ||
|
|
6361635b55 | ||
|
|
d2da4cfc43 | ||
|
|
a1136b3a02 | ||
|
|
4dd74b31b9 | ||
|
|
bc0f6eb65d | ||
|
|
6737d3da18 | ||
|
|
eb0f773146 | ||
|
|
ebac84899e | ||
|
|
0b7a090a73 | ||
|
|
a95019f38d | ||
|
|
15948c1af6 | ||
|
|
e73eb74208 | ||
|
|
278c59b920 | ||
|
|
5a1eb858a9 | ||
|
|
3c1dfb1170 | ||
|
|
09a02eb9e9 | ||
|
|
2bd7281fa0 | ||
|
|
e12fcd3a0d | ||
|
|
4af84fcaf6 | ||
|
|
c607015a26 | ||
|
|
217515344e | ||
|
|
dcf409aecb | ||
|
|
2683b7c734 | ||
|
|
3a672d725a | ||
|
|
f484781693 | ||
|
|
97f5b07003 | ||
|
|
7481395353 | ||
|
|
033ef151ca | ||
|
|
3fec7f432c | ||
|
|
4887078423 | ||
|
|
91deaece47 | ||
|
|
03ad2a17b2 | ||
|
|
a4cca6b759 | ||
|
|
6105bba0a4 | ||
|
|
259095eae2 | ||
|
|
38a0706b18 | ||
|
|
c7ae12c2ed | ||
|
|
3331f9b28d | ||
|
|
def4104c53 | ||
|
|
4eb5331ddc | ||
|
|
3bb5c0bbe5 |
@@ -1,9 +1,12 @@
|
|||||||
Dockerfile
|
Dockerfile
|
||||||
# Docs
|
build
|
||||||
doc/
|
deployment
|
||||||
# GitHub stuff
|
doc
|
||||||
.github
|
.github
|
||||||
.gitignore
|
.gitignore
|
||||||
|
.node-version
|
||||||
.travis.yml
|
.travis.yml
|
||||||
LICENSE
|
LICENSE
|
||||||
README.md
|
README.md
|
||||||
|
node_modules
|
||||||
|
release
|
||||||
7
.gitignore
vendored
@@ -1,6 +1,5 @@
|
|||||||
lib
|
|
||||||
node_modules
|
node_modules
|
||||||
dist
|
build
|
||||||
out
|
|
||||||
.DS_Store
|
|
||||||
release
|
release
|
||||||
|
binaries
|
||||||
|
source
|
||||||
|
|||||||
1
.node-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
10.16.0
|
||||||
101
.travis.yml
@@ -1,38 +1,73 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- 8.15.0
|
- 10.16.0
|
||||||
env:
|
services:
|
||||||
- VSCODE_VERSION="1.32.0" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION"
|
- docker
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: linux
|
|
||||||
dist: ubuntu
|
|
||||||
- os: osx
|
|
||||||
before_install:
|
before_install:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libxkbfile-dev
|
- export MAJOR_VERSION="2"
|
||||||
libsecret-1-dev; fi
|
- export VSCODE_VERSION="1.39.2"
|
||||||
script:
|
- export VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER"
|
||||||
- scripts/build.sh
|
- export TAG="$VERSION-vsc$VSCODE_VERSION"
|
||||||
|
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi
|
||||||
|
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export PACKAGE="true"; fi
|
||||||
|
|
||||||
|
# Don't build on tags because we'll already have built the commit.
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- name: "Linux build"
|
||||||
|
os: linux
|
||||||
|
dist: trusty
|
||||||
|
env: TARGET="linux" PUSH_DOCKER="true"
|
||||||
|
if: tag IS blank
|
||||||
|
script: scripts/ci.bash
|
||||||
|
- name: "Alpine build"
|
||||||
|
os: linux
|
||||||
|
dist: trusty
|
||||||
|
env: TARGET="alpine"
|
||||||
|
if: tag IS blank
|
||||||
|
script: scripts/ci.bash
|
||||||
|
- name: "MacOS build"
|
||||||
|
os: osx
|
||||||
|
if: tag IS blank
|
||||||
|
script: travis_wait 60 scripts/ci.bash
|
||||||
|
|
||||||
|
git:
|
||||||
|
depth: 3
|
||||||
|
|
||||||
before_deploy:
|
before_deploy:
|
||||||
- echo "$VERSION" "$TRAVIS_COMMIT"
|
- echo "$TAG" "$TRAVIS_COMMIT"
|
||||||
- git config --local user.name "$USER_NAME"
|
- git config --local user.name "$USER_NAME"
|
||||||
- git config --local user.email "$USER_EMAIL"
|
- git config --local user.email "$USER_EMAIL"
|
||||||
- git tag "$VERSION" "$TRAVIS_COMMIT"
|
- if ! git tag "$TAG" "$TRAVIS_COMMIT" ; then echo "$TAG already exists"; fi
|
||||||
- yarn task package "$VERSION"
|
- if [[ -n "$PUSH_DOCKER" ]] ; then echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin ; fi
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
provider: releases
|
- provider: releases
|
||||||
file_glob: true
|
file_glob: true
|
||||||
draft: true
|
draft: true
|
||||||
tag_name: "$VERSION"
|
tag_name: "$TAG"
|
||||||
target_commitish: "$TRAVIS_COMMIT"
|
target_commitish: "$TRAVIS_COMMIT"
|
||||||
name: "$VERSION"
|
name: "$TAG"
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
api_key:
|
api_key:
|
||||||
secure: YL/x24KjYjgYXPcJWk3FV7FGxI79Mh6gBECQEcdlf3fkLEoKFVgzHBoUNWrFPzyR4tgLyWNAgcpD9Lkme1TRWTom7UPjXcwMNyLcLa+uec7ciSAnYD9ntLTpiCuPDD1u0LtRGclSi/EHQ+F8YVq+HZJpXTsJeAmOmihma3GVbGKSZr+BRum+0YZSG4w+o4TOlYzw/4bLWS52MogZcwpjd+hemBbgXLuGU2ziKv2vEKCZFbEeA16II4x1WLI4mutDdCeh7+3aLzGLwDa49NxtsVYNjyNFF75JhCTCNA55e2YMiLz9Uq69IXe/mi5F7xUaFfhIqqLNyKBnKeEOzu3dYnc+8n3LjnQ+00PmkF05nx9kBn3UfV1kwQGh6QbyDmTtBP07rtUMyI14aeQqHjxsaVRdMnwj9Q2DjXRr8UDqESZF0rmK3pHCXS2fBhIzLE8tLVW5Heiba2pQRFMHMZW+KBE97FzcFh7is90Ait3T8enfcd/PWFPYoBejDAdjwxwOkezh5N5ZkYquEfDYuWrFi6zRFCktsruaAcA+xGtTf9oilBBzUqu8Ie+YFWH5me83xakcblJWdaW/D2rLJAJH3m6LFm8lBqyUgDX5t/etob6CpDuYHu5D1J3XINOj/+aLAcadq6qlh70PMZS3zYffUu3JlzaD2amlSHIT8b5YXFc=
|
secure: YL/x24KjYjgYXPcJWk3FV7FGxI79Mh6gBECQEcdlf3fkLEoKFVgzHBoUNWrFPzyR4tgLyWNAgcpD9Lkme1TRWTom7UPjXcwMNyLcLa+uec7ciSAnYD9ntLTpiCuPDD1u0LtRGclSi/EHQ+F8YVq+HZJpXTsJeAmOmihma3GVbGKSZr+BRum+0YZSG4w+o4TOlYzw/4bLWS52MogZcwpjd+hemBbgXLuGU2ziKv2vEKCZFbEeA16II4x1WLI4mutDdCeh7+3aLzGLwDa49NxtsVYNjyNFF75JhCTCNA55e2YMiLz9Uq69IXe/mi5F7xUaFfhIqqLNyKBnKeEOzu3dYnc+8n3LjnQ+00PmkF05nx9kBn3UfV1kwQGh6QbyDmTtBP07rtUMyI14aeQqHjxsaVRdMnwj9Q2DjXRr8UDqESZF0rmK3pHCXS2fBhIzLE8tLVW5Heiba2pQRFMHMZW+KBE97FzcFh7is90Ait3T8enfcd/PWFPYoBejDAdjwxwOkezh5N5ZkYquEfDYuWrFi6zRFCktsruaAcA+xGtTf9oilBBzUqu8Ie+YFWH5me83xakcblJWdaW/D2rLJAJH3m6LFm8lBqyUgDX5t/etob6CpDuYHu5D1J3XINOj/+aLAcadq6qlh70PMZS3zYffUu3JlzaD2amlSHIT8b5YXFc=
|
||||||
file:
|
file:
|
||||||
- release/*.tar.gz
|
- release/*.tar.gz
|
||||||
- release/*.zip
|
- release/*.zip
|
||||||
on:
|
on:
|
||||||
repo: codercom/code-server
|
repo: cdr/code-server
|
||||||
branch: master
|
branch: master
|
||||||
cache: yarn
|
|
||||||
|
- provider: script
|
||||||
|
skip_cleanup: true
|
||||||
|
script: docker build -f ./scripts/ci.dockerfile -t codercom/code-server:"$TAG" -t codercom/code-server:v2 -t codercom/code-server . && docker push codercom/code-server:"$TAG" && docker push codercom/code-server:v2 && docker push codercom/code-server
|
||||||
|
on:
|
||||||
|
repo: cdr/code-server
|
||||||
|
branch: master
|
||||||
|
condition: -n "$PUSH_DOCKER"
|
||||||
|
|
||||||
|
cache:
|
||||||
|
yarn: true
|
||||||
|
directories:
|
||||||
|
- source
|
||||||
|
|||||||
52
Dockerfile
@@ -1,4 +1,7 @@
|
|||||||
FROM node:8.15.0
|
FROM node:10.16.0
|
||||||
|
ARG codeServerVersion=docker
|
||||||
|
ARG vscodeVersion
|
||||||
|
ARG githubToken
|
||||||
|
|
||||||
# Install VS Code's deps. These are the only two it seems we need.
|
# Install VS Code's deps. These are the only two it seems we need.
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
@@ -11,23 +14,48 @@ RUN npm install -g yarn@1.13
|
|||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# In the future, we can use https://github.com/yarnpkg/rfcs/pull/53 to make yarn use the node_modules
|
RUN yarn \
|
||||||
# directly which should be fast as it is slow because it populates its own cache every time.
|
&& MINIFY=true GITHUB_TOKEN="${githubToken}" yarn build "${vscodeVersion}" "${codeServerVersion}" \
|
||||||
RUN yarn && yarn task build:server:binary
|
&& yarn binary "${vscodeVersion}" "${codeServerVersion}" \
|
||||||
|
&& mv "/src/binaries/code-server${codeServerVersion}-vsc${vscodeVersion}-linux-x86_64" /src/binaries/code-server \
|
||||||
|
&& rm -r /src/build \
|
||||||
|
&& rm -r /src/source
|
||||||
|
|
||||||
# We deploy with ubuntu so that devs have a familiar environment.
|
# We deploy with ubuntu so that devs have a familiar environment.
|
||||||
FROM ubuntu:18.10
|
FROM ubuntu:18.04
|
||||||
WORKDIR /root/project
|
|
||||||
COPY --from=0 /src/packages/server/cli-linux-x64 /usr/local/bin/code-server
|
|
||||||
EXPOSE 8443
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
openssl \
|
openssl \
|
||||||
net-tools \
|
net-tools \
|
||||||
git \
|
git \
|
||||||
locales
|
locales \
|
||||||
|
sudo \
|
||||||
|
dumb-init \
|
||||||
|
vim \
|
||||||
|
curl \
|
||||||
|
wget
|
||||||
|
|
||||||
RUN locale-gen en_US.UTF-8
|
RUN locale-gen en_US.UTF-8
|
||||||
# We unfortunately cannot use update-locale because docker will not use the env variables
|
# We cannot use update-locale because docker will not use the env variables
|
||||||
# configured in /etc/default/locale so we need to set it manually.
|
# configured in /etc/default/locale so we need to set it manually.
|
||||||
ENV LANG=en_US.UTF-8
|
ENV LC_ALL=en_US.UTF-8 \
|
||||||
ENTRYPOINT ["code-server"]
|
SHELL=/bin/bash
|
||||||
|
|
||||||
|
RUN adduser --gecos '' --disabled-password coder && \
|
||||||
|
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
|
||||||
|
|
||||||
|
USER coder
|
||||||
|
# We create first instead of just using WORKDIR as when WORKDIR creates, the
|
||||||
|
# user is root.
|
||||||
|
RUN mkdir -p /home/coder/project
|
||||||
|
|
||||||
|
WORKDIR /home/coder/project
|
||||||
|
|
||||||
|
# This ensures we have a volume mounted even if the user forgot to do bind
|
||||||
|
# mount. So that they do not lose their data if they delete the container.
|
||||||
|
VOLUME [ "/home/coder/project" ]
|
||||||
|
|
||||||
|
COPY --from=0 /src/binaries/code-server /usr/local/bin/code-server
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
ENTRYPOINT ["dumb-init", "code-server", "--host", "0.0.0.0"]
|
||||||
|
|||||||
189
README.md
@@ -1,74 +1,187 @@
|
|||||||
# code-server
|
# code-server · [](https://github.com/cdr/code-server/blob/master/LICENSE) [](https://github.com/cdr/code-server/releases/latest) [](https://github.com/cdr/code-server)
|
||||||
|
|
||||||
[](https://github.com/codercom/code-server/issues)
|
`code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a
|
||||||
[](https://github.com/codercom/code-server/releases/latest)
|
remote server, accessible through the browser.
|
||||||
[](#)
|
|
||||||
[](https://discord.gg/zxSwN8Z)
|
|
||||||
|
|
||||||
`code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a remote server, accessible through the browser.
|
|
||||||
|
|
||||||
Try it out:
|
Try it out:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -t -p 127.0.0.1:8443:8443 -v "${PWD}:/root/project" codercom/code-server code-server --allow-http --no-auth
|
docker run -it -p 127.0.0.1:8080:8080 -v "${HOME}/.local/share/code-server:/home/coder/.local/share/code-server" -v "$PWD:/home/coder/project" codercom/code-server:v2
|
||||||
```
|
```
|
||||||
|
|
||||||
- Code on your Chromebook, tablet, and laptop with a consistent dev environment.
|
- **Consistent environment:** Code on your Chromebook, tablet, and laptop with a
|
||||||
- If you have a Windows or Mac workstation, more easily develop for Linux.
|
consistent dev environment. develop more easily for Linux if you have a
|
||||||
- Take advantage of large cloud servers to speed up tests, compilations, downloads, and more.
|
Windows or Mac, and pick up where you left off when switching workstations.
|
||||||
- Preserve battery life when you're on the go.
|
- **Server-powered:** Take advantage of large cloud servers to speed up tests,
|
||||||
- All intensive computation runs on your server.
|
compilations, downloads, and more. Preserve battery life when you're on the go
|
||||||
- You're no longer running excess instances of Chrome.
|
since all intensive computation runs on your server.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
### Hosted
|
### Requirements
|
||||||
|
|
||||||
[Try `code-server` now](https://coder.com/signup) for free at coder.com.
|
- Minimum GLIBC version of 2.17 and a minimum version of GLIBCXX of 3.4.15.
|
||||||
|
- This is the main requirement for building Visual Studio Code. We cannot go lower than this.
|
||||||
|
- A 64-bit host with at least 1GB RAM and 2 cores.
|
||||||
|
- 1 core hosts would work but not optimally.
|
||||||
|
- Docker (for Docker versions of `code-server`).
|
||||||
|
|
||||||
|
### Run over SSH
|
||||||
|
|
||||||
|
Use [sshcode](https://github.com/codercom/sshcode) for a simple setup.
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
See docker oneliner mentioned above. Dockerfile is at [/Dockerfile](/Dockerfile).
|
See the Docker one-liner mentioned above. Dockerfile is at [/Dockerfile](/Dockerfile).
|
||||||
|
|
||||||
|
To debug Golang using the
|
||||||
|
[ms-vscode-go extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go),
|
||||||
|
you need to add `--security-opt seccomp=unconfined` to your `docker run`
|
||||||
|
arguments when launching code-server with Docker. See
|
||||||
|
[#725](https://github.com/cdr/code-server/issues/725) for details.
|
||||||
|
|
||||||
|
### Digital Ocean
|
||||||
|
|
||||||
|
[](https://marketplace.digitalocean.com/apps/code-server?action=deploy)
|
||||||
|
|
||||||
### Binaries
|
### Binaries
|
||||||
|
|
||||||
1. [Download a binary](https://github.com/codercom/code-server/releases) (Linux and OS X supported. Windows coming soon)
|
1. [Download a binary](https://github.com/cdr/code-server/releases). (Linux and
|
||||||
2. Start the binary with the project directory as the first argument
|
OS X supported. Windows coming soon)
|
||||||
|
2. Unpack the downloaded file then run the binary.
|
||||||
|
3. In your browser navigate to `localhost:8080`.
|
||||||
|
|
||||||
```
|
- For self-hosting and other information see [doc/quickstart.md](doc/quickstart.md).
|
||||||
code-server <initial directory to open>
|
- For hosting on cloud platforms see [doc/deploy.md](doc/deploy.md).
|
||||||
```
|
|
||||||
> You will be prompted to enter the password shown in the CLI
|
|
||||||
`code-server` should now be running at https://localhost:8443.
|
|
||||||
|
|
||||||
> code-server uses a self-signed SSL certificate that may prompt your browser to ask you some additional questions before you proceed. Please [read here](doc/self-hosted/index.md) for more information.
|
### Build
|
||||||
|
|
||||||
For detailed instructions and troubleshooting, see the [self-hosted quick start guide](doc/self-hosted/index.md).
|
See
|
||||||
|
[VS Code prerequisites](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites)
|
||||||
|
before building.
|
||||||
|
|
||||||
Quickstart guides for [Google Cloud](doc/admin/install/google_cloud.md), [AWS](doc/admin/install/aws.md), and [Digital Ocean](doc/admin/install/digitalocean.md).
|
```shell
|
||||||
|
export OUT=/path/to/output/build # Optional if only building. Required if also developing.
|
||||||
|
yarn build ${vscodeVersion} ${codeServerVersion} # See travis.yml for the VS Code version to use.
|
||||||
|
# The code-server version can be anything you want.
|
||||||
|
node ~/path/to/output/build/out/vs/server/main.js # You can run the built JavaScript with Node.
|
||||||
|
yarn binary ${vscodeVersion} ${codeServerVersion} # Or you can package it into a binary.
|
||||||
|
```
|
||||||
|
|
||||||
How to [secure your setup](/doc/security/ssl.md).
|
## Security
|
||||||
|
|
||||||
## Development
|
### Authentication
|
||||||
|
By default `code-server` enables password authentication using a randomly
|
||||||
|
generated password. You can set the `PASSWORD` environment variable to use your
|
||||||
|
own instead or use `--auth none` to disable password authentication.
|
||||||
|
|
||||||
### Known Issues
|
Do not expose `code-server` to the open internet without some form of
|
||||||
|
authentication.
|
||||||
|
|
||||||
|
### Encrypting traffic with HTTPS
|
||||||
|
If you aren't doing SSL termination elsewhere you can directly give
|
||||||
|
`code-server` a certificate with `code-server --cert` followed by the path to
|
||||||
|
your certificate. Additionally, you can use certificate keys with `--cert-key`
|
||||||
|
followed by the path to your key. If you pass `--cert` without any path
|
||||||
|
`code-server` will generate a self-signed certificate.
|
||||||
|
|
||||||
|
If `code-server` has been passed a certificate it will also respond to HTTPS
|
||||||
|
requests and will redirect all HTTP requests to HTTPS. Otherwise it will respond
|
||||||
|
only to HTTP requests.
|
||||||
|
|
||||||
|
You can use [Let's Encrypt](https://letsencrypt.org/) to get an SSL certificate
|
||||||
|
for free.
|
||||||
|
|
||||||
|
Do not expose `code-server` to the open internet without SSL, whether built-in
|
||||||
|
or through a proxy.
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
|
||||||
- Creating custom VS Code extensions and debugging them doesn't work.
|
- Creating custom VS Code extensions and debugging them doesn't work.
|
||||||
|
- Extension profiling and tips are currently disabled.
|
||||||
|
|
||||||
### Future
|
## Future
|
||||||
|
|
||||||
|
- **Stay up to date!** Get notified about new releases of code-server.
|
||||||
|

|
||||||
- Windows support.
|
- Windows support.
|
||||||
- Electron and Chrome OS applications to bridge the gap between local<->remote.
|
- Electron and Chrome OS applications to bridge the gap between local<->remote.
|
||||||
- Run VS Code unit tests against our builds to ensure features work as expected.
|
- Run VS Code unit tests against our builds to ensure features work as expected.
|
||||||
|
|
||||||
### Notes
|
## Extensions
|
||||||
|
|
||||||
- At the moment we can't use the official VSCode Marketplace. We've created a custom extension marketplace focused around open-sourced extensions. However, if you have access to the `.vsix` file, you can manually install the extension.
|
code-server does not provide access to the official
|
||||||
|
[Visual Studio Marketplace](https://marketplace.visualstudio.com/vscode). Instead,
|
||||||
|
Coder has created a custom extension marketplace that we manage for open-source
|
||||||
|
extensions. If you want to use an extension with code-server that we do not have
|
||||||
|
in our marketplace please look for a release in the extension’s repository,
|
||||||
|
contact us to see if we have one in the works or, if you build an extension
|
||||||
|
locally from open source, you can copy it to the `extensions` folder. If you
|
||||||
|
build one locally from open-source please contribute it to the project and let
|
||||||
|
us know so we can give you props! If you have your own custom marketplace, it is
|
||||||
|
possible to point code-server to it by setting the `SERVICE_URL` and `ITEM_URL`
|
||||||
|
environment variables.
|
||||||
|
|
||||||
|
## Telemetry
|
||||||
|
|
||||||
|
Use the `--disable-telemetry` flag to completely disable telemetry. We use the
|
||||||
|
data collected to improve code-server.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Development guides are coming soon.
|
### Development
|
||||||
|
|
||||||
|
See
|
||||||
|
[VS Code prerequisites](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#prerequisites)
|
||||||
|
before developing.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git clone https://github.com/microsoft/vscode
|
||||||
|
cd vscode
|
||||||
|
git checkout ${vscodeVersion} # See travis.yml for the version to use.
|
||||||
|
yarn
|
||||||
|
git clone https://github.com/cdr/code-server src/vs/server
|
||||||
|
cd src/vs/server
|
||||||
|
yarn
|
||||||
|
yarn patch:apply
|
||||||
|
yarn watch
|
||||||
|
# Wait for the initial compilation to complete (it will say "Finished compilation").
|
||||||
|
# Run the next command in another shell.
|
||||||
|
yarn start
|
||||||
|
# Visit http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
If you run into issues about a different version of Node being used, try running
|
||||||
|
`npm rebuild` in the VS Code directory and ignore the error at the end from
|
||||||
|
`vscode-ripgrep`.
|
||||||
|
|
||||||
|
### Upgrading VS Code
|
||||||
|
|
||||||
|
We patch VS Code to provide and fix some functionality. As the web portion of VS
|
||||||
|
Code matures, we'll be able to shrink and maybe even entirely eliminate our
|
||||||
|
patch. In the meantime, however, upgrading the VS Code version requires ensuring
|
||||||
|
that the patch still applies and has the intended effects.
|
||||||
|
|
||||||
|
To generate a new patch, **stage all the changes** you want to be included in
|
||||||
|
the patch in the VS Code source, then run `yarn patch:generate` in this
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Our changes include:
|
||||||
|
|
||||||
|
- Change the remote schema to `code-server`.
|
||||||
|
- Allow multiple extension directories (both user and built-in).
|
||||||
|
- Modify the loader, websocket, webview, service worker, and asset requests to
|
||||||
|
use the URL of the page as a base (and TLS if necessary for the websocket).
|
||||||
|
- Send client-side telemetry through the server.
|
||||||
|
- Add an upload service along with a file prefix to ignore for temporary files
|
||||||
|
created during upload.
|
||||||
|
- Make changing the display language work.
|
||||||
|
- Make it possible for us to load code on the client.
|
||||||
|
- Make extensions work in the browser.
|
||||||
|
- Fix getting permanently disconnected when you sleep or hibernate for a while.
|
||||||
|
- Make it possible to automatically update the binary.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
@@ -76,8 +189,10 @@ Development guides are coming soon.
|
|||||||
|
|
||||||
## Enterprise
|
## Enterprise
|
||||||
|
|
||||||
Visit [our enterprise page](https://coder.com/enterprise) for more information about our enterprise offering.
|
Visit [our enterprise page](https://coder.com/enterprise) for more information
|
||||||
|
about our enterprise offering.
|
||||||
|
|
||||||
## Commercialization
|
## Commercialization
|
||||||
|
|
||||||
If you would like to commercialize code-server, please contact contact@coder.com.
|
If you would like to commercialize code-server, please contact
|
||||||
|
contact@coder.com.
|
||||||
|
|||||||
258
build/tasks.ts
@@ -1,258 +0,0 @@
|
|||||||
import { register, run } from "@coder/runner";
|
|
||||||
import * as fs from "fs";
|
|
||||||
import * as fse from "fs-extra";
|
|
||||||
import * as os from "os";
|
|
||||||
import * as path from "path";
|
|
||||||
import * as zlib from "zlib";
|
|
||||||
|
|
||||||
const isWin = os.platform() === "win32";
|
|
||||||
const libPath = path.join(__dirname, "../lib");
|
|
||||||
const vscodePath = path.join(libPath, "vscode");
|
|
||||||
const pkgsPath = path.join(__dirname, "../packages");
|
|
||||||
const defaultExtensionsPath = path.join(libPath, "VSCode-linux-x64/resources/app/extensions");
|
|
||||||
const vscodeVersion = process.env.VSCODE_VERSION || "1.32.0";
|
|
||||||
|
|
||||||
const buildServerBinary = register("build:server:binary", async (runner) => {
|
|
||||||
await ensureInstalled();
|
|
||||||
await copyForDefaultExtensions();
|
|
||||||
await Promise.all([
|
|
||||||
buildBootstrapFork(),
|
|
||||||
buildWeb(),
|
|
||||||
buildDefaultExtensions(),
|
|
||||||
buildServerBundle(),
|
|
||||||
buildAppBrowser(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
await buildServerBinaryPackage();
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildServerBinaryPackage = register("build:server:binary:package", async (runner) => {
|
|
||||||
const cliPath = path.join(pkgsPath, "server");
|
|
||||||
runner.cwd = cliPath;
|
|
||||||
if (!fs.existsSync(path.join(cliPath, "out"))) {
|
|
||||||
throw new Error("Cannot build binary without server bundle built");
|
|
||||||
}
|
|
||||||
await buildServerBinaryCopy();
|
|
||||||
const resp = await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build:binary"]);
|
|
||||||
if (resp.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to package binary: ${resp.stderr}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildServerBinaryCopy = register("build:server:binary:copy", async (runner) => {
|
|
||||||
const cliPath = path.join(pkgsPath, "server");
|
|
||||||
const cliBuildPath = path.join(cliPath, "build");
|
|
||||||
fse.removeSync(cliBuildPath);
|
|
||||||
fse.mkdirpSync(path.join(cliBuildPath, "extensions"));
|
|
||||||
const bootstrapForkPath = path.join(pkgsPath, "vscode", "out", "bootstrap-fork.js");
|
|
||||||
const webOutputPath = path.join(pkgsPath, "web", "out");
|
|
||||||
const browserAppOutputPath = path.join(pkgsPath, "app", "browser", "out");
|
|
||||||
const nodePtyModule = path.join(pkgsPath, "protocol", "node_modules", "node-pty-prebuilt", "build", "Release", "pty.node");
|
|
||||||
const spdlogModule = path.join(pkgsPath, "protocol", "node_modules", "spdlog", "build", "Release", "spdlog.node");
|
|
||||||
let ripgrepPath = path.join(pkgsPath, "..", "lib", "vscode", "node_modules", "vscode-ripgrep", "bin", "rg");
|
|
||||||
if (isWin) {
|
|
||||||
ripgrepPath += ".exe";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fs.existsSync(nodePtyModule)) {
|
|
||||||
throw new Error("Could not find pty.node. Ensure all packages have been installed");
|
|
||||||
}
|
|
||||||
if (!fs.existsSync(spdlogModule)) {
|
|
||||||
throw new Error("Could not find spdlog.node. Ensure all packages have been installed");
|
|
||||||
}
|
|
||||||
if (!fs.existsSync(webOutputPath)) {
|
|
||||||
throw new Error("Web bundle must be built");
|
|
||||||
}
|
|
||||||
if (!fs.existsSync(defaultExtensionsPath)) {
|
|
||||||
throw new Error("Default extensions must be built");
|
|
||||||
}
|
|
||||||
if (!fs.existsSync(bootstrapForkPath)) {
|
|
||||||
throw new Error("Bootstrap fork must exist");
|
|
||||||
}
|
|
||||||
if (!fs.existsSync(ripgrepPath)) {
|
|
||||||
throw new Error("Ripgrep must exist");
|
|
||||||
}
|
|
||||||
fse.copySync(defaultExtensionsPath, path.join(cliBuildPath, "extensions"));
|
|
||||||
fs.writeFileSync(path.join(cliBuildPath, "bootstrap-fork.js.gz"), zlib.gzipSync(fs.readFileSync(bootstrapForkPath)));
|
|
||||||
const cpDir = (dir: string, subdir: "auth" | "unauth", rootPath: string): void => {
|
|
||||||
const stat = fs.statSync(dir);
|
|
||||||
if (stat.isDirectory()) {
|
|
||||||
const paths = fs.readdirSync(dir);
|
|
||||||
paths.forEach((p) => cpDir(path.join(dir, p), subdir, rootPath));
|
|
||||||
} else if (stat.isFile()) {
|
|
||||||
const newPath = path.join(cliBuildPath, "web", subdir, path.relative(rootPath, dir));
|
|
||||||
fse.mkdirpSync(path.dirname(newPath));
|
|
||||||
fs.writeFileSync(newPath + ".gz", zlib.gzipSync(fs.readFileSync(dir)));
|
|
||||||
} else {
|
|
||||||
// Nothing
|
|
||||||
}
|
|
||||||
};
|
|
||||||
cpDir(webOutputPath, "auth", webOutputPath);
|
|
||||||
cpDir(browserAppOutputPath, "unauth", browserAppOutputPath);
|
|
||||||
fse.mkdirpSync(path.join(cliBuildPath, "dependencies"));
|
|
||||||
fse.copySync(nodePtyModule, path.join(cliBuildPath, "dependencies", "pty.node"));
|
|
||||||
fse.copySync(spdlogModule, path.join(cliBuildPath, "dependencies", "spdlog.node"));
|
|
||||||
fse.copySync(ripgrepPath, path.join(cliBuildPath, "dependencies", "rg"));
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildServerBundle = register("build:server:bundle", async (runner) => {
|
|
||||||
const cliPath = path.join(pkgsPath, "server");
|
|
||||||
runner.cwd = cliPath;
|
|
||||||
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildBootstrapFork = register("build:bootstrap-fork", async (runner) => {
|
|
||||||
await ensureInstalled();
|
|
||||||
await ensurePatched();
|
|
||||||
|
|
||||||
const vscodePkgPath = path.join(pkgsPath, "vscode");
|
|
||||||
runner.cwd = vscodePkgPath;
|
|
||||||
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build:bootstrap-fork"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildAppBrowser = register("build:app:browser", async (runner) => {
|
|
||||||
await ensureInstalled();
|
|
||||||
|
|
||||||
const appPath = path.join(pkgsPath, "app/browser");
|
|
||||||
runner.cwd = appPath;
|
|
||||||
fse.removeSync(path.join(appPath, "out"));
|
|
||||||
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildWeb = register("build:web", async (runner) => {
|
|
||||||
await ensureInstalled();
|
|
||||||
await ensurePatched();
|
|
||||||
|
|
||||||
const webPath = path.join(pkgsPath, "web");
|
|
||||||
runner.cwd = webPath;
|
|
||||||
fse.removeSync(path.join(webPath, "out"));
|
|
||||||
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
const extDirPath = path.join("lib", "vscode-default-extensions");
|
|
||||||
const copyForDefaultExtensions = register("build:copy-vscode", async (runner) => {
|
|
||||||
if (!fs.existsSync(defaultExtensionsPath)) {
|
|
||||||
await ensureClean();
|
|
||||||
await ensureInstalled();
|
|
||||||
await new Promise((resolve, reject): void => {
|
|
||||||
fse.remove(extDirPath, (err) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
await new Promise((resolve, reject): void => {
|
|
||||||
fse.copy(vscodePath, extDirPath, (err) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const buildDefaultExtensions = register("build:default-extensions", async (runner) => {
|
|
||||||
if (!fs.existsSync(defaultExtensionsPath)) {
|
|
||||||
await copyForDefaultExtensions();
|
|
||||||
runner.cwd = extDirPath;
|
|
||||||
const resp = await runner.execute(isWin ? "npx.cmd" : "npx", [isWin ? "gulp.cmd" : "gulp", "vscode-linux-x64", "--max-old-space-size=32384"]);
|
|
||||||
if (resp.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to build default extensions: ${resp.stderr}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const ensureInstalled = register("vscode:install", async (runner) => {
|
|
||||||
await ensureCloned();
|
|
||||||
|
|
||||||
runner.cwd = vscodePath;
|
|
||||||
const install = await runner.execute(isWin ? "yarn.cmd" : "yarn", []);
|
|
||||||
if (install.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to install vscode dependencies: ${install.stderr}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const ensureCloned = register("vscode:clone", async (runner) => {
|
|
||||||
if (fs.existsSync(vscodePath)) {
|
|
||||||
await ensureClean();
|
|
||||||
} else {
|
|
||||||
fse.mkdirpSync(libPath);
|
|
||||||
runner.cwd = libPath;
|
|
||||||
const clone = await runner.execute("git", ["clone", "https://github.com/microsoft/vscode", "--branch", vscodeVersion, "--single-branch", "--depth=1"]);
|
|
||||||
if (clone.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to clone: ${clone.exitCode}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runner.cwd = vscodePath;
|
|
||||||
const checkout = await runner.execute("git", ["checkout", vscodeVersion]);
|
|
||||||
if (checkout.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to checkout: ${checkout.stderr}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const ensureClean = register("vscode:clean", async (runner) => {
|
|
||||||
runner.cwd = vscodePath;
|
|
||||||
|
|
||||||
const status = await runner.execute("git", ["status", "--porcelain"]);
|
|
||||||
if (status.stdout.trim() !== "") {
|
|
||||||
const clean = await runner.execute("git", ["clean", "-f", "-d", "-X"]);
|
|
||||||
if (clean.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to clean git repository: ${clean.stderr}`);
|
|
||||||
}
|
|
||||||
const removeUnstaged = await runner.execute("git", ["checkout", "--", "."]);
|
|
||||||
if (removeUnstaged.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to remove unstaged files: ${removeUnstaged.stderr}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const fetch = await runner.execute("git", ["fetch", "--prune"]);
|
|
||||||
if (fetch.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to fetch latest changes: ${fetch.stderr}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const ensurePatched = register("vscode:patch", async (runner) => {
|
|
||||||
if (!fs.existsSync(vscodePath)) {
|
|
||||||
throw new Error("vscode must be cloned to patch");
|
|
||||||
}
|
|
||||||
await ensureClean();
|
|
||||||
|
|
||||||
runner.cwd = vscodePath;
|
|
||||||
const patchPath = path.join(__dirname, "../scripts/vscode.patch");
|
|
||||||
const apply = await runner.execute("git", ["apply", "--unidiff-zero", patchPath]);
|
|
||||||
if (apply.exitCode !== 0) {
|
|
||||||
throw new Error(`Failed to apply patches: ${apply.stderr}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
register("package", async (runner, releaseTag) => {
|
|
||||||
if (!releaseTag) {
|
|
||||||
throw new Error("Please specify the release tag.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const releasePath = path.resolve(__dirname, "../release");
|
|
||||||
|
|
||||||
const archiveName = `code-server${releaseTag}-${os.platform()}-${os.arch()}`;
|
|
||||||
const archiveDir = path.join(releasePath, archiveName);
|
|
||||||
fse.removeSync(archiveDir);
|
|
||||||
fse.mkdirpSync(archiveDir);
|
|
||||||
|
|
||||||
const binaryPath = path.join(__dirname, `../packages/server/cli-${os.platform()}-${os.arch()}`);
|
|
||||||
const binaryDestination = path.join(archiveDir, "code-server");
|
|
||||||
fse.copySync(binaryPath, binaryDestination);
|
|
||||||
fs.chmodSync(binaryDestination, "755");
|
|
||||||
["README.md", "LICENSE"].forEach((fileName) => {
|
|
||||||
fse.copySync(path.resolve(__dirname, `../${fileName}`), path.join(archiveDir, fileName));
|
|
||||||
});
|
|
||||||
|
|
||||||
runner.cwd = releasePath;
|
|
||||||
await os.platform() === "linux"
|
|
||||||
? runner.execute("tar", ["-cvzf", `${archiveName}.tar.gz`, `${archiveName}`])
|
|
||||||
: runner.execute("zip", ["-r", `${archiveName}.zip`, `${archiveName}`]);
|
|
||||||
});
|
|
||||||
|
|
||||||
run();
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
# Deploy on AWS
|
|
||||||
|
|
||||||
This tutorial shows you how to deploy `code-server` on an EC2 AWS instance.
|
|
||||||
|
|
||||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. You can also try out the IDE on a container hosted [by Coder](http://coder.com/signup)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Deploy to EC2
|
|
||||||
|
|
||||||
### Use the AWS wizard
|
|
||||||
|
|
||||||
- Click **Launch Instance** from your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home).
|
|
||||||
- Select the Ubuntu Server 16.04 LTS (HVM), SSD Volume Type (`ami-0f9cf087c1f27d9b1)` at this time of writing)
|
|
||||||
- Select an appropriate instance size (we recommend t2.medium/large, depending on team size and number of repositories/languages enabled), then **Next: Configure Instance Details**
|
|
||||||
- Select **Next: ...** until you get to the **Configure Security Group** page, then add the default **HTTP** rule (port range "80", source "0.0.0.0/0, ::/0")
|
|
||||||
> Rules with source of 0.0.0.0/0 allow all IP addresses to access your instance. We recommend setting [security group rules](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html?icmpid=docs_ec2_console) to allow access from known IP addresses only.
|
|
||||||
- Click **Launch**
|
|
||||||
- You will be prompted to create a key pair
|
|
||||||
> A key pair consists of a public key that AWS stores, and a private key file that you store. Together, they allow you to connect to your instance securely. For Windows AMIs, the private key file is required to obtain the password used to log into your instance. For Linux AMIs, the private key file allows you to securely SSH into your instance.
|
|
||||||
- From the dropdown choose "create a new pair", give the key pair a name
|
|
||||||
- Click **Download Key Pair**
|
|
||||||
> This is necessary before you proceed. A `.pem` file will be downloaded. make sure you store is in a safe location because it can't be retrieved once we move on.
|
|
||||||
- Finally, click **Launch Instances**
|
|
||||||
---
|
|
||||||
### SSH Into EC2 Instance
|
|
||||||
- First head to your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home) and choose instances from the left panel
|
|
||||||
- In the description of your EC2 instance copy the public DNS (iPv4) address using the copy to clipboard button
|
|
||||||
- Open a terminal on your computer and use the following command to SSH into your EC2 instance
|
|
||||||
```
|
|
||||||
ssh -i "path/to/your/keypair.pem" ubuntu@(paste the public DNS here)
|
|
||||||
```
|
|
||||||
>example: `ssh -i "/Users/John/Downloads/TestInstance.pem" ubuntu@ec2-3-45-678-910.compute-1.amazonaws.co`
|
|
||||||
- You should see a prompt for your EC2 instance like so<img src="../../assets/aws_ubuntu.png">
|
|
||||||
- At this point it is time to download the `code-server` binary. We will of course want the linux version.
|
|
||||||
- Find the latest Linux release from this URL:
|
|
||||||
```
|
|
||||||
https://github.com/codercom/code-server/releases/latest
|
|
||||||
```
|
|
||||||
- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page):
|
|
||||||
```
|
|
||||||
wget https://github.com/codercom/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
|
||||||
```
|
|
||||||
- Extract the downloaded tar.gz file with this command, for example:
|
|
||||||
```
|
|
||||||
tar -xvzf code-server-{version}-linux-x64.tar.gz
|
|
||||||
```
|
|
||||||
- Navigate to extracted directory with this command:
|
|
||||||
```
|
|
||||||
cd code-server-{version}-linux-x64
|
|
||||||
```
|
|
||||||
- If you run into any permission errors, make the binary executable by running:
|
|
||||||
```
|
|
||||||
chmod +x code-server
|
|
||||||
```
|
|
||||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md)
|
|
||||||
- Finally, run
|
|
||||||
```
|
|
||||||
sudo ./code-server-linux -p 80
|
|
||||||
```
|
|
||||||
- When you visit the public IP for your AWS instance, you will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../../assets/chrome_warning.png">
|
|
||||||
- Then click **"proceed anyway"**<img src="../../assets/chrome_confirm.png">
|
|
||||||
|
|
||||||
> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed
|
|
||||||
|
|
||||||
> The `-p 80` flag is necessary in order to make the IDE accessible from the public IP of your instance (also available from the description in the instances page.
|
|
||||||
|
|
||||||
---
|
|
||||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
# Deploy on DigitalOcean
|
|
||||||
|
|
||||||
This tutorial shows you how to deploy `code-server` to a single node running on DigitalOcean.
|
|
||||||
|
|
||||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. You can also try out the IDE on a container hosted [by Coder](http://coder.com/signup)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Use the "Create Droplets" wizard
|
|
||||||
|
|
||||||
[Open your DigitalOcean dashboard](https://cloud.digitalocean.com/droplets/new) to create a new droplet
|
|
||||||
|
|
||||||
- **Choose an image -** Select the **Distributions** tab and then choose Ubuntu
|
|
||||||
- **Choose a size -** We recommend at least 4GB RAM and 2 CPU, more depending on team size and number of repositories/languages enabled.
|
|
||||||
- Launch your instance
|
|
||||||
- Open a terminal on your computer and SSH into your instance
|
|
||||||
> example: ssh root@203.0.113.0
|
|
||||||
- Once in the SSH session, visit code-server [releases page](https://github.com/codercom/code-server/releases/) and copy the link to the download for the latest linux release
|
|
||||||
- Find the latest Linux release from this URL:
|
|
||||||
```
|
|
||||||
https://github.com/codercom/code-server/releases/latest
|
|
||||||
```
|
|
||||||
- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page):
|
|
||||||
```
|
|
||||||
wget https://github.com/codercom/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
|
||||||
```
|
|
||||||
- Extract the downloaded tar.gz file with this command, for example:
|
|
||||||
```
|
|
||||||
tar -xvzf code-server-{version}-linux-x64.tar.gz
|
|
||||||
```
|
|
||||||
- Navigate to extracted directory with this command:
|
|
||||||
```
|
|
||||||
cd code-server-{version}-linux-x64
|
|
||||||
```
|
|
||||||
- If you run into any permission errors when attempting to run the binary:
|
|
||||||
```
|
|
||||||
chmod +x code-server
|
|
||||||
```
|
|
||||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../../security/ssl.md)
|
|
||||||
- Finally start the code-server
|
|
||||||
```
|
|
||||||
sudo ./code-server-linux -p 80
|
|
||||||
```
|
|
||||||
> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed
|
|
||||||
- When you visit the public IP for your Digital Ocean instance, you will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../../assets/chrome_warning.png">
|
|
||||||
- Then click **"proceed anyway"**<img src="../../assets/chrome_confirm.png">
|
|
||||||
|
|
||||||
---
|
|
||||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
# Deploy on Google Cloud
|
|
||||||
|
|
||||||
This tutorial shows you how to deploy `code-server` to a single node running on Google Cloud.
|
|
||||||
|
|
||||||
If you're just starting out, we recommend [installing code-server locally](../../self-hosted/index.md). It takes only a few minutes and lets you try out all of the features. You can also try out the IDE on a container hosted [by Coder](http://coder.com/signup)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Deploy to Google Cloud VM
|
|
||||||
> Pre-requisite: Please [set up Google Cloud SDK](https://cloud.google.com/sdk/docs/) on your local machine
|
|
||||||
|
|
||||||
- [Open your Google Cloud console](https://console.cloud.google.com/compute/instances) to create a new VM instance and click **Create Instance**
|
|
||||||
- Choose an appropriate machine type (we recommend 2 vCPU and 7.5 GB RAM, more depending on team size and number of repositories/languages enabled)
|
|
||||||
- Choose Ubuntu 16.04 LTS as your boot disk
|
|
||||||
- Check the boxes for **Allow HTTP traffic** and **Allow HTTPS traffic** in the **Firewall** section
|
|
||||||
- Create your VM, and **take note** of its public IP address.
|
|
||||||
- Copy the link to download the latest Linux binary from our [releases page](https://github.com/codercom/code-server/releases)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Final Steps
|
|
||||||
|
|
||||||
- SSH into your Google Cloud VM
|
|
||||||
```
|
|
||||||
gcloud compute ssh --zone [region] [instance name]
|
|
||||||
```
|
|
||||||
|
|
||||||
- Find the latest Linux release from this URL:
|
|
||||||
```
|
|
||||||
https://github.com/codercom/code-server/releases/latest
|
|
||||||
```
|
|
||||||
|
|
||||||
- Replace {version} in the following command with the version found on the releases page and run it (or just copy the download URL from the releases page):
|
|
||||||
```
|
|
||||||
wget https://github.com/codercom/code-server/releases/download/{version}/code-server-{version}-linux-x64.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
- Extract the downloaded tar.gz file with this command, for example:
|
|
||||||
```
|
|
||||||
tar -xvzf code-server-{version}-linux-x64.tar.gz
|
|
||||||
```
|
|
||||||
|
|
||||||
- Navigate to extracted directory with this command:
|
|
||||||
```
|
|
||||||
cd code-server-{version}-linux-x64
|
|
||||||
```
|
|
||||||
|
|
||||||
- Make the binary executable if you run into any errors regarding permission:
|
|
||||||
```
|
|
||||||
chmod +x code-server
|
|
||||||
```
|
|
||||||
|
|
||||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../security/ssl.md)
|
|
||||||
|
|
||||||
- Start the code-server
|
|
||||||
```
|
|
||||||
sudo ./code-server-linux -p 80
|
|
||||||
```
|
|
||||||
|
|
||||||
> For instructions on how to keep the server running after you end your SSH session please checkout [how to use systemd](https://www.linode.com/docs/quick-answers/linux/start-service-at-boot/) to start linux based services if they are killed
|
|
||||||
|
|
||||||
- Access code-server from the public IP of your Google Cloud instance we noted earlier in your browser.
|
|
||||||
> example: 32.32.32.234
|
|
||||||
|
|
||||||
- You will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../../assets/chrome_warning.png">
|
|
||||||
|
|
||||||
- Then click **"proceed anyway"**<img src="../../assets/chrome_confirm.png">
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
|
||||||
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 137 KiB |
24
doc/assets/droplet.svg
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="200px" height="40px" viewBox="0 0 200 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
|
||||||
|
<title>do-btn-blue-ghost</title>
|
||||||
|
<desc>Created with Sketch.</desc>
|
||||||
|
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||||
|
<g id="Partner-welcome-kit-Copy-3" transform="translate(-651.000000, -828.000000)">
|
||||||
|
<g id="do-btn-blue-ghost" transform="translate(651.000000, 828.000000)">
|
||||||
|
<rect id="Rectangle-Copy-4" stroke="#0069FF" x="0.5" y="0.5" width="199" height="39" rx="6"></rect>
|
||||||
|
<path d="M6,0 L47,0 L47,40 L6,40 C2.6862915,40 4.05812251e-16,37.3137085 0,34 L-8.8817842e-16,6 C-1.29399067e-15,2.6862915 2.6862915,6.08718376e-16 6,0 Z" id="Rectangle-Copy-5" fill="#0069FF"></path>
|
||||||
|
<g id="DO_Logo_horizontal_blue-Copy-3" transform="translate(13.000000, 10.000000)" fill="#FFFFFF">
|
||||||
|
<path d="M10.0098493,20 L10.0098493,16.1262429 C14.12457,16.1262429 17.2897398,12.0548452 15.7269372,7.74627862 C15.1334679,6.14538921 13.8674,4.86072487 12.2650328,4.28756693 C7.952489,2.72620566 3.87733294,5.88845634 3.87733294,9.99938223 C3.87733294,9.99938223 3.87733294,9.99938223 3.87733294,9.99938223 L0,9.99938223 C0,3.45747613 6.3303395,-1.64165309 13.1948014,0.492866119 C16.2017127,1.42177726 18.57559,3.81322933 19.5053586,6.79760341 C21.6418482,13.6754986 16.5577943,20 10.0098493,20 Z" id="XMLID_49_"></path>
|
||||||
|
<polygon id="XMLID_47_" points="9.52380952 16.1904762 5.71428571 16.1904762 5.71428571 12.3809524 5.71428571 12.3809524 9.52380952 12.3809524 9.52380952 12.3809524"></polygon>
|
||||||
|
<polygon id="XMLID_46_" points="6.66666667 19.047619 3.80952381 19.047619 3.80952381 19.047619 3.80952381 16.1904762 6.66666667 16.1904762"></polygon>
|
||||||
|
<polygon id="XMLID_45_" points="3.80952381 16.1904762 0.952380952 16.1904762 0.952380952 16.1904762 0.952380952 13.3333333 0.952380952 13.3333333 3.80952381 13.3333333 3.80952381 13.3333333"></polygon>
|
||||||
|
</g>
|
||||||
|
<!-- Modified to add GitHub font-family after DigitalOcean's font-family, otherwise it looks bad on GitHub -->
|
||||||
|
<text id="Create-a-Droplet-Copy-3" font-family="Sailec-Medium, Sailec, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol" font-size="16" font-weight="400" fill="#0069FF">
|
||||||
|
<tspan x="58" y="26">Create a Droplet</tspan>
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
BIN
doc/assets/ide.gif
Normal file
|
After Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 603 KiB |
|
Before Width: | Height: | Size: 18 KiB |
BIN
doc/assets/release.gif
Normal file
|
After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 58 KiB |
75
doc/cros-install.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# Installing code-server in your ChromiumOS/ChromeOS/CloudReady machine
|
||||||
|
|
||||||
|
This guide will show you how to install code-server into your CrOS machine.
|
||||||
|
|
||||||
|
## Using Crostini
|
||||||
|
|
||||||
|
One of the easier ways to run code-server is via
|
||||||
|
[Crostini](https://www.aboutchromebooks.com/tag/project-crostini/), the Linux
|
||||||
|
apps support feature in CrOS. Make sure you have enough RAM, HDD space and your
|
||||||
|
CPU has VT-x/ AMD-V support. If your chromebook has this, then you are
|
||||||
|
qualified to use Crostini.
|
||||||
|
|
||||||
|
If you are running R69, you might want to enable this on
|
||||||
|
[Chrome Flags](chrome://flags/#enable-experimental-crostini-ui).
|
||||||
|
If you run R72, however, this is already enabled for you.
|
||||||
|
|
||||||
|
After checking your prerequisites, follow the steps in [the self-host install guide](index.md)
|
||||||
|
on installing code-server. Once done, make sure code-server works by running
|
||||||
|
it. After running it, simply go to `penguin.linux.test:8080` to access
|
||||||
|
code-server. Now you should be greeted with this screen. If you did,
|
||||||
|
congratulations, you have installed code-server in your Chromebook!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Alternatively, if you ran code-server in another container and you need the IP
|
||||||
|
for that specific container, simply go to Termina's shell via `crosh` and type
|
||||||
|
`vsh termina`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Loading extra module: /usr/share/crosh/dev.d/50-crosh.sh
|
||||||
|
Welcome to crosh, the Chrome OS developer shell.
|
||||||
|
|
||||||
|
If you got here by mistake, don't panic! Just close this tab and carry on.
|
||||||
|
|
||||||
|
Type 'help' for a list of commands.
|
||||||
|
|
||||||
|
If you want to customize the look/behavior, you can use the options page.
|
||||||
|
Load it by using the Ctrl+Shift+P keyboard shortcut.
|
||||||
|
|
||||||
|
crosh> vsh termina
|
||||||
|
(termina) chronos@localhost ~ $
|
||||||
|
```
|
||||||
|
While in termina, run `lxc list`. It should output the list of running containers.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
(termina) chronos@localhost ~ $ lxc list
|
||||||
|
+---------|---------|-----------------------|------|------------|-----------+
|
||||||
|
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
|
||||||
|
+---------|---------|-----------------------|------|------------|-----------+
|
||||||
|
| penguin | RUNNING | 100.115.92.199 (eth0) | | PERSISTENT | 0 |
|
||||||
|
+---------|---------|-----------------------|------|------------|-----------+
|
||||||
|
(termina) chronos@localhost ~ $
|
||||||
|
```
|
||||||
|
|
||||||
|
For this example, we show the default `penguin` container, which is exposed on
|
||||||
|
`eth0` at 100.115.92.199. Simply enter the IP of the container where the
|
||||||
|
code-server runs to Chrome.
|
||||||
|
|
||||||
|
## Using Crouton
|
||||||
|
|
||||||
|
[Crouton](https://github.com/dnschneid/crouton) is one of the old ways to get a
|
||||||
|
running full Linux via `chroot` on a Chromebook. To use crouton, enable
|
||||||
|
developer mode and go to `crosh`. This time, run `shell`, which should drop you
|
||||||
|
to `bash`.
|
||||||
|
|
||||||
|
Make sure you downloaded `crouton`, if so, go ahead and run it under
|
||||||
|
`~/Downloads`. After installing your chroot container via crouton, go ahead and
|
||||||
|
enter `enter-chroot` to enter your container.
|
||||||
|
|
||||||
|
Follow the instructions set in [the self-host install guide](index.md) to
|
||||||
|
install code-server. After that is done, run `code-server` and verify it works
|
||||||
|
by going to `localhost:8080`.
|
||||||
|
|
||||||
|
> At this point in writing, `localhost` seems to work in this method. However,
|
||||||
|
> the author is not sure if it applies still to newer Chromebooks.
|
||||||
73
doc/deploy.md
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# Set up instance
|
||||||
|
## EC2 on AWS
|
||||||
|
- Click **Launch Instance** from your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home).
|
||||||
|
- Select the Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
|
||||||
|
- Select an appropriate instance size (we recommend t2.medium/large, depending
|
||||||
|
on team size and number of repositories/languages enabled), then
|
||||||
|
**Next: Configure Instance Details**.
|
||||||
|
- Select **Next: ...** until you get to the **Configure Security Group** page,
|
||||||
|
then add a **Custom TCP Rule** rule with port range set to `8080` and source
|
||||||
|
set to "Anywhere".
|
||||||
|
> Rules with source of 0.0.0.0/0 allow all IP addresses to access your
|
||||||
|
> instance. We recommend setting [security group rules](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html?icmpid=docs_ec2_console)
|
||||||
|
> to allow access from known IP addresses only.
|
||||||
|
- Click **Launch**.
|
||||||
|
- You will be prompted to create a key pair.
|
||||||
|
- From the dropdown choose "create a new pair", give the key pair a name.
|
||||||
|
- Click **Download Key Pair** and store the file in a safe place.
|
||||||
|
- Click **Launch Instances**.
|
||||||
|
- Head to your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home)
|
||||||
|
and choose instances from the left panel.
|
||||||
|
- In the description of your EC2 instance copy the public DNS (iPv4) address
|
||||||
|
using the copy to clipboard button.
|
||||||
|
- Open a terminal on your computer and SSH into your instance:
|
||||||
|
```
|
||||||
|
ssh -i ${path to key pair} ubuntu@${public address}
|
||||||
|
```
|
||||||
|
|
||||||
|
## DigitalOcean
|
||||||
|
[Open your DigitalOcean dashboard](https://cloud.digitalocean.com/droplets/new)
|
||||||
|
to create a new droplet
|
||||||
|
|
||||||
|
- **Choose an image -** Select the **Distributions** tab and then choose Ubuntu.
|
||||||
|
- **Choose a size -** We recommend at least 4GB RAM and 2 CPU, more depending
|
||||||
|
on team size and number of repositories/languages enabled.
|
||||||
|
- Launch your instance.
|
||||||
|
- Open a terminal on your computer and SSH into your instance:
|
||||||
|
```
|
||||||
|
ssh root@${instance ip}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Google Cloud
|
||||||
|
> Pre-requisite: Set up the [Google Cloud SDK](https://cloud.google.com/sdk/docs/)
|
||||||
|
> on your local machine
|
||||||
|
|
||||||
|
- [Open your Google Cloud console](https://console.cloud.google.com/compute/instances)
|
||||||
|
to create a new VM instance and click **Create Instance**.
|
||||||
|
- Choose an appropriate machine type (we recommend 2 vCPU and 7.5 GB RAM, more
|
||||||
|
depending on team size and number of repositories/languages enabled).
|
||||||
|
- Choose Ubuntu 16.04 LTS as your boot disk.
|
||||||
|
- Expand the "Management, security, disks, networking, sole tenancy" section,
|
||||||
|
go to the "Networking" tab, then under network tags add "code-server".
|
||||||
|
- Create your VM, and **take note** of its public IP address.
|
||||||
|
- Visit "VPC network" in the console and go to "Firewall rules". Create a new
|
||||||
|
firewall rule called "http-8080". Under "Target tags" add "code-server", and
|
||||||
|
under "Protocols and ports" tick "Specified protocols and ports" and "tcp".
|
||||||
|
Beside "tcp", add "8080", then create the rule.
|
||||||
|
- Open a terminal on your computer and SSH into your Google Cloud VM:
|
||||||
|
```
|
||||||
|
gcloud compute ssh --zone ${region} ${instance name}
|
||||||
|
```
|
||||||
|
# Run code-server
|
||||||
|
- Download the latest code-server release from the
|
||||||
|
[releases page](https://github.com/cdr/code-server/releases/latest)
|
||||||
|
to the instance, extract the file, then run the code-server binary:
|
||||||
|
```
|
||||||
|
wget https://github.com/cdr/code-server/releases/download/{version}/code-server{version}-linux-x64.tar.gz
|
||||||
|
tar -xvzf code-server{version}-linux-x64.tar.gz
|
||||||
|
cd code-server{version}-linux-x64
|
||||||
|
./code-server
|
||||||
|
```
|
||||||
|
- Open your browser and visit http://$public_ip:8080/ where `$public_ip` is
|
||||||
|
your instance's public IP address.
|
||||||
|
- For long-term use, set up a systemd service to run code-server.
|
||||||
15
doc/examples/fail2ban.conf
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Fail2Ban filter for code-server
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
|
||||||
|
failregex = ^INFO\s+Failed login attempt\s+{\"password\":\"(\\.|[^"])*\",\"remoteAddress\":\"<HOST>\"
|
||||||
|
|
||||||
|
# Use this instead for proxies (ensure the proxy is configured to send the
|
||||||
|
# X-Forwarded-For header).
|
||||||
|
# failregex = ^INFO\s+Failed login attempt\s+{\"password\":\"(\\.|[^"])*\",\"xForwardedFor\":\"<HOST>\"
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
|
datepattern = "timestamp":{EPOCH}}$
|
||||||
|
|
||||||
|
# Author: Dean Sheather
|
||||||
@@ -10,7 +10,7 @@ metadata:
|
|||||||
namespace: code-server
|
namespace: code-server
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- port: 8443
|
- port: 8080
|
||||||
name: https
|
name: https
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
selector:
|
selector:
|
||||||
@@ -26,7 +26,7 @@ metadata:
|
|||||||
provisioner: kubernetes.io/aws-ebs
|
provisioner: kubernetes.io/aws-ebs
|
||||||
parameters:
|
parameters:
|
||||||
type: gp2
|
type: gp2
|
||||||
fsType: ext4
|
fsType: ext4
|
||||||
---
|
---
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
@@ -58,11 +58,11 @@ spec:
|
|||||||
app: code-server
|
app: code-server
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- image: codercom/code-server
|
- image: codercom/code-server:v2
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
name: code-servery
|
name: code-servery
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8443
|
- containerPort: 8080
|
||||||
name: https
|
name: https
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: code-server-storage
|
- name: code-server-storage
|
||||||
@@ -71,4 +71,3 @@ spec:
|
|||||||
- name: code-server-storage
|
- name: code-server-storage
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: code-store
|
claimName: code-store
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ metadata:
|
|||||||
namespace: code-server
|
namespace: code-server
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- port: 8443
|
- port: 8080
|
||||||
name: https
|
name: https
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
selector:
|
selector:
|
||||||
@@ -35,9 +35,9 @@ spec:
|
|||||||
app: code-server
|
app: code-server
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- image: codercom/code-server
|
- image: codercom/code-server:v2
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
name: code-server
|
name: code-server
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8443
|
- containerPort: 8080
|
||||||
name: https
|
name: https
|
||||||
35
doc/fail2ban.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# Protecting code-server from bruteforce attempts
|
||||||
|
code-server outputs all failed login attempts, along with the IP address,
|
||||||
|
provided password, user agent and timestamp by default.
|
||||||
|
|
||||||
|
When using a reverse proxy such as Nginx or Apache, the remote address may
|
||||||
|
appear to be `127.0.0.1` or a similar address so `X-Forwarded-For` should be
|
||||||
|
used instead. Ensure that you are setting this value in your reverse proxy:
|
||||||
|
|
||||||
|
Nginx:
|
||||||
|
```
|
||||||
|
location / {
|
||||||
|
...
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Apache:
|
||||||
|
```
|
||||||
|
<VirtualEnv>
|
||||||
|
...
|
||||||
|
SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
|
||||||
|
...
|
||||||
|
</VirtualEnv>
|
||||||
|
```
|
||||||
|
|
||||||
|
It is extremely important that you ensure that your code-server instance is not
|
||||||
|
accessible from the internet (use localhost or block it in your firewall).
|
||||||
|
|
||||||
|
## Fail2Ban
|
||||||
|
Fail2Ban allows for automatically banning and logging repeated failed
|
||||||
|
authentication attempts for many applications through regex filters. A working
|
||||||
|
filter for code-server can be found in `./code-server.fail2ban.conf`. Once this
|
||||||
|
is installed and configured correctly, repeated failed login attempts should
|
||||||
|
automatically be banned from connecting to your server.
|
||||||
98
doc/quickstart.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# Quickstart Guide
|
||||||
|
1. Visit the [releases page](https://github.com/cdr/code-server/releases) and
|
||||||
|
download the latest binary for your operating system.
|
||||||
|
2. Unpack the downloaded file then run the binary.
|
||||||
|
3. In your browser navigate to `localhost:8080`.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Run `code-server --help` to view available options.
|
||||||
|
|
||||||
|
### Nginx Reverse Proxy
|
||||||
|
The trailing slashes are important.
|
||||||
|
|
||||||
|
```
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name code.example.com code.example.org;
|
||||||
|
location /some/path/ { # Or / if hosting at the root.
|
||||||
|
proxy_pass http://localhost:8080/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection upgrade;
|
||||||
|
proxy_set_header Accept-Encoding gzip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Apache Reverse Proxy
|
||||||
|
```
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName code.example.com
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteCond %{HTTP:Upgrade} =websocket [NC]
|
||||||
|
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]
|
||||||
|
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
|
||||||
|
RewriteRule /(.*) http://localhost:8080/$1 [P,L]
|
||||||
|
|
||||||
|
ProxyRequests off
|
||||||
|
ProxyPass / http://localhost:8080/ nocanon
|
||||||
|
ProxyPassReverse / http://localhost:8080/
|
||||||
|
</VirtualHost>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run automatically at startup
|
||||||
|
|
||||||
|
In some cases you might need to run code-server automatically once the host starts. You may use your local init service to do so.
|
||||||
|
|
||||||
|
#### Systemd
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=Code Server IDE
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=<USER>
|
||||||
|
EnvironmentFile=$HOME/.profile
|
||||||
|
WorkingDirectory=$HOME
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
ExecStart=<PATH TO BINARY> $(pwd)
|
||||||
|
|
||||||
|
StandardOutput=file:/var/log/code-server-output.log
|
||||||
|
StandardError=file:/var/log/code-server-error.log
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
#### OpenRC
|
||||||
|
|
||||||
|
```sh
|
||||||
|
#!/sbin/openrc-run
|
||||||
|
|
||||||
|
depend() {
|
||||||
|
after net-online
|
||||||
|
need net
|
||||||
|
}
|
||||||
|
|
||||||
|
supervisor=supervise-daemon
|
||||||
|
name="code-server"
|
||||||
|
command="/opt/cdr/code-server"
|
||||||
|
command_args=""
|
||||||
|
|
||||||
|
pidfile="/var/run/cdr.pid"
|
||||||
|
respawn_delay=5
|
||||||
|
|
||||||
|
set -o allexport
|
||||||
|
if [ -f /etc/environment ]; then source /etc/environment; fi
|
||||||
|
set +o allexport
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Kubernetes/Docker
|
||||||
|
|
||||||
|
Make sure you set your restart policy to always - this will ensure your container starts as the daemon starts.
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# Generate a self-signed certificate đź”’
|
|
||||||
|
|
||||||
code-server has the ability to secure your connection between client and server using SSL/TSL certificates. By default, the server will start with an unencrypted connection. We recommend Self-signed TLS/SSL certificates for personal use of code-server or within an organization.
|
|
||||||
|
|
||||||
This guide will show you how to create a self-signed certificate and start code-server using your certificate/key.
|
|
||||||
|
|
||||||
## TLS / HTTPS
|
|
||||||
|
|
||||||
You can specify any location that you want to save the certificate and key. In this example, we will navigate to the root directory, create a folder called `certs` and cd into it.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
mkdir ~/certs && cd ~/certs
|
|
||||||
```
|
|
||||||
|
|
||||||
If you don't already have a TLS certificate and key, you can generate them with the command below. They will be placed in `~/certs`
|
|
||||||
|
|
||||||
```shell
|
|
||||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ~/certs/MyKey.key -out ~/certs/MyCertificate.crt
|
|
||||||
```
|
|
||||||
|
|
||||||
You will be prompted to add some identifying information about your organization
|
|
||||||
```shell
|
|
||||||
You are about to be asked to enter information that will be incorporated
|
|
||||||
into your certificate request.
|
|
||||||
What you are about to enter is what is called a Distinguished Name or a DN.
|
|
||||||
There are quite a few fields but you can leave some blank
|
|
||||||
For some fields there will be a default value,
|
|
||||||
If you enter '.', the field will be left blank.
|
|
||||||
-----
|
|
||||||
Country Name (2 letter code) [AU]:US
|
|
||||||
State or Province Name (full name) [Some-State]:TX
|
|
||||||
Locality Name (eg, city) []:Austin
|
|
||||||
Organization Name (eg, company) [Coder Technologies]:Coder
|
|
||||||
Organizational Unit Name (eg, section) []:Docs
|
|
||||||
Common Name (e.g. server FQDN or YOUR name) []:hostname.example.com
|
|
||||||
Email Address []:admin@example.com
|
|
||||||
```
|
|
||||||
>If you already have a TLS certificate and key, you can simply reference them in the `--cert` and `--cert-key` flags when launching code-server
|
|
||||||
|
|
||||||
|
|
||||||
## Starting code-server with certificate and key
|
|
||||||
|
|
||||||
1. At the end of the path to your binary, add the following flags followed by the path to your certificate and key like so. Then press enter to run code-server.
|
|
||||||
```shell
|
|
||||||
./code-server --cert=~/certs/MyCertificate.crt --cert-key=~/certs/MyKey.key
|
|
||||||
```
|
|
||||||
2. After that you will be running a secure code-server.
|
|
||||||
|
|
||||||
> You will know your connection is secure if the lines `WARN No certificate specified. This could be insecure. WARN Documentation on securing your setup: https://coder.com/docs` no longer appear.
|
|
||||||
|
|
||||||
## Other options
|
|
||||||
|
|
||||||
For larger organizations you may wish to rely on a Certificate Authority as opposed to a self-signed certificate. For more information on generating free and open certificates for your site, please check out EFF's [certbot](https://certbot.eff.org/). Certbot is a cli to generate certificates using [LetsEncrypt](https://letsencrypt.org/).
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
# Installng code-server in your ChromiumOS/ChromeOS/CloudReady machine
|
|
||||||
|
|
||||||
This guide will show you how to install code-server into your CrOS machine.
|
|
||||||
|
|
||||||
## Using Crostini
|
|
||||||
|
|
||||||
One of the easier ways to run code-server is via [Crostini](https://www.aboutchromebooks.com/tag/project-crostini/), the Linux apps support feature in CrOS. Make sure you have enough RAM, HDD space and your CPU has VT-x/ AMD-V support. If your chromebook has this, then you are qualified to use Crostini.
|
|
||||||
|
|
||||||
If you are running R69, you might want to enable this on [Chrome Flags](chrome://flags/#enable-experimental-crostini-ui). If you run R72, however, this is already enabled for you.
|
|
||||||
|
|
||||||
After checking your prerequisites, follow the steps in [the self-host install guide](index.md) on installing code-server. Once done, make sure code-server works by running it. After running it, simply go to `penguin.linux.test:8443` to access code-server. Now you should be greeted with this screen. If you did, congratulations, you have installed code-server in your Chromebook!
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Alternatively, if you ran code-server in another container and you need the IP for that specific container, simply go to Termina's shell via `crosh` and type `vsh termina`.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
Loading extra module: /usr/share/crosh/dev.d/50-crosh.sh
|
|
||||||
Welcome to crosh, the Chrome OS developer shell.
|
|
||||||
|
|
||||||
If you got here by mistake, don't panic! Just close this tab and carry on.
|
|
||||||
|
|
||||||
Type 'help' for a list of commands.
|
|
||||||
|
|
||||||
If you want to customize the look/behavior, you can use the options page.
|
|
||||||
Load it by using the Ctrl+Shift+P keyboard shortcut.
|
|
||||||
|
|
||||||
crosh> vsh termina
|
|
||||||
(termina) chronos@localhost ~ $
|
|
||||||
```
|
|
||||||
While in termina, run `lxc list`. It should output the list of running containers.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
(termina) chronos@localhost ~ $ lxc list
|
|
||||||
+---------+---------+-----------------------+------+------------+-----------+
|
|
||||||
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
|
|
||||||
+---------+---------+-----------------------+------+------------+-----------+
|
|
||||||
| penguin | RUNNING | 100.115.92.199 (eth0) | | PERSISTENT | 0 |
|
|
||||||
+---------+---------+-----------------------+------+------------+-----------+
|
|
||||||
(termina) chronos@localhost ~ $
|
|
||||||
```
|
|
||||||
|
|
||||||
For this example, we show the default `penguin` container, which is exposed on `eth0` at 100.115.92.199. Simply enter the IP of the container where the code-server runs to Chrome.
|
|
||||||
|
|
||||||
## Using Crouton
|
|
||||||
|
|
||||||
[Crouton](https://github.com/dnschneid/crouton) is one of the old ways to get a running full Linux via `chroot` on a Chromebook. To use crouton, enable developer mode and go to `crosh`. This time, run `shell`, which should drop you to `bash`.
|
|
||||||
|
|
||||||
Make sure you downloaded `crouton`, if so, go ahead and run it under `~/Downloads`. After installing your chroot container via crouton, go ahead and enter `enter-chroot` to enter your container.
|
|
||||||
|
|
||||||
Follow the instructions set in [the self-host install guide](index.md) to install code-server. After that is done, run `code-server` and verify it works by going to `localhost:8443`.
|
|
||||||
|
|
||||||
> At this point in writing, `localhost` seems to work in this method. However, the author is not sure if it applies still to newer Chromebooks.
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
# Getting Started
|
|
||||||
|
|
||||||
[code-server](https://coder.com) is used by developers at Azure, Google, Reddit, and more to give them access to VS Code in the browser.
|
|
||||||
|
|
||||||
## Quickstart Guide
|
|
||||||
|
|
||||||
> NOTE: If you get stuck or need help, [file an issue](https://github.com/codercom/code-server/issues/new?&title=Improve+self-hosted+quickstart+guide), [tweet (@coderhq)](https://twitter.com/coderhq) or [email](mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide).
|
|
||||||
|
|
||||||
This document pertains to Coder specific implementations of VS Code. For documentation on how to use VS Code itself, please refer to the official [documentation for VS Code](https://code.visualstudio.com/docs)
|
|
||||||
|
|
||||||
It takes just a few minutes to get your own self-hosted server running. If you've got a machine running macOS, Windows, or Linux, you're ready to start the binary which listens on port `8443` by default.
|
|
||||||
|
|
||||||
<!--
|
|
||||||
DO NOT CHANGE THIS TO A CODEBLOCK.
|
|
||||||
We want line breaks for readability, but backslashes to escape them do not work cross-platform.
|
|
||||||
This uses line breaks that are rendered but not copy-pasted to the clipboard.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
1. Visit [the releases](https://github.com/codercom/code-server/releases) page and download the latest cli for your operating system
|
|
||||||
2. Double click the executable to run in the current directory
|
|
||||||
3. Copy the password that appears in the cli<img src="../assets/cli.png">
|
|
||||||
4. In your browser navigate to `localhost:8443`
|
|
||||||
5. Paste the password from the cli into the login window<img src="../assets/server-password-modal.png">
|
|
||||||
> NOTE: Be careful with your password as sharing it will grant those users access to your server's file system
|
|
||||||
|
|
||||||
### Things To Know
|
|
||||||
- When you visit the IP for your code-server, you will be greeted with this page. Code-server is using a self-signed SSL certificate for easy setup. To proceed to the IDE, click **"Advanced"**<img src ="../assets/chrome_warning.png">
|
|
||||||
- Then click **"proceed anyway"**<img src="../assets/chrome_confirm.png">
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
<pre class="pre-wrap"><code>code-server<span class="virtual-br"></span> --help</code></pre>
|
|
||||||
|
|
||||||
code-server can be ran with a number of arguments to customize your working directory, host, port, and SSL certificate.
|
|
||||||
|
|
||||||
```
|
|
||||||
USAGE
|
|
||||||
$ code-server [WORKDIR]
|
|
||||||
|
|
||||||
ARGUMENTS
|
|
||||||
WORKDIR [default: (directory to binary)] Specify working dir
|
|
||||||
|
|
||||||
OPTIONS
|
|
||||||
-d, --data-dir=data-dir
|
|
||||||
-h, --host=host [default: 0.0.0.0]
|
|
||||||
-o, --open Open in browser on startup
|
|
||||||
-p, --port=port [default: 8443] Port to bind on
|
|
||||||
-v, --version show CLI version
|
|
||||||
--allow-http
|
|
||||||
--cert=cert
|
|
||||||
--cert-key=cert-key
|
|
||||||
--help show CLI help
|
|
||||||
--no-auth
|
|
||||||
--password=password
|
|
||||||
```
|
|
||||||
|
|
||||||
### Data Directory
|
|
||||||
Use `code-server -d (path/to/directory)` or `code-server --data-dir=(path/to/directory)`, excluding the parentheses to specify the root folder that VS Code will start in
|
|
||||||
|
|
||||||
### Host
|
|
||||||
By default, code-server will use `0.0.0.0` as its address. This can be changed by using `code-server -h` or `code-server --host=` followed by the address you want to use.
|
|
||||||
> Example: `code-server -h 127.0.0.1`
|
|
||||||
|
|
||||||
### Open
|
|
||||||
You can have the server automatically open the VS Code in your browser on startup by using the `code server -o` or `code-server --open` flags
|
|
||||||
|
|
||||||
### Port
|
|
||||||
By default, code-server will use `8443` as its port. This can be changed by using `code-server -p` or `code-server --port=` followed by the port you want to use.
|
|
||||||
> Example: `code-server -p 9000`
|
|
||||||
|
|
||||||
### Cert and Cert Key
|
|
||||||
To encrypt the traffic between the browser and server use `code-server --cert=` followed by the path to your `.cer` file. Additionally, you can use certificate keys with `code-server --cert-key` followed by the path to your `.key` file.
|
|
||||||
> Example (certificate and key): `code-server --cert /etc/letsencrypt/live/example.com/fullchain.cer --cert-key /etc/letsencrypt/live/example.com/fullchain.key`
|
|
||||||
|
|
||||||
> To ensure the connection between you and your server is encrypted view our guide on [securing your setup](../security/ssl.md)
|
|
||||||
|
|
||||||
### Nginx Reverse Proxy
|
|
||||||
Nginx is for reverse proxy. Below is a virtual host example that works with code-server. Please also pass --allow-http. You can also use certbot by EFF to get a ssl certificates for free.
|
|
||||||
```
|
|
||||||
server {
|
|
||||||
listen 80;
|
|
||||||
listen [::]:80;
|
|
||||||
server_name code.example.com code.example.org;
|
|
||||||
location / {
|
|
||||||
proxy_pass http://localhost:8443/;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection upgrade;
|
|
||||||
proxy_set_header Accept-Encoding gzip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Apache Reverse Proxy
|
|
||||||
Example of https virtualhost configuration for Apache as a reverse proxy. Please also pass --allow-http on code-server startup to allow the proxy to connect.
|
|
||||||
```
|
|
||||||
<VirtualHost *:80>
|
|
||||||
ServerName code.example.com
|
|
||||||
|
|
||||||
RewriteEngine On
|
|
||||||
RewriteCond %{HTTP:Upgrade} =websocket [NC]
|
|
||||||
RewriteRule /(.*) ws://localhost:8443/$1 [P,L]
|
|
||||||
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
|
|
||||||
RewriteRule /(.*) http://localhost:8443/$1 [P,L]
|
|
||||||
|
|
||||||
ProxyRequests off
|
|
||||||
|
|
||||||
RequestHeader set X-Forwarded-Proto https
|
|
||||||
RequestHeader set X-Forwarded-Port 443
|
|
||||||
|
|
||||||
ProxyPass / http://localhost:8443/ nocanon
|
|
||||||
ProxyPassReverse / http://localhost:8443/
|
|
||||||
|
|
||||||
</VirtualHost>
|
|
||||||
```
|
|
||||||
*Important:* For more details about Apache reverse proxy configuration checkout the [documentation](https://httpd.apache.org/docs/current/mod/mod_proxy.html) - especially the [Securing your Server](https://httpd.apache.org/docs/current/mod/mod_proxy.html#access) section
|
|
||||||
|
|
||||||
### Help
|
|
||||||
Use `code-server -h` or `code-server --help` to view the usage for the cli. This is also shown at the beginning of this section.
|
|
||||||
13
docker-compose.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
version: "3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
code-server:
|
||||||
|
container_name: code-server
|
||||||
|
image: codercom/code-server
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- "${PWD}:/home/coder/project"
|
||||||
|
- "${HOME}/.local/share/code-server:/home/coder/.local/share/code-server"
|
||||||
|
environment:
|
||||||
|
PASSWORD: ${PASSWORD}
|
||||||
7
main.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Once our entry file is loaded we no longer need nbin to bypass normal Node
|
||||||
|
// execution. We can still shim the fs into the binary even when bypassing. This
|
||||||
|
// will ensure for example that a spawn like `${process.argv[0]} -e` will work
|
||||||
|
// while still allowing us to access files within the binary.
|
||||||
|
process.env.NBIN_BYPASS = true;
|
||||||
|
|
||||||
|
require("../../bootstrap-amd").load("vs/server/src/node/cli");
|
||||||
81
package.json
@@ -1,58 +1,41 @@
|
|||||||
{
|
{
|
||||||
"name": "@coder/code-server",
|
|
||||||
"repository": "https://github.com/codercom/code-server",
|
|
||||||
"author": "Coder",
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "Run VS Code remotely.",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:rules": "cd ./rules && tsc -p .",
|
"runner": "cd ./scripts && node --max-old-space-size=32384 -r ts-node/register ./build.ts",
|
||||||
"packages:install": "cd ./packages && yarn",
|
"start": "nodemon --watch ../../../out --verbose ../../../out/vs/server/main.js",
|
||||||
"postinstall": "npm-run-all --parallel packages:install build:rules",
|
"watch": "cd ../../../ && yarn watch",
|
||||||
"start": "cd ./packages/server && yarn start",
|
"build": "yarn && yarn runner build",
|
||||||
"task": "ts-node -r tsconfig-paths/register build/tasks.ts",
|
"package": "yarn runner package",
|
||||||
"test": "cd ./packages && yarn test"
|
"binary": "yarn runner binary",
|
||||||
|
"patch:generate": "cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch",
|
||||||
|
"patch:apply": "cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/fs-extra": "^5.0.4",
|
"@coder/nbin": "^1.2.2",
|
||||||
"@types/node": "^10.12.18",
|
"@types/fs-extra": "^8.0.1",
|
||||||
"@types/trash": "^4.3.1",
|
"@types/node": "^10.12.12",
|
||||||
"cross-env": "^5.2.0",
|
"@types/pem": "^1.9.5",
|
||||||
"crypto-browserify": "^3.12.0",
|
"@types/safe-compare": "^1.1.0",
|
||||||
"css-loader": "^2.1.0",
|
"@types/tar-fs": "^1.16.1",
|
||||||
"file-loader": "^3.0.1",
|
"@types/tar-stream": "^1.6.1",
|
||||||
"fork-ts-checker-webpack-plugin": "^0.5.2",
|
"fs-extra": "^8.1.0",
|
||||||
"fs-extra": "^7.0.1",
|
"nodemon": "^1.19.1",
|
||||||
"happypack": "^5.0.1",
|
"ts-node": "^8.4.1",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"typescript": "3.6"
|
||||||
"http-browserify": "^1.7.0",
|
},
|
||||||
"ignore-loader": "^0.1.2",
|
"resolutions": {
|
||||||
"mini-css-extract-plugin": "^0.5.0",
|
"@types/node": "^10.12.12",
|
||||||
"node-sass": "^4.11.0",
|
"safe-buffer": "^5.1.1"
|
||||||
"npm-run-all": "^4.1.5",
|
|
||||||
"path-browserify": "^1.0.0",
|
|
||||||
"preload-webpack-plugin": "^3.0.0-beta.2",
|
|
||||||
"sass-loader": "^7.1.0",
|
|
||||||
"string-replace-loader": "^2.1.1",
|
|
||||||
"style-loader": "^0.23.1",
|
|
||||||
"ts-loader": "^5.3.3",
|
|
||||||
"ts-node": "^7.0.1",
|
|
||||||
"tsconfig-paths": "^3.8.0",
|
|
||||||
"tslib": "^1.9.3",
|
|
||||||
"tslint": "^5.12.1",
|
|
||||||
"typescript": "^3.2.2",
|
|
||||||
"typescript-tslint-plugin": "^0.2.1",
|
|
||||||
"uglifyjs-webpack-plugin": "^2.1.1",
|
|
||||||
"util": "^0.11.1",
|
|
||||||
"webpack": "^4.28.4",
|
|
||||||
"webpack-bundle-analyzer": "^3.0.3",
|
|
||||||
"webpack-cli": "^3.2.1",
|
|
||||||
"webpack-dev-middleware": "^3.5.0",
|
|
||||||
"webpack-dev-server": "^3.1.14",
|
|
||||||
"webpack-hot-middleware": "^2.24.3",
|
|
||||||
"write-file-webpack-plugin": "^4.5.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-loader": "^0.6.0",
|
"@coder/logger": "^1.1.8",
|
||||||
"webpack-merge": "^4.2.1"
|
"@coder/node-browser": "^1.0.6",
|
||||||
|
"@coder/requirefs": "^1.0.6",
|
||||||
|
"httpolyglot": "^0.1.2",
|
||||||
|
"pem": "^1.14.2",
|
||||||
|
"safe-compare": "^1.1.4",
|
||||||
|
"tar-fs": "^2.0.0",
|
||||||
|
"tar-stream": "^2.1.0",
|
||||||
|
"util": "^0.12.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@coder/app",
|
|
||||||
"scripts": {
|
|
||||||
"start": "node ../../../node_modules/webpack-dev-server/bin/webpack-dev-server.js --config ./webpack.config.js",
|
|
||||||
"build": "node ../../../node_modules/webpack/bin/webpack.js --config ./webpack.config.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@material/checkbox": "^0.44.1",
|
|
||||||
"@material/textfield": "^0.44.1",
|
|
||||||
"material-components-web": "^0.44.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
|
|
||||||
<title>Authenticate: code-server</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="login">
|
|
||||||
<div class="back"> <- Back </div>
|
|
||||||
<h4 class="title">code-server</h4>
|
|
||||||
<h2 class="subtitle">
|
|
||||||
Enter server password
|
|
||||||
</h2>
|
|
||||||
<div class="mdc-text-field">
|
|
||||||
<input type="password" id="password" class="mdc-text-field__input" required>
|
|
||||||
<label class="mdc-floating-label" for="password">Password</label>
|
|
||||||
<div class="mdc-line-ripple"></div>
|
|
||||||
</div>
|
|
||||||
<button id="submit" class="mdc-button mdc-button--unelevated">
|
|
||||||
<span class="mdc-button__label">Enter IDE</span>
|
|
||||||
</button>
|
|
||||||
<div id="error-display"></div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
@import url("https://use.typekit.net/vzk7ygg.css");
|
|
||||||
|
|
||||||
html, body {
|
|
||||||
background-color: #FFFFFF;
|
|
||||||
min-height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: 'aktiv-grotesk';
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: calc(100vh - 20px);
|
|
||||||
margin: 0;
|
|
||||||
padding: 10px;
|
|
||||||
--mdc-theme-primary: #AAADA1;
|
|
||||||
--mdc-theme-secondary: #AAADA1;
|
|
||||||
|
|
||||||
&.in-app {
|
|
||||||
.back {
|
|
||||||
pointer-events: all;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.login {
|
|
||||||
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
|
|
||||||
max-width: 328px;
|
|
||||||
width: 100%;
|
|
||||||
padding: 40px;
|
|
||||||
border-radius: 5px;
|
|
||||||
position: relative;
|
|
||||||
color: #575962;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
margin-bottom: 0px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
letter-spacing: 1.5px;
|
|
||||||
line-height: 15px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
margin-top: 0px;
|
|
||||||
text-align: center;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.subtitle {
|
|
||||||
text-align: center;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 19px;
|
|
||||||
font-weight: bold;
|
|
||||||
line-height: 25px;
|
|
||||||
margin-bottom: 45px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdc-text-field {
|
|
||||||
width: 100%;
|
|
||||||
background: none !important;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
background: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdc-form-field {
|
|
||||||
text-align: left;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #797E84;
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdc-button {
|
|
||||||
border-radius: 24px;
|
|
||||||
padding-left: 75px;
|
|
||||||
padding-right: 75px;
|
|
||||||
padding-top: 15px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
height: 48px;
|
|
||||||
margin: 0 auto;
|
|
||||||
display: block;
|
|
||||||
box-shadow: 0 12px 17px 2px rgba(171,173,163,0.14), 0 5px 22px 4px rgba(171,173,163,0.12), 0 7px 8px -4px rgba(171,173,163,0.2);
|
|
||||||
margin-top: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label {
|
|
||||||
color: var(--mdc-theme-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdc-floating-label--float-above {
|
|
||||||
transform: translateY(-70%) scale(0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdc-text-field:not(.mdc-text-field--disabled):not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mdc-text-field__input, .mdc-text-field:not(.mdc-text-field--disabled):not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mdc-text-field__input:hover {
|
|
||||||
border-bottom-color: #EBEDF2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back {
|
|
||||||
position: absolute;
|
|
||||||
top: -50px;
|
|
||||||
left: -50px;
|
|
||||||
font-weight: bold;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
// transition: 500ms opacity ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
#error-display {
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: #bb2d0f;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
line-height: 12px;
|
|
||||||
padding: 8px;
|
|
||||||
padding-bottom: 0;
|
|
||||||
padding-top: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
//@ts-ignore
|
|
||||||
import { MDCTextField } from "@material/textfield";
|
|
||||||
//@ts-ignore
|
|
||||||
import { MDCCheckbox } from "@material/checkbox";
|
|
||||||
import "material-components-web/dist/material-components-web.css";
|
|
||||||
import "./app.scss";
|
|
||||||
|
|
||||||
document.querySelectorAll(".mdc-text-field").forEach((d) => new MDCTextField(d));
|
|
||||||
document.querySelectorAll(".mdc-checkbox").forEach((d) => new MDCCheckbox(d));
|
|
||||||
|
|
||||||
window.addEventListener("message", (event) => {
|
|
||||||
if (event.data === "app") {
|
|
||||||
document.body.classList.add("in-app");
|
|
||||||
|
|
||||||
const back = document.querySelector(".back")!;
|
|
||||||
back.addEventListener("click", () => {
|
|
||||||
(event.source as Window).postMessage("back", event.origin);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const password = document.getElementById("password") as HTMLInputElement;
|
|
||||||
const submit = document.getElementById("submit") as HTMLButtonElement;
|
|
||||||
if (!submit) {
|
|
||||||
throw new Error("No submit button found");
|
|
||||||
}
|
|
||||||
submit.addEventListener("click", () => {
|
|
||||||
document.cookie = `password=${password.value}`;
|
|
||||||
location.reload();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notify user on load of page if previous password was unsuccessful
|
|
||||||
*/
|
|
||||||
const reg = new RegExp(`password=(\\w+);?`);
|
|
||||||
const matches = document.cookie.match(reg);
|
|
||||||
const errorDisplay = document.getElementById("error-display") as HTMLDivElement;
|
|
||||||
|
|
||||||
if (document.referrer === document.location.href && matches) {
|
|
||||||
errorDisplay.innerText = "Password is incorrect!";
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const merge = require("webpack-merge");
|
|
||||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
||||||
|
|
||||||
const root = path.resolve(__dirname, "../../..");
|
|
||||||
|
|
||||||
module.exports = merge(
|
|
||||||
require(path.join(root, "scripts/webpack.client.config.js"))({
|
|
||||||
entry: path.join(root, "packages/app/browser/src/app.ts"),
|
|
||||||
template: path.join(root, "packages/app/browser/src/app.html"),
|
|
||||||
}), {
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, "out"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
@@ -1,606 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
"@material/animation@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/animation/-/animation-0.41.0.tgz#315b45b32e1aeebee8a4cf555b8ad52076d09ddd"
|
|
||||||
integrity sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==
|
|
||||||
|
|
||||||
"@material/auto-init@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/auto-init/-/auto-init-0.41.0.tgz#8a59bb0b83e0f51ead9508074f9a29b2b6a20eec"
|
|
||||||
integrity sha512-jp6L8MpYu7DudgDfA8iTyD9BwQrYPEDsIJGbqzN9vcCBl5FoBatkB8pcFXKr+1mRBk7T1Qmf6+H5nDtxyXjHEQ==
|
|
||||||
|
|
||||||
"@material/base@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/base/-/base-0.41.0.tgz#badadce711b4c25b1eb889a5e7581e32cd07c421"
|
|
||||||
integrity sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==
|
|
||||||
|
|
||||||
"@material/button@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/button/-/button-0.44.0.tgz#f01dcbea88bdc314e7640b76e5558101c8b4d69d"
|
|
||||||
integrity sha512-T8u8s8rlB49D9/5Nh5b0XsKRgSq3X0yWGo71MgaTnCnwxt8oZ6PxW/cH6Nn3Xp0NCr3mlSVQs08BviUfAmtlsg==
|
|
||||||
dependencies:
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/feature-targeting" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/card@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/card/-/card-0.44.0.tgz#e62050e3e77f525173a015119200055cd7b71bf0"
|
|
||||||
integrity sha512-fUixXuh133bVp5c1gPIHreL5jwMJEeVIQf0E4xdxhkA+i4ku8fIAvIW62EuCmfJsXicv4q8NG3Ip6pCY+NW3ZA==
|
|
||||||
dependencies:
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/checkbox@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.44.0.tgz#5d0eee1db006db9f0fb700bf1c20408292305cf7"
|
|
||||||
integrity sha512-IzucxG+NuPNyByGmHg/cuYJ5ooMKouuj994PZXZyqb7owfrjjtXm7wjav66cvCowbVbcoa1owQMGBi18C9f4TQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/checkbox@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.44.1.tgz#7e69271ccab7c57914a475da3a15d4d36702c1c4"
|
|
||||||
integrity sha512-RFUNc+9RKRozL+gXfJ8V57tXfC31Q9R9tRMTHpe62NXZriTrwNJDnSkFIERDXqtMGtkKUnIlPfPE5znF6XyPUw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/feature-targeting" "^0.44.1"
|
|
||||||
"@material/ripple" "^0.44.1"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/selection-control" "^0.44.1"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/chips@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/chips/-/chips-0.44.0.tgz#bf553a5bf5db7320978402ac92069c9688b84d5a"
|
|
||||||
integrity sha512-+qrme6sGwYmX/ixHAo3Z1M7lorsxRyKexn1l+BSBX5PBc2f4w5Ml1eYYYcyVGfLX9LXmefRk0G6dUXXPyCE00g==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/checkbox" "^0.44.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/dialog@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/dialog/-/dialog-0.44.0.tgz#388f93f9f225824c75cbe9da8c464a52d79972e8"
|
|
||||||
integrity sha512-V6ButfknOMKOscL0Y39yLjamxvrIuyugobjf5s44ZeJc+9jUSkC7M3zP+T7rh358NcX+JSPP8iCGmUn/+LXpMQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/dom" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
focus-trap "^4.0.2"
|
|
||||||
|
|
||||||
"@material/dom@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/dom/-/dom-0.41.0.tgz#6756865f97bad4c91ee75e69d769d7cdc25398ae"
|
|
||||||
integrity sha512-wOJrMwjPddYXpQFZAIaCLWI3TO/6KU1lxESTBzunni8A4FHQVWhokml5Xt85GqZwmPFeIF2s+D0wfbWyrGBuKQ==
|
|
||||||
|
|
||||||
"@material/drawer@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/drawer/-/drawer-0.44.0.tgz#74b3ddfb741bffc72331c7a73cf62716fd3f0ab3"
|
|
||||||
integrity sha512-AYwFe0jgqqSmJd1bny8JJTA2SScF86Wfbk99lXXEwd/acS8IbnnuH6zfAg6MyJX12FDb8dE8Z/Ok1IwLiVa9sQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/list" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
focus-trap "^4.0.2"
|
|
||||||
|
|
||||||
"@material/elevation@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/elevation/-/elevation-0.44.0.tgz#ca16a67188ce9810dc2fa3d7a39073e72df4b754"
|
|
||||||
integrity sha512-edNou34yFCSMb6XXe/6Y7AEh8DigWAhBUyIeMiMBD4k1km2xYCJbcnl8FBPJFteOrca97KoJComRlJPB6EurRQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/fab@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/fab/-/fab-0.44.0.tgz#0bcbbdfb6f24c53d59e08c9c0d400d2616dea184"
|
|
||||||
integrity sha512-1CEP4NlXDYioJ/YpSjh/MlIygtoC7CaHqIbucxX1O5WRPmS7K1uPt+o7netbLErAmcJdV/JrI/tqh9kKuX2x/Q==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/feature-targeting@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-0.44.0.tgz#52cc73f0c8a83159de0357aebe74f15f9856fb4c"
|
|
||||||
integrity sha512-ShuC2TOLfjFpYUCQFtvkqDJhM6HTaucSx5HkRbOvOG+VlpzDx6pAqRUmdVaq2p7tHoQf2vwPMlSVm3gOjWt4VQ==
|
|
||||||
|
|
||||||
"@material/feature-targeting@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-0.44.1.tgz#afafc80294e5efab94bee31a187273d43d34979a"
|
|
||||||
integrity sha512-90cc7njn4aHbH9UxY8qgZth1W5JgOgcEdWdubH1t7sFkwqFxS5g3zgxSBt46TygFBVIXNZNq35Xmg80wgqO7Pg==
|
|
||||||
|
|
||||||
"@material/floating-label@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-0.44.0.tgz#8694cd49f6905641b67a9e7a112b820d028f09c7"
|
|
||||||
integrity sha512-k4npGNxyMtnjgJZNjU5VvqqaUqlbzlbVAhepT8PxYTpj+4Skg6PjHwieTCDCgsbqHvFcQX+WfUrSZXY7wFV7cw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/floating-label@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-0.44.1.tgz#39af84a3a0abbfa6d210911d5f4200a65c2ef59b"
|
|
||||||
integrity sha512-umj5q5feJcZuB8snRX5aVBrwQNnrt/HcvN7pENzgqaYZNcmBnxRl0OutTlHCn6l7OVU9VlWhFMf77DYwmMWKJQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.1"
|
|
||||||
|
|
||||||
"@material/form-field@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-0.44.0.tgz#b7518e885c0e953a2a5fe0140af927c30e066f4e"
|
|
||||||
integrity sha512-SK+V34dzoBCQ/CHn5nBp8BAh21Vj9p1pcok+/WpYBTeg4EphTYP2nUQLMNEN92l6zjgAYf+g9Ocj3t26HNHWqA==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/grid-list@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/grid-list/-/grid-list-0.44.0.tgz#bd31d992ab1a910731e4a47c11fe91d44e3bc02b"
|
|
||||||
integrity sha512-NxLL0A48K1O14ZZymFIyf6HDbF33+NgXYXqP2yosTC3Jw4iwmUcJTpFTmSw1U/m1xT4zEpeKEGJ4vjVUWpS9Mg==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/icon-button@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/icon-button/-/icon-button-0.44.0.tgz#febbcfd27d91eca8096ae042b9c07ed0f65345e9"
|
|
||||||
integrity sha512-n6L7RaRyEci6eGsuBTSEG+t9ATHAHaMlf9zuTWorEnIXY4DAmGO7ggBjw4+1XIOjhpLeIjyJdcvUK6Yz/UVM6Q==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/icon-toggle@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/icon-toggle/-/icon-toggle-0.44.0.tgz#b9de32f194b5aa9721ca799d59be0f477a5c5305"
|
|
||||||
integrity sha512-8T1b4iK61/q/3U0iIjEDJ9do5viCQ45IbrQqa8EYCZ1KDU/Q8z5N+bvOzQK8XnTL51BdDRMgP9lfQZh6nszmkA==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/image-list@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/image-list/-/image-list-0.44.0.tgz#a27996962044ac8c9ce6cb509f63746f08ed2e98"
|
|
||||||
integrity sha512-kI9aKJdc1Bd02l8nRTGG1wy/lNkECScfnBmCiLQ3XjAFtRYd2eWO0Z/AVvUG3egsIZnZBxqFGGsf5Htm9E/HiQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/layout-grid@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/layout-grid/-/layout-grid-0.41.0.tgz#2e7d3be76313e0684d573b10c2c6a88b3230d251"
|
|
||||||
integrity sha512-Sa5RNoTGgfIojqJ9E94p7/k11V6q/tGk7HwKi4AQNAPjxield0zcl3G/SbsSb8YSHoK+D+7OXDN+n11x6EqF7g==
|
|
||||||
|
|
||||||
"@material/line-ripple@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/line-ripple/-/line-ripple-0.43.0.tgz#6cb530bab53f055f3583646a21ad20c1703f3a83"
|
|
||||||
integrity sha512-sXZYW4Em5uLEnAuVsQCO+sVHsTg7J2TOTJ0+akwZFMmd2tmNicjarQdlGIE9iU7Wjm51NOoLAu6Mz+8kLg90bQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/linear-progress@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/linear-progress/-/linear-progress-0.43.0.tgz#4821424aa24c78de256e74a91d5be3df55c534d9"
|
|
||||||
integrity sha512-bqkDcob+xp1mFkyBsOkoaLgrtapmz7jznGoI3nmkqyk75EB2XQcn1H8Vr6cnp/jkF4nbKu0GdVJO3VXUFmGmrQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/list@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/list/-/list-0.44.0.tgz#cf1910e15b66759334b8618d1110fbcc72c3d326"
|
|
||||||
integrity sha512-35gkN1+XZaau9d9ngyN2x14bzkj/ajZCDm7mbWibDQy272A16j6KuFLQFA8RUQV04OgL4YPVxY87dpCn/p+uTg==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/dom" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/menu-surface@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/menu-surface/-/menu-surface-0.44.0.tgz#902c081df42859b925a5b4502791b3febf48f1ae"
|
|
||||||
integrity sha512-s49kvIlQ4H5wvMD4yeHMMqnamPod06IUagMK6Ry0oTpUANSnyeNXxa3HkScl7DMJiS8IJeV21fSLAzlZYP2PDQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/menu@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/menu/-/menu-0.44.0.tgz#776ec8a04406266a0a0a13eb140b1fd691e442cb"
|
|
||||||
integrity sha512-92XvAcv9rBW1jQ3UvwJ8zk9hbSRe/FqSuFdZ9fNPE348dCY2pbcdQfnUJTe3ycAN/I1c5frkrhx8F0II+nfbNQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/list" "^0.44.0"
|
|
||||||
"@material/menu-surface" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
|
|
||||||
"@material/notched-outline@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-0.44.0.tgz#d5a2e1d649921575a7cd2e88ee4581e4a1809573"
|
|
||||||
integrity sha512-c3nqOqUQAmW3h4zBbZVbMRdf4nNTYm0tVwXIAwmcCs5nvAthEHnzHwwFddNP7/9Wju6LZ0uqWn6xlyKly0uipw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/floating-label" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/notched-outline@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-0.44.1.tgz#dba4812286ba4c20f0361e6040bf9b9cad307434"
|
|
||||||
integrity sha512-x1ZJtrrqZgXT8gYE7aRF+6hTWpX7XaKZzsuwD+e0HBsogYNNsYmkBdLjl4YwhhFuHhX8vWzgkay41GtbgQx84Q==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/floating-label" "^0.44.1"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.44.1"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/radio@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/radio/-/radio-0.44.0.tgz#f4cacdfabc7d765aa000cb34c5a37966f6d4fd6d"
|
|
||||||
integrity sha512-ar7uhlfHuSwM9JUUjpv7pLDLE0p436cCMxNTpmMjWabfvo3pMWlExvk72Oj81tBgfxY/uASLB3oj4neudXu9JQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/ripple@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.44.0.tgz#98920ff8ec4bf5714c97df3d190f02f8a5b476cc"
|
|
||||||
integrity sha512-MlaW4nUDgzS0JOBfsUawXyTOilr0jn+xvTVn6PEaGh2rmhNA54AhixXvdsVUWE9lfmHAsZV0AJHz2z7nunNhbQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/feature-targeting" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/ripple@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.44.1.tgz#79cb2ddf1f998498d877d3e3c46b50fed6f13b01"
|
|
||||||
integrity sha512-prJ1p3bR+GvwAtJgtdeIixsnRVApN3bizGnX7upKoqxsqbBDHj84JxaO8EsG9bjruG/LJu8Fb6WKKdIp2oXHTA==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/feature-targeting" "^0.44.1"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/rtl@^0.42.0":
|
|
||||||
version "0.42.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/rtl/-/rtl-0.42.0.tgz#1836e78186c2d8b996f6fbf97adab203535335bc"
|
|
||||||
integrity sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==
|
|
||||||
|
|
||||||
"@material/select@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/select/-/select-0.44.0.tgz#8041b4fe6247d013b0f12685fbdf50aa9ff57b35"
|
|
||||||
integrity sha512-tw3/QIBLuRCT+5IXx4IPiJk7FzeGeR65JEizdRUItH8yzoIiQLs/b2i3KtHM2YBXHgeUcEBF2AOqPX2opdYhug==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/floating-label" "^0.44.0"
|
|
||||||
"@material/line-ripple" "^0.43.0"
|
|
||||||
"@material/menu" "^0.44.0"
|
|
||||||
"@material/menu-surface" "^0.44.0"
|
|
||||||
"@material/notched-outline" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/selection-control@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/selection-control/-/selection-control-0.44.0.tgz#63d5c65a47a9f54f5a0316b5ecdb5e5f35108609"
|
|
||||||
integrity sha512-HgCAPnMVMEj4X4ILkFSifqtZ3Tcc5HkU+Lfk9g0807sCaN/qBKWkYKLH2WJUbW8uk+MXK7DgP1khtS5zzanJWA==
|
|
||||||
dependencies:
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/selection-control@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/selection-control/-/selection-control-0.44.1.tgz#77a47354a4c5128fa34e3ba98d9cc26e8a92839a"
|
|
||||||
integrity sha512-Xf1ee2ZV2XJ+rK8OcOD1DZOihfU0uVRdY6iYX/Bqi8k8RXnAbLIBoh6zG3xSwjRNODNvAyHEQaS/ozEfH8eehg==
|
|
||||||
dependencies:
|
|
||||||
"@material/ripple" "^0.44.1"
|
|
||||||
|
|
||||||
"@material/shape@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/shape/-/shape-0.43.0.tgz#b877acfd8be8abc9ddcf6601eb60dd0588292415"
|
|
||||||
integrity sha512-KGnoQV4G2OQbMe5Lr5Xbk8XNlO93Qi/juxXtd2wrAfiaPmktD8ug0CwdVDOPBOmj9a0gX3Ofi9XWcoU+tLEVjg==
|
|
||||||
|
|
||||||
"@material/shape@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/shape/-/shape-0.44.1.tgz#ff4d5d42b07c5781306677bffee43234b756ea8e"
|
|
||||||
integrity sha512-8mCDQmyTEhDK+HX8Tap2Lc82QlVySlXU8zDCNkWoIn1ge+UnRezSDjE4y4P1ABegN5PrkJZPartuQ1U0ttIYXw==
|
|
||||||
dependencies:
|
|
||||||
"@material/feature-targeting" "^0.44.1"
|
|
||||||
|
|
||||||
"@material/slider@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/slider/-/slider-0.44.0.tgz#2055df894eb725e541cde50a544719c07934755b"
|
|
||||||
integrity sha512-Lnn2fdUesXX4O0UpJzveEuOj+og+dXCwhal73u3l3NXEdc/eRgYxwWdF3ww4MmCZ786EwUmjb4vIc9olN4DO3A==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/snackbar@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/snackbar/-/snackbar-0.44.0.tgz#d98672b849f5f295e4fac2d474a9c80f11945518"
|
|
||||||
integrity sha512-KhCrmJm8Zu/ZZPuRCGfMKsZ0vudINlNgTjlOau0kQ/UgR1xBUvLOE8NjyXZr0RQz5obyW7xpyIWIpscn0IUeyw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/button" "^0.44.0"
|
|
||||||
"@material/dom" "^0.41.0"
|
|
||||||
"@material/icon-button" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/switch@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/switch/-/switch-0.44.0.tgz#f2cbb447437b12eb3bc7f0ec8318dbd3b4f0afce"
|
|
||||||
integrity sha512-EadCg6lHUF260R2Q/l++vXIITqacvbXlobSoewA5ib6y9BU2g7l13wL1W8xAVJNUMgFa/PyN+EKT3oCql7jZLg==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/tab-bar@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/tab-bar/-/tab-bar-0.44.0.tgz#b17d791bd557b1d84892fef1a1d8b8d6fef7c6d6"
|
|
||||||
integrity sha512-kCrt05d61YXyY43SNc0dPGuqysbcLr/KRDBvzpXgE4gv2jCCVhhjAH10KPlx8pthp/UtvrYJHb34acAKEGzdHA==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/tab" "^0.44.0"
|
|
||||||
"@material/tab-scroller" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/tab-indicator@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/tab-indicator/-/tab-indicator-0.43.0.tgz#37fd05513ba55ae218d9068c986c2676096fd6eb"
|
|
||||||
integrity sha512-RMNMQpWYghWpM6d0ayfuHEPzTiebKG0bMthViiD6tly8PubmOT8mShNhPm8ihybhDPUOLSz+7V4QNE5wikLEYg==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/tab-scroller@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/tab-scroller/-/tab-scroller-0.44.0.tgz#82d092ed45d2ee9d82038bed318e6ff6bdc36dad"
|
|
||||||
integrity sha512-Ufd3NWBN11kY2oA7bGmTYWGP1uz2mq0tfDM0JOiqoLMgD7y3Z18kmxnpq2qkg1vi4kvix28hBYGGMfLlq9rGDA==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/tab" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/tab@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/tab/-/tab-0.44.0.tgz#254b92cff99015f0bd59a86d08d3f1c4744d0742"
|
|
||||||
integrity sha512-czrbGjtKkmUS3iYBX523xT5GOkjP0h+0x9fTnw+heFNpw5dCn6cZvlj3D9ayZU+ZH93x68TFhFVBuLU5f0EBXw==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/tab-indicator" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/textfield@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.44.0.tgz#277b33948ddff33f7f643323895e5a683f013601"
|
|
||||||
integrity sha512-IMBwMcE82eVU+Wifpu0t84tozvBPLCeqQELDtZNYujKg3RxaultzJLwIyGKPMZ9R4yPEpV2vgXPGKE+2/AWt0g==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/floating-label" "^0.44.0"
|
|
||||||
"@material/line-ripple" "^0.43.0"
|
|
||||||
"@material/notched-outline" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/textfield@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.44.1.tgz#2bba41cc94e68e328683997a1acf222b643dea9c"
|
|
||||||
integrity sha512-zy+56+uqr+L9DGrdOfQjOIMdKlai/7ruyqVfqIY6ieABM7LEGsOsxHhyExQmXo9IiuFhrOceWKFa4yIb8jBsmQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/floating-label" "^0.44.1"
|
|
||||||
"@material/line-ripple" "^0.43.0"
|
|
||||||
"@material/notched-outline" "^0.44.1"
|
|
||||||
"@material/ripple" "^0.44.1"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.44.1"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.1"
|
|
||||||
|
|
||||||
"@material/theme@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/theme/-/theme-0.43.0.tgz#6d9fa113c82e841817882172c152d60d2d203ca6"
|
|
||||||
integrity sha512-/zndZL6EihI18v2mYd4O8xvOBAAXmLeHyHVK28LozSAaJ9okQgD25wq5Ktk95oMTmPIC+rH66KcK6371ivNk8g==
|
|
||||||
|
|
||||||
"@material/toolbar@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/toolbar/-/toolbar-0.44.0.tgz#6689aecdeccc78b7a890a3abbe8b68a2c6339307"
|
|
||||||
integrity sha512-YgLlOFQ5VzFLQBpXYSMviEbYox0fia+sasHuYPUhTAtas1ExVt9EEiIolDSVvhv2PruTReKKefxSbXAqGlOHog==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/top-app-bar@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/top-app-bar/-/top-app-bar-0.44.0.tgz#2495c7f9567568fb961ccced24f479c4806a72af"
|
|
||||||
integrity sha512-tf0yXQJARYs8UPaH8oo3LnsSHEiur7Zm8Fc3hv3F0gNRRaZYBjwsMQMVbZZaWoQCWskMALyntBg+Fo18zdgDxw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/typography@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.44.0.tgz#cf61dce2ee89bfa084d86e1b0f270a585bf9dfaf"
|
|
||||||
integrity sha512-m4SjA9OjZRDKowN3cPzEa8e2GlTlEn3ZmW/Fy9eRNSp83iY+8a0xl6kCaF80v5qAVwVcpfEFyEHWxMJtkBw2uA==
|
|
||||||
|
|
||||||
"@material/typography@^0.44.1":
|
|
||||||
version "0.44.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.44.1.tgz#a94f01172f9122180bc2ce0aa55658183a35590d"
|
|
||||||
integrity sha512-wMXHusg+Lp5Fdgoj3m0c+Lt6GCeGSh3EPRtQ1TQ2bwdBa0et2FqBaQRgXoq3tVmr0O/7unTfa0DoXlh4nVp1wA==
|
|
||||||
dependencies:
|
|
||||||
"@material/feature-targeting" "^0.44.1"
|
|
||||||
|
|
||||||
focus-trap@^4.0.2:
|
|
||||||
version "4.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-4.0.2.tgz#4ee2b96547c9ea0e4252a2d4b2cca68944194663"
|
|
||||||
integrity sha512-HtLjfAK7Hp2qbBtLS6wEznID1mPT+48ZnP2nkHzgjpL4kroYHg0CdqJ5cTXk+UO5znAxF5fRUkhdyfgrhh8Lzw==
|
|
||||||
dependencies:
|
|
||||||
tabbable "^3.1.2"
|
|
||||||
xtend "^4.0.1"
|
|
||||||
|
|
||||||
material-components-web@^0.44.0:
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/material-components-web/-/material-components-web-0.44.0.tgz#ff782e8d7bdd8212d3c6022a731258d0d42da531"
|
|
||||||
integrity sha512-BSRLf58SMVhAvlDhJDlcgYuvzeMwbMHKTJ7oIB8LaM24ZpXBxP9XCYJpKheMtiVLrgllCGDlJ/47OIDReHQXdQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/auto-init" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/button" "^0.44.0"
|
|
||||||
"@material/card" "^0.44.0"
|
|
||||||
"@material/checkbox" "^0.44.0"
|
|
||||||
"@material/chips" "^0.44.0"
|
|
||||||
"@material/dialog" "^0.44.0"
|
|
||||||
"@material/dom" "^0.41.0"
|
|
||||||
"@material/drawer" "^0.44.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/fab" "^0.44.0"
|
|
||||||
"@material/feature-targeting" "^0.44.0"
|
|
||||||
"@material/floating-label" "^0.44.0"
|
|
||||||
"@material/form-field" "^0.44.0"
|
|
||||||
"@material/grid-list" "^0.44.0"
|
|
||||||
"@material/icon-button" "^0.44.0"
|
|
||||||
"@material/icon-toggle" "^0.44.0"
|
|
||||||
"@material/image-list" "^0.44.0"
|
|
||||||
"@material/layout-grid" "^0.41.0"
|
|
||||||
"@material/line-ripple" "^0.43.0"
|
|
||||||
"@material/linear-progress" "^0.43.0"
|
|
||||||
"@material/list" "^0.44.0"
|
|
||||||
"@material/menu" "^0.44.0"
|
|
||||||
"@material/menu-surface" "^0.44.0"
|
|
||||||
"@material/notched-outline" "^0.44.0"
|
|
||||||
"@material/radio" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/select" "^0.44.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/slider" "^0.44.0"
|
|
||||||
"@material/snackbar" "^0.44.0"
|
|
||||||
"@material/switch" "^0.44.0"
|
|
||||||
"@material/tab" "^0.44.0"
|
|
||||||
"@material/tab-bar" "^0.44.0"
|
|
||||||
"@material/tab-indicator" "^0.43.0"
|
|
||||||
"@material/tab-scroller" "^0.44.0"
|
|
||||||
"@material/textfield" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/toolbar" "^0.44.0"
|
|
||||||
"@material/top-app-bar" "^0.44.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
tabbable@^3.1.2:
|
|
||||||
version "3.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2"
|
|
||||||
integrity sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==
|
|
||||||
|
|
||||||
xtend@^4.0.1:
|
|
||||||
version "4.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
|
||||||
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
|
|
||||||
|
Before Width: | Height: | Size: 537 B |
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"manifest_version": 2,
|
|
||||||
"name": "Coder",
|
|
||||||
"version": "1",
|
|
||||||
"icons": {
|
|
||||||
"128": "icon_128.png"
|
|
||||||
},
|
|
||||||
"permissions": [
|
|
||||||
"storage",
|
|
||||||
"webview",
|
|
||||||
"http://*/*",
|
|
||||||
"https://*/*"
|
|
||||||
],
|
|
||||||
"app": {
|
|
||||||
"background": {
|
|
||||||
"scripts": [
|
|
||||||
"out/background.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"content": {
|
|
||||||
"scripts": [
|
|
||||||
"out/content.js"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"commands": {
|
|
||||||
"toggle-feature-foo": {
|
|
||||||
"suggested_key": {
|
|
||||||
"default": "Ctrl+W"
|
|
||||||
},
|
|
||||||
"description": "Toggle feature foo",
|
|
||||||
"global": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"sockets": {
|
|
||||||
"tcpServer": {
|
|
||||||
"listen": [
|
|
||||||
""
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@coder/chrome-app",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/chrome": "^0.0.79"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "../../../node_modules/.bin/webpack --config ./webpack.config.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
/// <reference path="../node_modules/@types/chrome/index.d.ts" />
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
const chromeApp = (<any>chrome).app;
|
|
||||||
|
|
||||||
chromeApp.runtime.onLaunched.addListener(() => {
|
|
||||||
chromeApp.window.create("src/index.html", {
|
|
||||||
outerBounds: {
|
|
||||||
width: 400,
|
|
||||||
height: 500,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
//@ts-ignore
|
|
||||||
import { TcpHost, TcpServer, TcpConnection } from "@coder/app/common/src/app";
|
|
||||||
import { Event, Emitter } from "@coder/events/src";
|
|
||||||
|
|
||||||
export const tcpHost: TcpHost = {
|
|
||||||
listen(host: string, port: number): Promise<TcpServer> {
|
|
||||||
const socketApi: {
|
|
||||||
readonly tcpServer: {
|
|
||||||
create(props: {}, cb: (createInfo: { readonly socketId: number }) => void): void;
|
|
||||||
listen(socketId: number, address: string, port: number, callback: (result: number) => void): void;
|
|
||||||
disconnect(socketId: number, callback: () => void): void;
|
|
||||||
|
|
||||||
readonly onAccept: {
|
|
||||||
addListener(callback: (info: { readonly socketId: number; readonly clientSocketId: number }) => void): void;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
readonly tcp: {
|
|
||||||
readonly onReceive: {
|
|
||||||
addListener(callback: (info: { readonly socketId: number; readonly data: ArrayBuffer; }) => void): void;
|
|
||||||
};
|
|
||||||
close(socketId: number, callback?: () => void): void;
|
|
||||||
send(socketId: number, data: ArrayBuffer, callback?: () => void): void;
|
|
||||||
setPaused(socketId: number, value: boolean): void;
|
|
||||||
};
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
} = (<any>chrome).sockets;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject): void => {
|
|
||||||
socketApi.tcpServer.create({}, (createInfo) => {
|
|
||||||
const serverSocketId = createInfo.socketId;
|
|
||||||
socketApi.tcpServer.listen(serverSocketId, host, port, (result) => {
|
|
||||||
if (result < 0) {
|
|
||||||
return reject("Failed to listen: " + chrome.runtime.lastError);
|
|
||||||
}
|
|
||||||
|
|
||||||
const connectionEmitter = new Emitter<TcpConnection>();
|
|
||||||
|
|
||||||
socketApi.tcpServer.onAccept.addListener((info) => {
|
|
||||||
if (info.socketId !== serverSocketId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dataEmitter = new Emitter<ArrayBuffer>();
|
|
||||||
|
|
||||||
socketApi.tcp.onReceive.addListener((recvInfo) => {
|
|
||||||
if (recvInfo.socketId !== info.clientSocketId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dataEmitter.emit(recvInfo.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
socketApi.tcp.setPaused(info.clientSocketId, false);
|
|
||||||
|
|
||||||
connectionEmitter.emit({
|
|
||||||
send: (data): Promise<void> => {
|
|
||||||
return new Promise<void>((res): void => {
|
|
||||||
socketApi.tcp.send(info.clientSocketId, data, () => {
|
|
||||||
res();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
close: (): Promise<void> => {
|
|
||||||
return new Promise((res): void => {
|
|
||||||
socketApi.tcp.close(info.clientSocketId, () => {
|
|
||||||
res();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get onData(): Event<ArrayBuffer> {
|
|
||||||
return dataEmitter.event;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
resolve({
|
|
||||||
get onConnection(): Event<TcpConnection> {
|
|
||||||
return connectionEmitter.event;
|
|
||||||
},
|
|
||||||
close: (): Promise<void> => {
|
|
||||||
return new Promise((res): void => {
|
|
||||||
socketApi.tcpServer.disconnect(serverSocketId, () => {
|
|
||||||
res();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import { create } from "@coder/app/common/src/app";
|
|
||||||
import { tcpHost } from "./chome";
|
|
||||||
|
|
||||||
create({
|
|
||||||
storage: {
|
|
||||||
get: <T>(key: string): Promise<T | undefined> => {
|
|
||||||
return new Promise<T | undefined>((resolve, reject): void => {
|
|
||||||
try {
|
|
||||||
chrome.storage.sync.get(key, (items) => {
|
|
||||||
resolve(items[key]);
|
|
||||||
});
|
|
||||||
} catch (ex) {
|
|
||||||
reject(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
set: <T>(key: string, value: T): Promise<void> => {
|
|
||||||
return new Promise<void>((resolve, reject): void => {
|
|
||||||
try {
|
|
||||||
chrome.storage.sync.set({
|
|
||||||
[key]: value,
|
|
||||||
}, () => {
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
} catch (ex) {
|
|
||||||
reject(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tcp: tcpHost,
|
|
||||||
node: document.getElementById("main") as HTMLDivElement,
|
|
||||||
});
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="Content-Security-Policy" content="style-src 'self' https://use.typekit.net; font-src 'self' https://use.typekit.net;">
|
|
||||||
<link rel="stylesheet" type="text/css" href="/out/main.css">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="main"></div>
|
|
||||||
<script src="/out/content.js"></script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
const path = require("path");
|
|
||||||
const webpack = require("webpack");
|
|
||||||
const merge = require("webpack-merge");
|
|
||||||
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
|
|
||||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
|
||||||
const prod = process.env.NODE_ENV === "production";
|
|
||||||
|
|
||||||
module.exports = [
|
|
||||||
merge(require(path.join(__dirname, "../../../scripts", "webpack.general.config.js"))(), {
|
|
||||||
devtool: "none",
|
|
||||||
mode: "development",
|
|
||||||
target: "web",
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, "out"),
|
|
||||||
filename: "background.js",
|
|
||||||
},
|
|
||||||
entry: [
|
|
||||||
"./packages/app/chrome/src/background.ts"
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
merge(require(path.join(__dirname, "../../../scripts", "webpack.general.config.js"))(), {
|
|
||||||
devtool: "none",
|
|
||||||
mode: "development",
|
|
||||||
target: "web",
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, "out"),
|
|
||||||
filename: "content.js",
|
|
||||||
},
|
|
||||||
entry: [
|
|
||||||
"./packages/app/chrome/src/content.ts"
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
]
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
"@types/chrome@^0.0.79":
|
|
||||||
version "0.0.79"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.79.tgz#1c83b35bd9b21b6204fb56e4816a1ea65dc013e5"
|
|
||||||
integrity sha512-4+Xducpig6lpwVX65Hk8KSZwRoURHXMDbd38SDNcV8TBaw4xyJki39fjB1io2h7ip+BsyFvgTm9OxR5qneLPiA==
|
|
||||||
dependencies:
|
|
||||||
"@types/filesystem" "*"
|
|
||||||
|
|
||||||
"@types/filesystem@*":
|
|
||||||
version "0.0.29"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.29.tgz#ee3748eb5be140dcf980c3bd35f11aec5f7a3748"
|
|
||||||
integrity sha512-85/1KfRedmfPGsbK8YzeaQUyV1FQAvMPMTuWFQ5EkLd2w7szhNO96bk3Rh/SKmOfd9co2rCLf0Voy4o7ECBOvw==
|
|
||||||
dependencies:
|
|
||||||
"@types/filewriter" "*"
|
|
||||||
|
|
||||||
"@types/filewriter@*":
|
|
||||||
version "0.0.28"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
|
|
||||||
integrity sha1-wFTor02d11205jq8dviFFocU1LM=
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@coder/app-common",
|
|
||||||
"main": "src/app.ts",
|
|
||||||
"dependencies": {
|
|
||||||
"material-components-web": "^0.44.0",
|
|
||||||
"react": "^16.8.1",
|
|
||||||
"react-dom": "^16.8.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/react": "^16.8.2",
|
|
||||||
"@types/react-dom": "^16.8.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,279 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'aktiv-grotesk';
|
|
||||||
font-weight: 400;
|
|
||||||
// src: url("fonts/AktivGroteskRegular.ttf"); /* IE9 Compat Modes */
|
|
||||||
src: url("fonts/AktivGroteskRegular.woff2") format("woff2"), url("fonts/AktivGroteskRegular.woff") format("woff"); /* Pretty Modern Browsers */
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'aktiv-grotesk';
|
|
||||||
font-weight: 500;
|
|
||||||
src: url("fonts/AktivGroteskMedium.woff2") format("woff2"), url("fonts/AktivGroteskMedium.woff") format("woff"); /* Pretty Modern Browsers */
|
|
||||||
// src: url("fonts/AktivGroteskMedium.ttf");
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'aktiv-grotesk';
|
|
||||||
font-weight: 700;
|
|
||||||
src: url("fonts/AktivGroteskBold.woff2") format("woff2"), url("fonts/AktivGroteskBold.woff") format("woff"); /* Pretty Modern Browsers */
|
|
||||||
// src: url("fonts/AktivGroteskBold.ttf") format("ttf"); /* IE9 Compat Modes */
|
|
||||||
}
|
|
||||||
|
|
||||||
body, button, input {
|
|
||||||
font-family: 'aktiv-grotesk',sans-serif !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
background-color: #F6F8FB;
|
|
||||||
--mdc-theme-primary: #2A2E37;
|
|
||||||
}
|
|
||||||
|
|
||||||
webview {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
transition: 150ms opacity ease;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
opacity: 1;
|
|
||||||
pointer-events: all;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-fill {
|
|
||||||
fill: #2A2E37;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main {
|
|
||||||
& > .header {
|
|
||||||
width: 100%;
|
|
||||||
height: 71px;
|
|
||||||
border-bottom: 1px solid rgba(117, 122, 131, 0.1);
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: 60px;
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
max-height: fit-content;
|
|
||||||
width: 145px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shrinker {
|
|
||||||
max-width: 1145px;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 auto;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
max-width: 960px;
|
|
||||||
width: 100%;
|
|
||||||
padding-bottom: 100px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.servers {
|
|
||||||
color: #2B343B;
|
|
||||||
|
|
||||||
& > .header {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
padding-bottom: 21px;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 500;
|
|
||||||
letter-spacing: 0.35px;
|
|
||||||
line-height: 33px;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-server {
|
|
||||||
margin-left: auto;
|
|
||||||
border-radius: 24px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 14px;
|
|
||||||
letter-spacing: 1.25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.refresh {
|
|
||||||
margin-left: 16px;
|
|
||||||
margin-right: 15px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
@keyframes rotate {
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
&.refreshing {
|
|
||||||
animation: rotate 1s linear infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1.6fr 1.3fr 1.1fr 0.6fr 0.4fr;
|
|
||||||
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
|
|
||||||
border-radius: 0 0 5px 5px;
|
|
||||||
|
|
||||||
.mdc-linear-progress {
|
|
||||||
grid-column-start: 1;
|
|
||||||
grid-column-end: 7;
|
|
||||||
// height: 0;
|
|
||||||
position: relative;
|
|
||||||
--mdc-theme-primary: rgb(107, 109, 102);
|
|
||||||
height: 5px;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
background-color: #2A2E37;
|
|
||||||
transition: 500ms opacity ease;
|
|
||||||
content: " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
&.loading {
|
|
||||||
&:after {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.title, .value {
|
|
||||||
padding-top: 14px;
|
|
||||||
padding-bottom: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
background-color: var(--mdc-theme-primary);
|
|
||||||
font-size: 10px;
|
|
||||||
color: #9D9FA4;
|
|
||||||
font-weight: bold;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
line-height: 12px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
// padding-top: 15px;
|
|
||||||
// padding-bottom: 10px;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
padding-left: 30px;
|
|
||||||
border-radius: 10px 0 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-child(6) {
|
|
||||||
padding-right: 30px;
|
|
||||||
border-radius: 0 10px 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.servername {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
|
||||||
border-top: 1px solid #EBEBF2;
|
|
||||||
font-size: 14px;
|
|
||||||
letter-spacing: 0.2px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
color: #717680;
|
|
||||||
background-color: white;
|
|
||||||
|
|
||||||
&.dark {
|
|
||||||
background-color: #F6F8FB;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.servername {
|
|
||||||
.logo {
|
|
||||||
height: 25px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.strong {
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2B343B;
|
|
||||||
font-size: 14px;
|
|
||||||
letter-spacing: 0.6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.status {
|
|
||||||
padding-left: 36px;
|
|
||||||
|
|
||||||
span {
|
|
||||||
margin-left: 7px;
|
|
||||||
line-height: 0px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.buttons {
|
|
||||||
button {
|
|
||||||
margin-left: auto;
|
|
||||||
border-radius: 24px;
|
|
||||||
border: 1px solid #CFD1D7;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
letter-spacing: 1.25px;
|
|
||||||
line-height: 16px;
|
|
||||||
padding-left: 18px;
|
|
||||||
padding-right: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.icons {
|
|
||||||
padding-left: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
border-bottom-right-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-last-child(6) {
|
|
||||||
border-bottom-left-radius: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flex-row {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
}
|
|
||||||
|
|
||||||
.floater {
|
|
||||||
box-shadow: 0 8px 80px 10px rgba(69, 65, 78, 0.08);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 3em;
|
|
||||||
min-width: 300px;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
& > h1 {
|
|
||||||
font-size: 3.5em;
|
|
||||||
margin-top: 0px;
|
|
||||||
|
|
||||||
// margin-bottom: 0px;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mdc-ripple-upgraded--unbounded {
|
|
||||||
padding: 2px;
|
|
||||||
padding-top: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
//@ts-ignore
|
|
||||||
import { MDCTextField } from "@material/textfield";
|
|
||||||
import { TcpHost } from "./connection";
|
|
||||||
import { StorageProvider } from "./storage";
|
|
||||||
import "material-components-web/dist/material-components-web.css";
|
|
||||||
import "./app.scss";
|
|
||||||
import "./tooltip.scss";
|
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { render } from "react-dom";
|
|
||||||
import { Main } from "./containers";
|
|
||||||
|
|
||||||
export * from "./connection";
|
|
||||||
export interface App {
|
|
||||||
readonly tcp: TcpHost;
|
|
||||||
readonly storage: StorageProvider;
|
|
||||||
readonly node: HTMLElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RegisteredServer {
|
|
||||||
readonly host: "coder" | "self";
|
|
||||||
readonly hostname: string;
|
|
||||||
readonly name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const create = async (app: App): Promise<void> => {
|
|
||||||
let servers = await app.storage.get<RegisteredServer[]>("servers");
|
|
||||||
if (!servers) {
|
|
||||||
servers = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
render(<Main />, app.node);
|
|
||||||
};
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { Event } from "@coder/events";
|
|
||||||
import { TunnelCloseEvent } from "@coder/tunnel/src/client";
|
|
||||||
|
|
||||||
export interface TcpHost {
|
|
||||||
listen(host: string, port: number): Promise<TcpServer>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TcpServer {
|
|
||||||
readonly onConnection: Event<TcpConnection>;
|
|
||||||
close(): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TcpConnection {
|
|
||||||
readonly onData: Event<ArrayBuffer>;
|
|
||||||
send(data: ArrayBuffer): Promise<void>;
|
|
||||||
close(): Promise<void>;
|
|
||||||
}
|
|
||||||
@@ -1,573 +0,0 @@
|
|||||||
//@ts-ignore
|
|
||||||
import { MDCRipple } from "@material/ripple";
|
|
||||||
//@ts-ignore
|
|
||||||
import { MDCTextField } from "@material/textfield";
|
|
||||||
//@ts-ignore
|
|
||||||
import { MDCLinearProgress } from "@material/linear-progress";
|
|
||||||
import * as React from "react";
|
|
||||||
import * as ReactDOM from "react-dom";
|
|
||||||
import { RegisteredServer } from "./app";
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
declare var WebSettings: any;
|
|
||||||
|
|
||||||
interface AuthedUser {
|
|
||||||
readonly username: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Main extends React.Component<void, {
|
|
||||||
readonly view: "servers" | "add-server";
|
|
||||||
readonly loading: boolean;
|
|
||||||
}> {
|
|
||||||
private webview: HTMLWebViewElement | undefined;
|
|
||||||
|
|
||||||
public constructor(props: void) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
view: "servers",
|
|
||||||
loading: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidMount(): void {
|
|
||||||
window.addEventListener("message", (event) => {
|
|
||||||
if (event.data === "back") {
|
|
||||||
if (this.webview) {
|
|
||||||
this.webview.classList.remove("active");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (event.data === "loaded") {
|
|
||||||
if (this.webview) {
|
|
||||||
// this.setState({ loading: false });
|
|
||||||
// this.webview.classList.add("active");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.webview) {
|
|
||||||
this.webview.addEventListener("error", (event) => {
|
|
||||||
console.error(event);
|
|
||||||
});
|
|
||||||
this.webview.addEventListener("loadstart", (event) => {
|
|
||||||
this.setState({ loading: true });
|
|
||||||
});
|
|
||||||
this.webview.addEventListener("loadstop", (event) => {
|
|
||||||
this.setState({ loading: false });
|
|
||||||
this.webview!.classList.add("active");
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
const cw = (this.webview as any).contentWindow as Window;
|
|
||||||
cw.postMessage("app", "*");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<div className="main">
|
|
||||||
<div className="header">
|
|
||||||
<div className="shrinker">
|
|
||||||
<Logo />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="content">
|
|
||||||
{((): JSX.Element => {
|
|
||||||
switch (this.state.view) {
|
|
||||||
case "servers":
|
|
||||||
return (
|
|
||||||
<Servers servers={[
|
|
||||||
{
|
|
||||||
host: "coder",
|
|
||||||
hostname: "--",
|
|
||||||
name: "Coder",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
host: "self",
|
|
||||||
hostname: "http://localhost:8080",
|
|
||||||
name: "Dev Server",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
user={{
|
|
||||||
username: "Kyle",
|
|
||||||
}}
|
|
||||||
onSelect={(server): void => {
|
|
||||||
if (this.webview) {
|
|
||||||
this.webview.setAttribute("src", server.hostname);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onAddServer={() => this.setState({ view: "add-server" })}
|
|
||||||
loading={this.state.loading}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case "add-server":
|
|
||||||
return (
|
|
||||||
<div>Add server</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
<webview ref={(wv: HTMLWebViewElement): HTMLWebViewElement => this.webview = wv}></webview>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AddServer extends React.Component {
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<div className="add-server">
|
|
||||||
<h3>Add Server</h3>
|
|
||||||
<p>Something about what you can do once you add your own server. A link to setup guides for this would be great as well.</p>
|
|
||||||
<Input label="Address" id="address" />
|
|
||||||
<br></br>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Servers extends React.Component<{
|
|
||||||
readonly user?: AuthedUser;
|
|
||||||
readonly servers: ReadonlyArray<RegisteredServer>;
|
|
||||||
readonly onSelect: (server: RegisteredServer) => void;
|
|
||||||
readonly onAddServer: () => void;
|
|
||||||
readonly loading: boolean;
|
|
||||||
}, {
|
|
||||||
readonly refreshing: boolean;
|
|
||||||
}> {
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
public constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
refreshing: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<div className="servers">
|
|
||||||
<div className="header">
|
|
||||||
<h3>Servers</h3>
|
|
||||||
<Button onClick={(): void => this.props.onAddServer()} className="add-server" type="unelevated">Add Server</Button>
|
|
||||||
<Ripple>
|
|
||||||
<div className="refresh">
|
|
||||||
<svg onClick={(): void => this.doRefresh()} className={this.state.refreshing ? "refreshing" : ""} width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
|
||||||
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
||||||
<g>
|
|
||||||
<g transform="translate(4.000000, 4.000000)" fill="#2A2E37">
|
|
||||||
<path d="M8,3 C9.179,3 10.311,3.423 11.205,4.17 L8.883,6.492 L15.094,7.031 L14.555,0.82 L12.625,2.75 C11.353,1.632 9.71,1 8,1 C4.567,1 1.664,3.454 1.097,6.834 L3.07,7.165 C3.474,4.752 5.548,3 8,3 Z" id="Path"></path>
|
|
||||||
<path d="M8,13 C6.821,13 5.689,12.577 4.795,11.83 L7.117,9.508 L0.906,8.969 L1.445,15.18 L3.375,13.25 C4.647,14.368 6.29,15 8,15 C11.433,15 14.336,12.546 14.903,9.166 L12.93,8.835 C12.526,11.248 10.452,13 8,13 Z" id="Path"></path>
|
|
||||||
</g>
|
|
||||||
<rect id="Rectangle" fillRule="nonzero" x="0" y="0" width="24" height="24"></rect>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</Ripple>
|
|
||||||
</div>
|
|
||||||
<div className="grid">
|
|
||||||
<div className="title status">
|
|
||||||
Status
|
|
||||||
</div>
|
|
||||||
<div className="title servername">
|
|
||||||
Server Name
|
|
||||||
</div>
|
|
||||||
<div className="title hostname">
|
|
||||||
Hostname
|
|
||||||
</div>
|
|
||||||
<div className="title details">
|
|
||||||
Details
|
|
||||||
</div>
|
|
||||||
<div className="title">
|
|
||||||
{/* Used for continue/launch buttons */}
|
|
||||||
</div>
|
|
||||||
<div className="title">
|
|
||||||
{/* Used for logout and delete buttons */}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div role="progressbar" className={`mdc-linear-progress mdc-linear-progress--indeterminate ${this.props.loading ? "loading" : ""}`} ref={(d) => {
|
|
||||||
if (d) new MDCLinearProgress(d)}}>
|
|
||||||
<div className="mdc-linear-progress__buffering-dots"></div>
|
|
||||||
<div className="mdc-linear-progress__buffer"></div>
|
|
||||||
<div className="mdc-linear-progress__bar mdc-linear-progress__primary-bar">
|
|
||||||
<span className="mdc-linear-progress__bar-inner"></span>
|
|
||||||
</div>
|
|
||||||
<div className="mdc-linear-progress__bar mdc-linear-progress__secondary-bar">
|
|
||||||
<span className="mdc-linear-progress__bar-inner"></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.props.servers.map((server, i) => {
|
|
||||||
return (
|
|
||||||
<Server key={server.hostname + i} user={this.props.user} server={server} onSelect={(): void => this.props.onSelect(server)} />
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private doRefresh(): void {
|
|
||||||
if (this.state.refreshing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
refreshing: true,
|
|
||||||
}, () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.setState({
|
|
||||||
refreshing: false,
|
|
||||||
});
|
|
||||||
}, 1500);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ServerProps {
|
|
||||||
readonly user?: AuthedUser;
|
|
||||||
readonly server: RegisteredServer;
|
|
||||||
readonly onSelect: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Server extends React.Component<ServerProps, {
|
|
||||||
readonly user?: AuthedUser;
|
|
||||||
readonly status: "Online" | "Offline" | "Checking";
|
|
||||||
readonly version: string;
|
|
||||||
}> {
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
public constructor(props: ServerProps) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
status: props.server.host === "coder" ? "Online" : "Checking",
|
|
||||||
version: "",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillMount(): void {
|
|
||||||
if (this.props.server.host !== "self") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.open("GET", this.props.server.hostname);
|
|
||||||
xhr.addEventListener("error", (err) => {
|
|
||||||
this.setState({
|
|
||||||
status: "Offline",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
xhr.addEventListener("loadend", () => {
|
|
||||||
if (xhr.status === 200) {
|
|
||||||
this.setState({
|
|
||||||
status: "Online",
|
|
||||||
version: process.env.VERSION,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
status: "Offline",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className={`status value ${this.extraClasses}`}>
|
|
||||||
{((): JSX.Element => {
|
|
||||||
switch (this.state.status) {
|
|
||||||
case "Offline":
|
|
||||||
return (
|
|
||||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
|
||||||
<g id="Artboard-Copy-3" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
||||||
<circle id="Oval" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" cx="8" cy="8" r="7.25"></circle>
|
|
||||||
<path d="M5.15444712,5.15444712 L10.8455529,10.8455529" id="Path-4" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero"></path>
|
|
||||||
<path d="M5.15444712,5.15444712 L10.8455529,10.8455529" id="Path-4" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" transform="translate(8.000000, 8.000000) scale(-1, 1) translate(-8.000000, -8.000000) "></path>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
case "Online":
|
|
||||||
return (
|
|
||||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
|
||||||
<g id="Artboard-Copy-4" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
||||||
<g id="checkmark-copy-21" fillRule="nonzero">
|
|
||||||
<circle id="Oval" fill="#2B343B" cx="8" cy="8" r="8"></circle>
|
|
||||||
<polyline id="Path-2" stroke="#FFFFFF" strokeWidth="1.5" points="3.46296296 8.62222222 6.05555556 11.1111111 12.537037 4.88888889"></polyline>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
case "Checking":
|
|
||||||
return (
|
|
||||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
|
||||||
<g id="Artboard-Copy-5" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
||||||
<circle id="Oval" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" cx="8" cy="8" r="7.25"></circle>
|
|
||||||
<polyline id="Path" stroke="#2B343B" strokeWidth="1.5" points="7.90558664 4.63916767 7.90558664 8.63916767 11.9055866 8.63916767"></polyline>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
throw new Error("unsupported status");
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
<span>
|
|
||||||
{this.state.status}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className={`servername value strong ${this.extraClasses}`}>
|
|
||||||
{this.props.server.host === "coder" ? (
|
|
||||||
<Logo />
|
|
||||||
) : this.props.server.name}
|
|
||||||
</div>
|
|
||||||
<div className={`hostname value ${this.extraClasses}`}>
|
|
||||||
{this.props.server.hostname}
|
|
||||||
</div>
|
|
||||||
<div className={`details value ${this.extraClasses}`}>
|
|
||||||
{this.props.server.host === "coder" && this.props.user ? `Logged in as ${this.props.user.username}` : this.state.version}
|
|
||||||
</div>
|
|
||||||
<div className={`buttons value ${this.extraClasses}`}>
|
|
||||||
<Button onClick={(): void => this.props.onSelect()} className="add-server" type="outlined">{this.props.server.host === "coder" ? "Continue" : "Launch"}</Button>
|
|
||||||
</div>
|
|
||||||
<div className={`icons value ${this.extraClasses}`}>
|
|
||||||
<Ripple>
|
|
||||||
<div>
|
|
||||||
{this.props.server.host === "coder" ? (
|
|
||||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
|
||||||
<g id="Artboard" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
||||||
<g id="log-out-copy-2" transform="translate(4.000000, 4.000000)" fill="#2A2E37">
|
|
||||||
<polygon id="Path" points="4 4 0 8 4 12 4 9 10 9 10 7 4 7"></polygon>
|
|
||||||
<path d="M15,16 L6,16 C5.4,16 5,15.6 5,15 L5,12 L7,12 L7,14 L14,14 L14,2 L7,2 L7,4 L5,4 L5,1 C5,0.4 5.4,0 6,0 L15,0 C15.6,0 16,0.4 16,1 L16,15 C16,15.6 15.6,16 15,16 Z" id="Path"></path>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
) : (
|
|
||||||
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
|
||||||
<g id="Artboard" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
|
|
||||||
<g id="bin" transform="translate(4.000000, 4.000000)" fill="#2B343B">
|
|
||||||
<rect id="Rectangle" x="5" y="7" width="2" height="6"></rect>
|
|
||||||
<rect id="Rectangle" x="9" y="7" width="2" height="6"></rect>
|
|
||||||
<path d="M12,1 C12,0.4 11.6,0 11,0 L5,0 C4.4,0 4,0.4 4,1 L4,3 L0,3 L0,5 L1,5 L1,15 C1,15.6 1.4,16 2,16 L14,16 C14.6,16 15,15.6 15,15 L15,5 L16,5 L16,3 L12,3 L12,1 Z M6,2 L10,2 L10,3 L6,3 L6,2 Z M13,5 L13,14 L3,14 L3,5 L13,5 Z" id="Shape" fillRule="nonzero"></path>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Ripple>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private get extraClasses(): string {
|
|
||||||
return this.props.server.host === "coder" ? "dark" : "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Input extends React.Component<{
|
|
||||||
readonly label: string;
|
|
||||||
readonly id: string;
|
|
||||||
readonly type?: string;
|
|
||||||
}> {
|
|
||||||
private wrapper: HTMLDivElement | undefined;
|
|
||||||
|
|
||||||
public componentDidMount(): void {
|
|
||||||
if (this.wrapper) {
|
|
||||||
const textInput = new MDCTextField(this.wrapper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<div className="mdc-text-field mdc-text-field--outlined" ref={(i: HTMLDivElement): HTMLDivElement => this.wrapper = i}>
|
|
||||||
<input type={this.props.type || "text"} id={this.props.id} className="mdc-text-field__input" spellCheck={false}></input>
|
|
||||||
<div className="mdc-notched-outline">
|
|
||||||
<div className="mdc-notched-outline__leading"></div>
|
|
||||||
<div className="mdc-notched-outline__notch">
|
|
||||||
<label htmlFor={this.props.id} className="mdc-floating-label">{this.props.label}</label>
|
|
||||||
</div>
|
|
||||||
<div className="mdc-notched-outline__trailing"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Button extends React.Component<{
|
|
||||||
readonly type: "outlined" | "unelevated";
|
|
||||||
readonly className?: string;
|
|
||||||
readonly onClick?: () => void;
|
|
||||||
}> {
|
|
||||||
private button: HTMLButtonElement | undefined;
|
|
||||||
|
|
||||||
public componentDidMount(): void {
|
|
||||||
if (this.button) {
|
|
||||||
const b = new MDCRipple(this.button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<button onClick={() => this.props.onClick ? this.props.onClick() : undefined} className={`mdc-button mdc-button--${this.props.type} ${this.props.className || ""}`} ref={(b: HTMLButtonElement): HTMLButtonElement => this.button = b}>
|
|
||||||
<span className="mdc-button__label">{this.props.children}</span>
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Tooltip extends React.Component<{
|
|
||||||
readonly message: string;
|
|
||||||
}> {
|
|
||||||
public componentDidMount(): void {
|
|
||||||
Object.keys(this.refs).forEach((ref) => {
|
|
||||||
const el = this.refs[ref];
|
|
||||||
if (el) {
|
|
||||||
const element = ReactDOM.findDOMNode(el);
|
|
||||||
if (element) {
|
|
||||||
const te = document.createElement("div");
|
|
||||||
te.className = "md-tooltip-content";
|
|
||||||
te.innerHTML = this.props.message;
|
|
||||||
element.appendChild(te);
|
|
||||||
(element as HTMLElement).classList.add("md-tooltip");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{React.Children.map(this.props.children, (element, idx) => {
|
|
||||||
return React.cloneElement(element as any, { ref: idx });
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Ripple extends React.Component<{
|
|
||||||
readonly className?: string;
|
|
||||||
}> {
|
|
||||||
public componentDidMount(): void {
|
|
||||||
Object.keys(this.refs).forEach((ref) => {
|
|
||||||
const el = this.refs[ref];
|
|
||||||
if (el) {
|
|
||||||
const element = ReactDOM.findDOMNode(el);
|
|
||||||
if (element) {
|
|
||||||
(element as HTMLElement).classList.add("mdc-ripple-surface");
|
|
||||||
(element as HTMLElement).setAttribute("data-mdc-ripple-is-unbounded", "");
|
|
||||||
const r = new MDCRipple(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{React.Children.map(this.props.children, (element, idx) => {
|
|
||||||
return React.cloneElement(element as any, { ref: idx });
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Logo extends React.Component {
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<svg className="logo" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 471 117"
|
|
||||||
style={{enableBackground: "new 0 0 471 117"} as any} xmlSpace="preserve">
|
|
||||||
<g>
|
|
||||||
<g>
|
|
||||||
<path className="logo-fill" d="M217,75.6c5.9,0,10.7-2.3,14.5-7l7.7,7.9c-6.1,6.9-13.3,10.3-21.6,10.3s-15.1-2.6-20.5-7.9
|
|
||||||
C191.7,73.7,189,67,189,59s2.7-14.7,8.2-20s12.2-8,20.1-8c8.8,0,16.2,3.4,22.2,10.1l-7.5,8.5c-3.8-4.7-8.5-7.1-14.2-7.1
|
|
||||||
c-4.5,0-8.4,1.5-11.6,4.4c-3.2,3-4.8,6.9-4.8,11.9s1.5,9,4.5,12.1C209,74.1,212.6,75.6,217,75.6z M284.1,46.7
|
|
||||||
c-3.1-3.4-6.9-5.1-11.4-5.1s-8.3,1.7-11.4,5.1s-4.6,7.5-4.6,12.3s1.5,8.9,4.6,12.3s6.9,5,11.4,5s8.3-1.7,11.4-5
|
|
||||||
c3.1-3.4,4.6-7.5,4.6-12.3S287.2,50.1,284.1,46.7z M272.7,86.8c-8,0-14.7-2.7-20.1-8s-8.2-11.9-8.2-19.9c0-7.9,2.7-14.5,8.2-19.9
|
|
||||||
c5.4-5.3,12.2-8,20.1-8c8,0,14.7,2.7,20.1,8s8.2,11.9,8.2,19.9c0,7.9-2.7,14.5-8.2,19.9C287.4,84.1,280.7,86.8,272.7,86.8z
|
|
||||||
M352.3,39.4c5.1,4.7,7.7,11.2,7.7,19.6s-2.5,15-7.5,19.9s-12.7,7.3-22.9,7.3h-18.4V32.3h19C339.8,32.4,347.2,34.7,352.3,39.4z
|
|
||||||
M343.5,71.5c3-2.8,4.4-6.8,4.4-12.1s-1.5-9.4-4.4-12.2c-3-2.9-7.5-4.3-13.6-4.3h-6.7v32.8h7.6C336.3,75.6,340.5,74.2,343.5,71.5z
|
|
||||||
M409.3,32.4v10.7h-26.8v11.1h24.1v10.3h-24.1v11.2h27.7v10.6h-39.7V32.4H409.3L409.3,32.4z M464.6,50.3c0,8.6-3.4,14.2-10.3,16.7
|
|
||||||
l13.6,19.3h-14.8l-11.9-17.2h-8.3v17.2h-12V32.4h20.4c8.4,0,14.4,1.4,17.9,4.2C462.8,39.4,464.6,44,464.6,50.3z M450.1,56.7
|
|
||||||
c1.5-1.3,2.2-3.5,2.2-6.4s-0.8-4.9-2.3-6s-4.2-1.6-8.1-1.6h-9v16h8.8C445.8,58.7,448.6,58,450.1,56.7z"/>
|
|
||||||
</g>
|
|
||||||
<g>
|
|
||||||
<path className="logo-fill" d="M164.8,50.9c-3.3,0-5.5-1.9-5.5-5.8V22.7c0-14.3-6-22.2-21.5-22.2h-7.2v15.1h2.2c6.1,0,9,3.3,9,9.2v19.8
|
|
||||||
c0,8.6,2.6,12.1,8.3,13.9c-5.7,1.7-8.3,5.3-8.3,13.9c0,4.9,0,9.8,0,14.7c0,4.1,0,8.1-1.1,12.2c-1.1,3.8-2.9,7.4-5.4,10.5
|
|
||||||
c-1.4,1.8-3,3.3-4.8,4.7v2h7.2c15.5,0,21.5-7.9,21.5-22.2V71.9c0-4,2.1-5.8,5.5-5.8h4.1V51h-4V50.9L164.8,50.9z"/>
|
|
||||||
<path className="logo-fill" d="M115.8,23.3H93.6c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h22.3c0.5,0,0.9,0.4,0.9,0.9v1.7
|
|
||||||
C116.8,22.9,116.3,23.3,115.8,23.3z"/>
|
|
||||||
<path className="logo-fill" d="M119.6,44.9h-16.2c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h16.2c0.5,0,0.9,0.4,0.9,0.9V44
|
|
||||||
C120.5,44.4,120.1,44.9,119.6,44.9z"/>
|
|
||||||
<path className="logo-fill" d="M126,34.1H93.6c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h32.3c0.5,0,0.9,0.4,0.9,0.9v1.7
|
|
||||||
C126.8,33.6,126.5,34.1,126,34.1z"/>
|
|
||||||
<g>
|
|
||||||
<path className="logo-fill" d="M67.9,28.2c2.2,0,4.4,0.2,6.5,0.7v-4.1c0-5.8,3-9.2,9-9.2h2.2V0.5h-7.2c-15.5,0-21.5,7.9-21.5,22.2v7.4
|
|
||||||
C60.4,28.9,64.1,28.2,67.9,28.2z"/>
|
|
||||||
</g>
|
|
||||||
<path className="logo-fill" d="M132.8,82.6c-1.6-12.7-11.4-23.3-24-25.7c-3.5-0.7-7-0.8-10.4-0.2c-0.1,0-0.1-0.1-0.2-0.1
|
|
||||||
c-5.5-11.5-17.3-19.1-30.1-19.1S43.6,44.9,38,56.4c-0.1,0-0.1,0.1-0.2,0.1c-3.6-0.4-7.2-0.2-10.8,0.7c-12.4,3-21.8,13.4-23.5,26
|
|
||||||
c-0.2,1.3-0.3,2.6-0.3,3.8c0,3.8,2.6,7.3,6.4,7.8c4.7,0.7,8.8-2.9,8.7-7.5c0-0.7,0-1.5,0.1-2.2c0.8-6.4,5.7-11.8,12.1-13.3
|
|
||||||
c2-0.5,4-0.6,5.9-0.3c6.1,0.8,12.1-2.3,14.7-7.7c1.9-4,4.9-7.5,8.9-9.4c4.4-2.1,9.4-2.4,14-0.8c4.8,1.7,8.4,5.3,10.6,9.8
|
|
||||||
c2.3,4.4,3.4,7.5,8.3,8.1c2,0.3,7.6,0.2,9.7,0.1c4.1,0,8.2,1.4,11.1,4.3c1.9,2,3.3,4.5,3.9,7.3c0.9,4.5-0.2,9-2.9,12.4
|
|
||||||
c-1.9,2.4-4.5,4.2-7.4,5c-1.4,0.4-2.8,0.5-4.2,0.5c-0.8,0-1.9,0-3.2,0c-4,0-12.5,0-18.9,0c-4.4,0-7.9-3.5-7.9-7.9V78.4V63.9
|
|
||||||
c0-1.2-1-2.2-2.2-2.2h-3.1c-6.1,0.1-11,6.9-11,14.1s0,26.3,0,26.3c0,7.8,6.3,14.1,14.1,14.1c0,0,34.7-0.1,35.2-0.1
|
|
||||||
c8-0.8,15.4-4.9,20.4-11.2C131.5,98.8,133.8,90.8,132.8,82.6z"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// const $ = <K extends keyof HTMLElementTagNameMap>(tagName: K, className?: string, content?: string): HTMLElementTagNameMap[K] => {
|
|
||||||
// const el = document.createElement(tagName);
|
|
||||||
// if (className) {
|
|
||||||
// el.className = className;
|
|
||||||
// }
|
|
||||||
// if (content) {
|
|
||||||
// el.innerText = content;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return el;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const createInput = (id: string, labelName: string, type: string = "text"): HTMLDivElement => {
|
|
||||||
// // <div class="mdc-text-field mdc-text-field--outlined">
|
|
||||||
// // <input type="password" id="password" class="mdc-text-field__input">
|
|
||||||
// // <!-- <label class="mdc-floating-label" for="name">Name</label>
|
|
||||||
// // <div class="mdc-line-ripple"></div> -->
|
|
||||||
// // <div class="mdc-notched-outline">
|
|
||||||
// // <div class="mdc-notched-outline__leading"></div>
|
|
||||||
// // <div class="mdc-notched-outline__notch">
|
|
||||||
// // <label for="password" class="mdc-floating-label">Password</label>
|
|
||||||
// // </div>
|
|
||||||
// // <div class="mdc-notched-outline__trailing"></div>
|
|
||||||
// // </div>
|
|
||||||
|
|
||||||
// const wrapper = $("div", "mdc-text-field mdc-text-field--outlined");
|
|
||||||
// const input = $("input", "mdc-text-field__input");
|
|
||||||
// input.type = type;
|
|
||||||
// input.id = id;
|
|
||||||
// wrapper.appendChild(input);
|
|
||||||
// const notchedOutline = $("div", "mdc-notched-outline");
|
|
||||||
// notchedOutline.appendChild($("div", "mdc-notched-outline__leading"));
|
|
||||||
// const notch = $("div", "mdc-notched-outline__notch");
|
|
||||||
// const label = $("label", "mdc-floating-label", labelName);
|
|
||||||
// label.setAttribute("for", id);
|
|
||||||
// notch.appendChild(label);
|
|
||||||
// notchedOutline.appendChild(notch);
|
|
||||||
// wrapper.appendChild(notchedOutline);
|
|
||||||
// wrapper.appendChild($("div", "mdc-notched-outline__trailing"));
|
|
||||||
|
|
||||||
// const field = new MDCTextField(wrapper);
|
|
||||||
|
|
||||||
// return wrapper;
|
|
||||||
// };
|
|
||||||
|
|
||||||
// export const createCoderLogin = (parentNode: HTMLElement): void => {
|
|
||||||
// parentNode.appendChild($("h1", "header", "Login with Coder"));
|
|
||||||
// parentNode.appendChild(createInput("username", "Username"));
|
|
||||||
// parentNode.appendChild($("br"));
|
|
||||||
// parentNode.appendChild($("br"));
|
|
||||||
// parentNode.appendChild(createInput("password", "Password", "password"));
|
|
||||||
// };
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
export interface StorageProvider {
|
|
||||||
set<T>(key: string, value: T): Promise<void>;
|
|
||||||
get<T>(key: string): Promise<T | undefined>;
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
.md-tooltip {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-tooltip-content {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -35px;
|
|
||||||
left: 50%;
|
|
||||||
padding: 7px;
|
|
||||||
transform: translateX(-50%) scale(0);
|
|
||||||
transition: transform 0.15s cubic-bezier(0, 0, 0.2, 1);
|
|
||||||
transform-origin: top;
|
|
||||||
background: rgba(67, 67, 67, 0.97);
|
|
||||||
color: white;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.md-tooltip:hover .md-tooltip-content {
|
|
||||||
transform: translateX(-50%) scale(1);
|
|
||||||
}
|
|
||||||
@@ -1,601 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
"@material/animation@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/animation/-/animation-0.41.0.tgz#315b45b32e1aeebee8a4cf555b8ad52076d09ddd"
|
|
||||||
integrity sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==
|
|
||||||
|
|
||||||
"@material/auto-init@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/auto-init/-/auto-init-0.41.0.tgz#8a59bb0b83e0f51ead9508074f9a29b2b6a20eec"
|
|
||||||
integrity sha512-jp6L8MpYu7DudgDfA8iTyD9BwQrYPEDsIJGbqzN9vcCBl5FoBatkB8pcFXKr+1mRBk7T1Qmf6+H5nDtxyXjHEQ==
|
|
||||||
|
|
||||||
"@material/base@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/base/-/base-0.41.0.tgz#badadce711b4c25b1eb889a5e7581e32cd07c421"
|
|
||||||
integrity sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==
|
|
||||||
|
|
||||||
"@material/button@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/button/-/button-0.44.0.tgz#f01dcbea88bdc314e7640b76e5558101c8b4d69d"
|
|
||||||
integrity sha512-T8u8s8rlB49D9/5Nh5b0XsKRgSq3X0yWGo71MgaTnCnwxt8oZ6PxW/cH6Nn3Xp0NCr3mlSVQs08BviUfAmtlsg==
|
|
||||||
dependencies:
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/feature-targeting" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/card@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/card/-/card-0.44.0.tgz#e62050e3e77f525173a015119200055cd7b71bf0"
|
|
||||||
integrity sha512-fUixXuh133bVp5c1gPIHreL5jwMJEeVIQf0E4xdxhkA+i4ku8fIAvIW62EuCmfJsXicv4q8NG3Ip6pCY+NW3ZA==
|
|
||||||
dependencies:
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/checkbox@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.44.0.tgz#5d0eee1db006db9f0fb700bf1c20408292305cf7"
|
|
||||||
integrity sha512-IzucxG+NuPNyByGmHg/cuYJ5ooMKouuj994PZXZyqb7owfrjjtXm7wjav66cvCowbVbcoa1owQMGBi18C9f4TQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/chips@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/chips/-/chips-0.44.0.tgz#bf553a5bf5db7320978402ac92069c9688b84d5a"
|
|
||||||
integrity sha512-+qrme6sGwYmX/ixHAo3Z1M7lorsxRyKexn1l+BSBX5PBc2f4w5Ml1eYYYcyVGfLX9LXmefRk0G6dUXXPyCE00g==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/checkbox" "^0.44.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/dialog@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/dialog/-/dialog-0.44.0.tgz#388f93f9f225824c75cbe9da8c464a52d79972e8"
|
|
||||||
integrity sha512-V6ButfknOMKOscL0Y39yLjamxvrIuyugobjf5s44ZeJc+9jUSkC7M3zP+T7rh358NcX+JSPP8iCGmUn/+LXpMQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/dom" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
focus-trap "^4.0.2"
|
|
||||||
|
|
||||||
"@material/dom@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/dom/-/dom-0.41.0.tgz#6756865f97bad4c91ee75e69d769d7cdc25398ae"
|
|
||||||
integrity sha512-wOJrMwjPddYXpQFZAIaCLWI3TO/6KU1lxESTBzunni8A4FHQVWhokml5Xt85GqZwmPFeIF2s+D0wfbWyrGBuKQ==
|
|
||||||
|
|
||||||
"@material/drawer@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/drawer/-/drawer-0.44.0.tgz#74b3ddfb741bffc72331c7a73cf62716fd3f0ab3"
|
|
||||||
integrity sha512-AYwFe0jgqqSmJd1bny8JJTA2SScF86Wfbk99lXXEwd/acS8IbnnuH6zfAg6MyJX12FDb8dE8Z/Ok1IwLiVa9sQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/list" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
focus-trap "^4.0.2"
|
|
||||||
|
|
||||||
"@material/elevation@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/elevation/-/elevation-0.44.0.tgz#ca16a67188ce9810dc2fa3d7a39073e72df4b754"
|
|
||||||
integrity sha512-edNou34yFCSMb6XXe/6Y7AEh8DigWAhBUyIeMiMBD4k1km2xYCJbcnl8FBPJFteOrca97KoJComRlJPB6EurRQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/fab@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/fab/-/fab-0.44.0.tgz#0bcbbdfb6f24c53d59e08c9c0d400d2616dea184"
|
|
||||||
integrity sha512-1CEP4NlXDYioJ/YpSjh/MlIygtoC7CaHqIbucxX1O5WRPmS7K1uPt+o7netbLErAmcJdV/JrI/tqh9kKuX2x/Q==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/feature-targeting@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-0.44.0.tgz#52cc73f0c8a83159de0357aebe74f15f9856fb4c"
|
|
||||||
integrity sha512-ShuC2TOLfjFpYUCQFtvkqDJhM6HTaucSx5HkRbOvOG+VlpzDx6pAqRUmdVaq2p7tHoQf2vwPMlSVm3gOjWt4VQ==
|
|
||||||
|
|
||||||
"@material/floating-label@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-0.44.0.tgz#8694cd49f6905641b67a9e7a112b820d028f09c7"
|
|
||||||
integrity sha512-k4npGNxyMtnjgJZNjU5VvqqaUqlbzlbVAhepT8PxYTpj+4Skg6PjHwieTCDCgsbqHvFcQX+WfUrSZXY7wFV7cw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/form-field@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-0.44.0.tgz#b7518e885c0e953a2a5fe0140af927c30e066f4e"
|
|
||||||
integrity sha512-SK+V34dzoBCQ/CHn5nBp8BAh21Vj9p1pcok+/WpYBTeg4EphTYP2nUQLMNEN92l6zjgAYf+g9Ocj3t26HNHWqA==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/grid-list@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/grid-list/-/grid-list-0.44.0.tgz#bd31d992ab1a910731e4a47c11fe91d44e3bc02b"
|
|
||||||
integrity sha512-NxLL0A48K1O14ZZymFIyf6HDbF33+NgXYXqP2yosTC3Jw4iwmUcJTpFTmSw1U/m1xT4zEpeKEGJ4vjVUWpS9Mg==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/icon-button@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/icon-button/-/icon-button-0.44.0.tgz#febbcfd27d91eca8096ae042b9c07ed0f65345e9"
|
|
||||||
integrity sha512-n6L7RaRyEci6eGsuBTSEG+t9ATHAHaMlf9zuTWorEnIXY4DAmGO7ggBjw4+1XIOjhpLeIjyJdcvUK6Yz/UVM6Q==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/icon-toggle@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/icon-toggle/-/icon-toggle-0.44.0.tgz#b9de32f194b5aa9721ca799d59be0f477a5c5305"
|
|
||||||
integrity sha512-8T1b4iK61/q/3U0iIjEDJ9do5viCQ45IbrQqa8EYCZ1KDU/Q8z5N+bvOzQK8XnTL51BdDRMgP9lfQZh6nszmkA==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/image-list@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/image-list/-/image-list-0.44.0.tgz#a27996962044ac8c9ce6cb509f63746f08ed2e98"
|
|
||||||
integrity sha512-kI9aKJdc1Bd02l8nRTGG1wy/lNkECScfnBmCiLQ3XjAFtRYd2eWO0Z/AVvUG3egsIZnZBxqFGGsf5Htm9E/HiQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/layout-grid@^0.41.0":
|
|
||||||
version "0.41.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/layout-grid/-/layout-grid-0.41.0.tgz#2e7d3be76313e0684d573b10c2c6a88b3230d251"
|
|
||||||
integrity sha512-Sa5RNoTGgfIojqJ9E94p7/k11V6q/tGk7HwKi4AQNAPjxield0zcl3G/SbsSb8YSHoK+D+7OXDN+n11x6EqF7g==
|
|
||||||
|
|
||||||
"@material/line-ripple@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/line-ripple/-/line-ripple-0.43.0.tgz#6cb530bab53f055f3583646a21ad20c1703f3a83"
|
|
||||||
integrity sha512-sXZYW4Em5uLEnAuVsQCO+sVHsTg7J2TOTJ0+akwZFMmd2tmNicjarQdlGIE9iU7Wjm51NOoLAu6Mz+8kLg90bQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/linear-progress@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/linear-progress/-/linear-progress-0.43.0.tgz#4821424aa24c78de256e74a91d5be3df55c534d9"
|
|
||||||
integrity sha512-bqkDcob+xp1mFkyBsOkoaLgrtapmz7jznGoI3nmkqyk75EB2XQcn1H8Vr6cnp/jkF4nbKu0GdVJO3VXUFmGmrQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/list@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/list/-/list-0.44.0.tgz#cf1910e15b66759334b8618d1110fbcc72c3d326"
|
|
||||||
integrity sha512-35gkN1+XZaau9d9ngyN2x14bzkj/ajZCDm7mbWibDQy272A16j6KuFLQFA8RUQV04OgL4YPVxY87dpCn/p+uTg==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/dom" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/menu-surface@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/menu-surface/-/menu-surface-0.44.0.tgz#902c081df42859b925a5b4502791b3febf48f1ae"
|
|
||||||
integrity sha512-s49kvIlQ4H5wvMD4yeHMMqnamPod06IUagMK6Ry0oTpUANSnyeNXxa3HkScl7DMJiS8IJeV21fSLAzlZYP2PDQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/menu@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/menu/-/menu-0.44.0.tgz#776ec8a04406266a0a0a13eb140b1fd691e442cb"
|
|
||||||
integrity sha512-92XvAcv9rBW1jQ3UvwJ8zk9hbSRe/FqSuFdZ9fNPE348dCY2pbcdQfnUJTe3ycAN/I1c5frkrhx8F0II+nfbNQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/list" "^0.44.0"
|
|
||||||
"@material/menu-surface" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
|
|
||||||
"@material/notched-outline@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-0.44.0.tgz#d5a2e1d649921575a7cd2e88ee4581e4a1809573"
|
|
||||||
integrity sha512-c3nqOqUQAmW3h4zBbZVbMRdf4nNTYm0tVwXIAwmcCs5nvAthEHnzHwwFddNP7/9Wju6LZ0uqWn6xlyKly0uipw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/floating-label" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/radio@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/radio/-/radio-0.44.0.tgz#f4cacdfabc7d765aa000cb34c5a37966f6d4fd6d"
|
|
||||||
integrity sha512-ar7uhlfHuSwM9JUUjpv7pLDLE0p436cCMxNTpmMjWabfvo3pMWlExvk72Oj81tBgfxY/uASLB3oj4neudXu9JQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/ripple@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.44.0.tgz#98920ff8ec4bf5714c97df3d190f02f8a5b476cc"
|
|
||||||
integrity sha512-MlaW4nUDgzS0JOBfsUawXyTOilr0jn+xvTVn6PEaGh2rmhNA54AhixXvdsVUWE9lfmHAsZV0AJHz2z7nunNhbQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/feature-targeting" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/rtl@^0.42.0":
|
|
||||||
version "0.42.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/rtl/-/rtl-0.42.0.tgz#1836e78186c2d8b996f6fbf97adab203535335bc"
|
|
||||||
integrity sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==
|
|
||||||
|
|
||||||
"@material/select@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/select/-/select-0.44.0.tgz#8041b4fe6247d013b0f12685fbdf50aa9ff57b35"
|
|
||||||
integrity sha512-tw3/QIBLuRCT+5IXx4IPiJk7FzeGeR65JEizdRUItH8yzoIiQLs/b2i3KtHM2YBXHgeUcEBF2AOqPX2opdYhug==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/floating-label" "^0.44.0"
|
|
||||||
"@material/line-ripple" "^0.43.0"
|
|
||||||
"@material/menu" "^0.44.0"
|
|
||||||
"@material/menu-surface" "^0.44.0"
|
|
||||||
"@material/notched-outline" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/selection-control@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/selection-control/-/selection-control-0.44.0.tgz#63d5c65a47a9f54f5a0316b5ecdb5e5f35108609"
|
|
||||||
integrity sha512-HgCAPnMVMEj4X4ILkFSifqtZ3Tcc5HkU+Lfk9g0807sCaN/qBKWkYKLH2WJUbW8uk+MXK7DgP1khtS5zzanJWA==
|
|
||||||
dependencies:
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/shape@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/shape/-/shape-0.43.0.tgz#b877acfd8be8abc9ddcf6601eb60dd0588292415"
|
|
||||||
integrity sha512-KGnoQV4G2OQbMe5Lr5Xbk8XNlO93Qi/juxXtd2wrAfiaPmktD8ug0CwdVDOPBOmj9a0gX3Ofi9XWcoU+tLEVjg==
|
|
||||||
|
|
||||||
"@material/slider@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/slider/-/slider-0.44.0.tgz#2055df894eb725e541cde50a544719c07934755b"
|
|
||||||
integrity sha512-Lnn2fdUesXX4O0UpJzveEuOj+og+dXCwhal73u3l3NXEdc/eRgYxwWdF3ww4MmCZ786EwUmjb4vIc9olN4DO3A==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/snackbar@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/snackbar/-/snackbar-0.44.0.tgz#d98672b849f5f295e4fac2d474a9c80f11945518"
|
|
||||||
integrity sha512-KhCrmJm8Zu/ZZPuRCGfMKsZ0vudINlNgTjlOau0kQ/UgR1xBUvLOE8NjyXZr0RQz5obyW7xpyIWIpscn0IUeyw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/button" "^0.44.0"
|
|
||||||
"@material/dom" "^0.41.0"
|
|
||||||
"@material/icon-button" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/switch@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/switch/-/switch-0.44.0.tgz#f2cbb447437b12eb3bc7f0ec8318dbd3b4f0afce"
|
|
||||||
integrity sha512-EadCg6lHUF260R2Q/l++vXIITqacvbXlobSoewA5ib6y9BU2g7l13wL1W8xAVJNUMgFa/PyN+EKT3oCql7jZLg==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/tab-bar@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/tab-bar/-/tab-bar-0.44.0.tgz#b17d791bd557b1d84892fef1a1d8b8d6fef7c6d6"
|
|
||||||
integrity sha512-kCrt05d61YXyY43SNc0dPGuqysbcLr/KRDBvzpXgE4gv2jCCVhhjAH10KPlx8pthp/UtvrYJHb34acAKEGzdHA==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/tab" "^0.44.0"
|
|
||||||
"@material/tab-scroller" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/tab-indicator@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/tab-indicator/-/tab-indicator-0.43.0.tgz#37fd05513ba55ae218d9068c986c2676096fd6eb"
|
|
||||||
integrity sha512-RMNMQpWYghWpM6d0ayfuHEPzTiebKG0bMthViiD6tly8PubmOT8mShNhPm8ihybhDPUOLSz+7V4QNE5wikLEYg==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
|
|
||||||
"@material/tab-scroller@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/tab-scroller/-/tab-scroller-0.44.0.tgz#82d092ed45d2ee9d82038bed318e6ff6bdc36dad"
|
|
||||||
integrity sha512-Ufd3NWBN11kY2oA7bGmTYWGP1uz2mq0tfDM0JOiqoLMgD7y3Z18kmxnpq2qkg1vi4kvix28hBYGGMfLlq9rGDA==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/tab" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/tab@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/tab/-/tab-0.44.0.tgz#254b92cff99015f0bd59a86d08d3f1c4744d0742"
|
|
||||||
integrity sha512-czrbGjtKkmUS3iYBX523xT5GOkjP0h+0x9fTnw+heFNpw5dCn6cZvlj3D9ayZU+ZH93x68TFhFVBuLU5f0EBXw==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/tab-indicator" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/textfield@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.44.0.tgz#277b33948ddff33f7f643323895e5a683f013601"
|
|
||||||
integrity sha512-IMBwMcE82eVU+Wifpu0t84tozvBPLCeqQELDtZNYujKg3RxaultzJLwIyGKPMZ9R4yPEpV2vgXPGKE+2/AWt0g==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/floating-label" "^0.44.0"
|
|
||||||
"@material/line-ripple" "^0.43.0"
|
|
||||||
"@material/notched-outline" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/theme@^0.43.0":
|
|
||||||
version "0.43.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/theme/-/theme-0.43.0.tgz#6d9fa113c82e841817882172c152d60d2d203ca6"
|
|
||||||
integrity sha512-/zndZL6EihI18v2mYd4O8xvOBAAXmLeHyHVK28LozSAaJ9okQgD25wq5Ktk95oMTmPIC+rH66KcK6371ivNk8g==
|
|
||||||
|
|
||||||
"@material/toolbar@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/toolbar/-/toolbar-0.44.0.tgz#6689aecdeccc78b7a890a3abbe8b68a2c6339307"
|
|
||||||
integrity sha512-YgLlOFQ5VzFLQBpXYSMviEbYox0fia+sasHuYPUhTAtas1ExVt9EEiIolDSVvhv2PruTReKKefxSbXAqGlOHog==
|
|
||||||
dependencies:
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/top-app-bar@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/top-app-bar/-/top-app-bar-0.44.0.tgz#2495c7f9567568fb961ccced24f479c4806a72af"
|
|
||||||
integrity sha512-tf0yXQJARYs8UPaH8oo3LnsSHEiur7Zm8Fc3hv3F0gNRRaZYBjwsMQMVbZZaWoQCWskMALyntBg+Fo18zdgDxw==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
"@material/typography@^0.44.0":
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.44.0.tgz#cf61dce2ee89bfa084d86e1b0f270a585bf9dfaf"
|
|
||||||
integrity sha512-m4SjA9OjZRDKowN3cPzEa8e2GlTlEn3ZmW/Fy9eRNSp83iY+8a0xl6kCaF80v5qAVwVcpfEFyEHWxMJtkBw2uA==
|
|
||||||
|
|
||||||
"@types/prop-types@*":
|
|
||||||
version "15.5.8"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.8.tgz#8ae4e0ea205fe95c3901a5a1df7f66495e3a56ce"
|
|
||||||
integrity sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==
|
|
||||||
|
|
||||||
"@types/react-dom@^16.8.0":
|
|
||||||
version "16.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.0.tgz#c565f43f9d2ec911f9e0b8f3b74e25e67879aa3f"
|
|
||||||
integrity sha512-Jp4ufcEEjVJEB0OHq2MCZcE1u3KYUKO6WnSuiU/tZeYeiZxUoQavfa/TZeiIT+1XoN6l0lQVNM30VINZFDeolQ==
|
|
||||||
dependencies:
|
|
||||||
"@types/react" "*"
|
|
||||||
|
|
||||||
"@types/react@*", "@types/react@^16.8.2":
|
|
||||||
version "16.8.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.2.tgz#3b7a7f7ea89d1c7d68b00849fb5de839011c077b"
|
|
||||||
integrity sha512-6mcKsqlqkN9xADrwiUz2gm9Wg4iGnlVGciwBRYFQSMWG6MQjhOZ/AVnxn+6v8nslFgfYTV8fNdE6XwKu6va5PA==
|
|
||||||
dependencies:
|
|
||||||
"@types/prop-types" "*"
|
|
||||||
csstype "^2.2.0"
|
|
||||||
|
|
||||||
csstype@^2.2.0:
|
|
||||||
version "2.6.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.2.tgz#3043d5e065454579afc7478a18de41909c8a2f01"
|
|
||||||
integrity sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==
|
|
||||||
|
|
||||||
focus-trap@^4.0.2:
|
|
||||||
version "4.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-4.0.2.tgz#4ee2b96547c9ea0e4252a2d4b2cca68944194663"
|
|
||||||
integrity sha512-HtLjfAK7Hp2qbBtLS6wEznID1mPT+48ZnP2nkHzgjpL4kroYHg0CdqJ5cTXk+UO5znAxF5fRUkhdyfgrhh8Lzw==
|
|
||||||
dependencies:
|
|
||||||
tabbable "^3.1.2"
|
|
||||||
xtend "^4.0.1"
|
|
||||||
|
|
||||||
"js-tokens@^3.0.0 || ^4.0.0":
|
|
||||||
version "4.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
|
||||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
|
||||||
|
|
||||||
loose-envify@^1.1.0:
|
|
||||||
version "1.4.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
|
||||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
|
||||||
dependencies:
|
|
||||||
js-tokens "^3.0.0 || ^4.0.0"
|
|
||||||
|
|
||||||
material-components-web@^0.44.0:
|
|
||||||
version "0.44.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/material-components-web/-/material-components-web-0.44.0.tgz#ff782e8d7bdd8212d3c6022a731258d0d42da531"
|
|
||||||
integrity sha512-BSRLf58SMVhAvlDhJDlcgYuvzeMwbMHKTJ7oIB8LaM24ZpXBxP9XCYJpKheMtiVLrgllCGDlJ/47OIDReHQXdQ==
|
|
||||||
dependencies:
|
|
||||||
"@material/animation" "^0.41.0"
|
|
||||||
"@material/auto-init" "^0.41.0"
|
|
||||||
"@material/base" "^0.41.0"
|
|
||||||
"@material/button" "^0.44.0"
|
|
||||||
"@material/card" "^0.44.0"
|
|
||||||
"@material/checkbox" "^0.44.0"
|
|
||||||
"@material/chips" "^0.44.0"
|
|
||||||
"@material/dialog" "^0.44.0"
|
|
||||||
"@material/dom" "^0.41.0"
|
|
||||||
"@material/drawer" "^0.44.0"
|
|
||||||
"@material/elevation" "^0.44.0"
|
|
||||||
"@material/fab" "^0.44.0"
|
|
||||||
"@material/feature-targeting" "^0.44.0"
|
|
||||||
"@material/floating-label" "^0.44.0"
|
|
||||||
"@material/form-field" "^0.44.0"
|
|
||||||
"@material/grid-list" "^0.44.0"
|
|
||||||
"@material/icon-button" "^0.44.0"
|
|
||||||
"@material/icon-toggle" "^0.44.0"
|
|
||||||
"@material/image-list" "^0.44.0"
|
|
||||||
"@material/layout-grid" "^0.41.0"
|
|
||||||
"@material/line-ripple" "^0.43.0"
|
|
||||||
"@material/linear-progress" "^0.43.0"
|
|
||||||
"@material/list" "^0.44.0"
|
|
||||||
"@material/menu" "^0.44.0"
|
|
||||||
"@material/menu-surface" "^0.44.0"
|
|
||||||
"@material/notched-outline" "^0.44.0"
|
|
||||||
"@material/radio" "^0.44.0"
|
|
||||||
"@material/ripple" "^0.44.0"
|
|
||||||
"@material/rtl" "^0.42.0"
|
|
||||||
"@material/select" "^0.44.0"
|
|
||||||
"@material/selection-control" "^0.44.0"
|
|
||||||
"@material/shape" "^0.43.0"
|
|
||||||
"@material/slider" "^0.44.0"
|
|
||||||
"@material/snackbar" "^0.44.0"
|
|
||||||
"@material/switch" "^0.44.0"
|
|
||||||
"@material/tab" "^0.44.0"
|
|
||||||
"@material/tab-bar" "^0.44.0"
|
|
||||||
"@material/tab-indicator" "^0.43.0"
|
|
||||||
"@material/tab-scroller" "^0.44.0"
|
|
||||||
"@material/textfield" "^0.44.0"
|
|
||||||
"@material/theme" "^0.43.0"
|
|
||||||
"@material/toolbar" "^0.44.0"
|
|
||||||
"@material/top-app-bar" "^0.44.0"
|
|
||||||
"@material/typography" "^0.44.0"
|
|
||||||
|
|
||||||
object-assign@^4.1.1:
|
|
||||||
version "4.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
|
||||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
|
||||||
|
|
||||||
prop-types@^15.6.2:
|
|
||||||
version "15.7.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.1.tgz#2fa61e0a699d428b40320127733ee2931f05d9d1"
|
|
||||||
integrity sha512-f8Lku2z9kERjOCcnDOPm68EBJAO2K00Q5mSgPAUE/gJuBgsYLbVy6owSrtcHj90zt8PvW+z0qaIIgsIhHOa1Qw==
|
|
||||||
dependencies:
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
react-is "^16.8.1"
|
|
||||||
|
|
||||||
react-dom@^16.8.1:
|
|
||||||
version "16.8.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.1.tgz#ec860f98853d09d39bafd3a6f1e12389d283dbb4"
|
|
||||||
integrity sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
prop-types "^15.6.2"
|
|
||||||
scheduler "^0.13.1"
|
|
||||||
|
|
||||||
react-is@^16.8.1:
|
|
||||||
version "16.8.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.1.tgz#a80141e246eb894824fb4f2901c0c50ef31d4cdb"
|
|
||||||
integrity sha512-ioMCzVDWvCvKD8eeT+iukyWrBGrA3DiFYkXfBsVYIRdaREZuBjENG+KjrikavCLasozqRWTwFUagU/O4vPpRMA==
|
|
||||||
|
|
||||||
react@^16.8.1:
|
|
||||||
version "16.8.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-16.8.1.tgz#ae11831f6cb2a05d58603a976afc8a558e852c4a"
|
|
||||||
integrity sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
prop-types "^15.6.2"
|
|
||||||
scheduler "^0.13.1"
|
|
||||||
|
|
||||||
scheduler@^0.13.1:
|
|
||||||
version "0.13.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.1.tgz#1a217df1bfaabaf4f1b92a9127d5d732d85a9591"
|
|
||||||
integrity sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==
|
|
||||||
dependencies:
|
|
||||||
loose-envify "^1.1.0"
|
|
||||||
object-assign "^4.1.1"
|
|
||||||
|
|
||||||
tabbable@^3.1.2:
|
|
||||||
version "3.1.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2"
|
|
||||||
integrity sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==
|
|
||||||
|
|
||||||
xtend@^4.0.1:
|
|
||||||
version "4.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
|
||||||
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@coder/disposable",
|
|
||||||
"main": "src/index.ts"
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export interface IDisposable {
|
|
||||||
dispose(): void;
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from "./disposable";
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# This file specifies files that are *not* uploaded to Google Cloud Platform
|
|
||||||
# using gcloud. It follows the same syntax as .gitignore, with the addition of
|
|
||||||
# "#!include" directives (which insert the entries of the given .gitignore-style
|
|
||||||
# file at that point).
|
|
||||||
#
|
|
||||||
# For more information, run:
|
|
||||||
# $ gcloud topic gcloudignore
|
|
||||||
#
|
|
||||||
.gcloudignore
|
|
||||||
# If you would like to upload your .git directory, .gitignore file or files
|
|
||||||
# from your .gitignore file, remove the corresponding line
|
|
||||||
# below:
|
|
||||||
.git
|
|
||||||
.gitignore
|
|
||||||
src
|
|
||||||
|
|
||||||
# Node.js dependencies:
|
|
||||||
node_modules/
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
FROM node
|
|
||||||
|
|
||||||
COPY out/main.js /main.js
|
|
||||||
COPY package.json /package.json
|
|
||||||
RUN yarn
|
|
||||||
ENV NODE_ENV production
|
|
||||||
|
|
||||||
CMD ["node", "/main.js"]
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
runtime: nodejs10
|
|
||||||
service: cdrdns
|
|
||||||
network:
|
|
||||||
forwarded_ports:
|
|
||||||
- 53/udp
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@coder/dns",
|
|
||||||
"main": "out/main.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "../../node_modules/.bin/webpack --config ./webpack.config.js"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"node-named": "^0.0.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"ip-address": "^5.8.9",
|
|
||||||
"@types/ip-address": "^5.8.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
import { field, logger } from "@coder/logger";
|
|
||||||
import * as http from "http";
|
|
||||||
//@ts-ignore
|
|
||||||
import * as named from "node-named";
|
|
||||||
import * as ip from "ip-address";
|
|
||||||
import { words, wordKeys } from "./words";
|
|
||||||
|
|
||||||
import * as dgram from "dgram";
|
|
||||||
|
|
||||||
const oldCreate = dgram.createSocket;
|
|
||||||
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
(<any>dgram).createSocket = (_: any, callback: any): dgram.Socket => {
|
|
||||||
return oldCreate("udp4", callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface DnsQuery {
|
|
||||||
name(): string;
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
addAnswer(domain: string, target: any, ttl: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dnsServer: {
|
|
||||||
listen(port: number, host: string, callback: () => void): void;
|
|
||||||
on(event: "query", callback: (query: DnsQuery) => void): void;
|
|
||||||
send(query: DnsQuery): void;
|
|
||||||
} = named.createServer();
|
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV !== "production";
|
|
||||||
const dnsPort = isDev ? 9999 : 53;
|
|
||||||
dnsServer.listen(dnsPort, "0.0.0.0", () => {
|
|
||||||
logger.info("DNS server started", field("port", dnsPort));
|
|
||||||
});
|
|
||||||
|
|
||||||
dnsServer.on("query", (query) => {
|
|
||||||
const domain = query.name();
|
|
||||||
const reqParts = domain.split(".");
|
|
||||||
if (reqParts.length < 2) {
|
|
||||||
dnsServer.send(query);
|
|
||||||
logger.info("Invalid request", field("request", domain));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const allWords = reqParts.shift()!;
|
|
||||||
if (allWords.length > 16) {
|
|
||||||
dnsServer.send(query);
|
|
||||||
logger.info("Invalid request", field("request", domain));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const wordParts = allWords.split(/(?=[A-Z])/);
|
|
||||||
const ipParts: string[] = [];
|
|
||||||
// Should be left with HowAreYouNow
|
|
||||||
for (let i = 0; i < wordParts.length; i++) {
|
|
||||||
const part = wordParts[i];
|
|
||||||
if (part.length > 4) {
|
|
||||||
dnsServer.send(query);
|
|
||||||
logger.info("Words too long", field("request", domain));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const ipPart = words[part.toLowerCase()];
|
|
||||||
if (typeof ipPart === "undefined") {
|
|
||||||
dnsServer.send(query);
|
|
||||||
logger.info("Word not found in index", field("part", part), field("request", domain));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ipParts.push(ipPart.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
const address = new ip.Address4(ipParts.join("."));
|
|
||||||
|
|
||||||
if (address.isValid()) {
|
|
||||||
logger.info("Responded with valid address query", field("address", address.address), field("request", domain));
|
|
||||||
query.addAnswer(domain, new named.ARecord(address.address), 99999);
|
|
||||||
} else {
|
|
||||||
logger.warn("Received invalid request", field("request", domain));
|
|
||||||
}
|
|
||||||
|
|
||||||
dnsServer.send(query);
|
|
||||||
});
|
|
||||||
|
|
||||||
const httpServer = http.createServer((request, response) => {
|
|
||||||
const remoteAddr = request.connection.remoteAddress;
|
|
||||||
if (!remoteAddr) {
|
|
||||||
response.writeHead(422);
|
|
||||||
response.end();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const hostHeader = request.headers.host;
|
|
||||||
if (!hostHeader) {
|
|
||||||
response.writeHead(422);
|
|
||||||
response.end();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const host = remoteAddr.split(".").map(p => wordKeys[Number.parseInt(p, 10)]).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
||||||
logger.info("Resolved host", field("remote-addr", remoteAddr), field("host", host));
|
|
||||||
response.writeHead(200);
|
|
||||||
response.write(`${host}.${hostHeader}`);
|
|
||||||
response.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
const httpPort = isDev ? 3000 : 80;
|
|
||||||
httpServer.listen(httpPort, "0.0.0.0", () => {
|
|
||||||
logger.info("HTTP server started", field("port", httpPort));
|
|
||||||
});
|
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
export const words: { readonly [key: string]: number } = {
|
|
||||||
term: 0,
|
|
||||||
salt: 1,
|
|
||||||
barn: 2,
|
|
||||||
corn: 3,
|
|
||||||
went: 4,
|
|
||||||
feel: 5,
|
|
||||||
rest: 6,
|
|
||||||
will: 7,
|
|
||||||
pale: 8,
|
|
||||||
cave: 9,
|
|
||||||
dirt: 10,
|
|
||||||
time: 11,
|
|
||||||
in: 12,
|
|
||||||
pie: 13,
|
|
||||||
star: 14,
|
|
||||||
iron: 15,
|
|
||||||
door: 16,
|
|
||||||
tone: 17,
|
|
||||||
want: 18,
|
|
||||||
task: 19,
|
|
||||||
zoo: 20,
|
|
||||||
nor: 21,
|
|
||||||
fall: 22,
|
|
||||||
tell: 23,
|
|
||||||
noon: 24,
|
|
||||||
new: 25,
|
|
||||||
per: 26,
|
|
||||||
end: 27,
|
|
||||||
arm: 28,
|
|
||||||
been: 29,
|
|
||||||
wolf: 30,
|
|
||||||
port: 31,
|
|
||||||
beat: 32,
|
|
||||||
pour: 33,
|
|
||||||
far: 34,
|
|
||||||
may: 35,
|
|
||||||
tie: 36,
|
|
||||||
moon: 37,
|
|
||||||
duck: 38,
|
|
||||||
us: 39,
|
|
||||||
led: 40,
|
|
||||||
met: 41,
|
|
||||||
bank: 42,
|
|
||||||
day: 43,
|
|
||||||
due: 44,
|
|
||||||
both: 45,
|
|
||||||
pet: 46,
|
|
||||||
gate: 47,
|
|
||||||
pain: 48,
|
|
||||||
rock: 49,
|
|
||||||
fill: 50,
|
|
||||||
open: 51,
|
|
||||||
thus: 52,
|
|
||||||
mark: 53,
|
|
||||||
our: 54,
|
|
||||||
loud: 55,
|
|
||||||
wife: 56,
|
|
||||||
say: 57,
|
|
||||||
flag: 58,
|
|
||||||
as: 59,
|
|
||||||
ride: 60,
|
|
||||||
once: 61,
|
|
||||||
sun: 62,
|
|
||||||
duty: 63,
|
|
||||||
pure: 64,
|
|
||||||
made: 65,
|
|
||||||
gulf: 66,
|
|
||||||
pig: 67,
|
|
||||||
fish: 68,
|
|
||||||
name: 69,
|
|
||||||
army: 70,
|
|
||||||
have: 71,
|
|
||||||
ill: 72,
|
|
||||||
meal: 73,
|
|
||||||
ago: 74,
|
|
||||||
late: 75,
|
|
||||||
view: 76,
|
|
||||||
atom: 77,
|
|
||||||
pen: 78,
|
|
||||||
mud: 79,
|
|
||||||
tail: 80,
|
|
||||||
sink: 81,
|
|
||||||
cow: 82,
|
|
||||||
rear: 83,
|
|
||||||
fur: 84,
|
|
||||||
go: 85,
|
|
||||||
suit: 86,
|
|
||||||
come: 87,
|
|
||||||
fear: 88,
|
|
||||||
also: 89,
|
|
||||||
sail: 90,
|
|
||||||
row: 91,
|
|
||||||
lay: 92,
|
|
||||||
noun: 93,
|
|
||||||
hat: 94,
|
|
||||||
am: 95,
|
|
||||||
mail: 96,
|
|
||||||
keep: 97,
|
|
||||||
drop: 98,
|
|
||||||
than: 99,
|
|
||||||
weak: 100,
|
|
||||||
by: 101,
|
|
||||||
who: 102,
|
|
||||||
fire: 103,
|
|
||||||
good: 104,
|
|
||||||
sick: 105,
|
|
||||||
care: 106,
|
|
||||||
pink: 107,
|
|
||||||
lady: 108,
|
|
||||||
war: 109,
|
|
||||||
sets: 110,
|
|
||||||
swam: 111,
|
|
||||||
well: 112,
|
|
||||||
shoe: 113,
|
|
||||||
bent: 114,
|
|
||||||
fuel: 115,
|
|
||||||
wet: 116,
|
|
||||||
fog: 117,
|
|
||||||
land: 118,
|
|
||||||
lead: 119,
|
|
||||||
tax: 120,
|
|
||||||
deal: 121,
|
|
||||||
verb: 122,
|
|
||||||
take: 123,
|
|
||||||
save: 124,
|
|
||||||
gift: 125,
|
|
||||||
had: 126,
|
|
||||||
gold: 127,
|
|
||||||
slow: 128,
|
|
||||||
drew: 129,
|
|
||||||
lamp: 130,
|
|
||||||
roof: 131,
|
|
||||||
hung: 132,
|
|
||||||
wild: 133,
|
|
||||||
able: 134,
|
|
||||||
girl: 135,
|
|
||||||
warn: 136,
|
|
||||||
were: 137,
|
|
||||||
know: 138,
|
|
||||||
camp: 139,
|
|
||||||
milk: 140,
|
|
||||||
neck: 141,
|
|
||||||
aid: 142,
|
|
||||||
fair: 143,
|
|
||||||
bell: 144,
|
|
||||||
dig: 145,
|
|
||||||
hope: 146,
|
|
||||||
wood: 147,
|
|
||||||
away: 148,
|
|
||||||
cook: 149,
|
|
||||||
just: 150,
|
|
||||||
form: 151,
|
|
||||||
food: 152,
|
|
||||||
hall: 153,
|
|
||||||
mind: 154,
|
|
||||||
for: 155,
|
|
||||||
card: 156,
|
|
||||||
half: 157,
|
|
||||||
sat: 158,
|
|
||||||
now: 159,
|
|
||||||
team: 160,
|
|
||||||
rush: 161,
|
|
||||||
face: 162,
|
|
||||||
wire: 163,
|
|
||||||
such: 164,
|
|
||||||
tool: 165,
|
|
||||||
make: 166,
|
|
||||||
fat: 167,
|
|
||||||
hold: 168,
|
|
||||||
inch: 169,
|
|
||||||
bill: 170,
|
|
||||||
mean: 171,
|
|
||||||
tide: 172,
|
|
||||||
burn: 173,
|
|
||||||
talk: 174,
|
|
||||||
tape: 175,
|
|
||||||
hard: 176,
|
|
||||||
mine: 177,
|
|
||||||
on: 178,
|
|
||||||
year: 179,
|
|
||||||
rich: 180,
|
|
||||||
sum: 181,
|
|
||||||
yes: 182,
|
|
||||||
baby: 183,
|
|
||||||
wide: 184,
|
|
||||||
how: 185,
|
|
||||||
clay: 186,
|
|
||||||
car: 187,
|
|
||||||
here: 188,
|
|
||||||
cent: 189,
|
|
||||||
bowl: 190,
|
|
||||||
post: 191,
|
|
||||||
said: 192,
|
|
||||||
see: 193,
|
|
||||||
raw: 194,
|
|
||||||
foot: 195,
|
|
||||||
life: 196,
|
|
||||||
bar: 197,
|
|
||||||
from: 198,
|
|
||||||
path: 199,
|
|
||||||
meat: 200,
|
|
||||||
show: 201,
|
|
||||||
sent: 202,
|
|
||||||
wait: 203,
|
|
||||||
mice: 204,
|
|
||||||
ten: 205,
|
|
||||||
pot: 206,
|
|
||||||
nice: 207,
|
|
||||||
idea: 208,
|
|
||||||
or: 209,
|
|
||||||
onto: 210,
|
|
||||||
rose: 211,
|
|
||||||
your: 212,
|
|
||||||
this: 213,
|
|
||||||
cat: 214,
|
|
||||||
bet: 215,
|
|
||||||
took: 216,
|
|
||||||
hang: 217,
|
|
||||||
very: 218,
|
|
||||||
bend: 219,
|
|
||||||
mix: 220,
|
|
||||||
base: 221,
|
|
||||||
jack: 222,
|
|
||||||
her: 223,
|
|
||||||
leg: 224,
|
|
||||||
own: 225,
|
|
||||||
book: 226,
|
|
||||||
love: 227,
|
|
||||||
dawn: 228,
|
|
||||||
deer: 229,
|
|
||||||
hit: 230,
|
|
||||||
rain: 231,
|
|
||||||
gas: 232,
|
|
||||||
eat: 233,
|
|
||||||
tube: 234,
|
|
||||||
case: 235,
|
|
||||||
pipe: 236,
|
|
||||||
get: 237,
|
|
||||||
joy: 238,
|
|
||||||
ever: 239,
|
|
||||||
nest: 240,
|
|
||||||
home: 241,
|
|
||||||
egg: 242,
|
|
||||||
pack: 243,
|
|
||||||
hand: 244,
|
|
||||||
cold: 245,
|
|
||||||
hot: 246,
|
|
||||||
frog: 247,
|
|
||||||
peep: 248,
|
|
||||||
seed: 249,
|
|
||||||
rawr: 250,
|
|
||||||
top: 251,
|
|
||||||
meow: 252,
|
|
||||||
bark: 253,
|
|
||||||
eel: 254,
|
|
||||||
swap: 255,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const wordKeys = Object.keys(words);
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
const path = require("path");
|
|
||||||
const merge = require("webpack-merge");
|
|
||||||
|
|
||||||
const root = path.resolve(__dirname, "../..");
|
|
||||||
|
|
||||||
module.exports = merge(
|
|
||||||
require(path.join(root, "scripts/webpack.node.config.js"))({
|
|
||||||
// Options.
|
|
||||||
}), {
|
|
||||||
externals: {
|
|
||||||
"node-named": "commonjs node-named",
|
|
||||||
},
|
|
||||||
output: {
|
|
||||||
path: path.join(__dirname, "out"),
|
|
||||||
filename: "main.js",
|
|
||||||
},
|
|
||||||
entry: [
|
|
||||||
"./packages/dns/src/dns.ts"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
"@types/ip-address@^5.8.2":
|
|
||||||
version "5.8.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/ip-address/-/ip-address-5.8.2.tgz#5e413c477f78b3a264745eac937538a6e6e0c1f6"
|
|
||||||
integrity sha512-LFlDGRjJDnahfPyNCZGXvlaevSmZTi/zDxjTdXeTs8TQ9pQkNZKbCWaJXW29a3bGPRsASqeO+jGgZlaTUi9jTw==
|
|
||||||
dependencies:
|
|
||||||
"@types/jsbn" "*"
|
|
||||||
|
|
||||||
"@types/jsbn@*":
|
|
||||||
version "1.2.29"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/jsbn/-/jsbn-1.2.29.tgz#28229bc0262c704a1506c3ed69a7d7e115bd7832"
|
|
||||||
integrity sha512-2dVz9LTEGWVj9Ov9zaDnpvqHFV+W4bXtU0EUEGAzWfdRNO3dlUuosdHpENI6/oQW+Kejn0hAjk6P/czs9h/hvg==
|
|
||||||
|
|
||||||
bunyan@0.7.0:
|
|
||||||
version "0.7.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-0.7.0.tgz#921065e70c936fe302a740e2c5605775beea2f42"
|
|
||||||
integrity sha1-khBl5wyTb+MCp0DixWBXdb7qL0I=
|
|
||||||
|
|
||||||
"coffee-script@>= 1.1.1":
|
|
||||||
version "1.12.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53"
|
|
||||||
integrity sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==
|
|
||||||
|
|
||||||
ip-address@^5.8.9:
|
|
||||||
version "5.8.9"
|
|
||||||
resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-5.8.9.tgz#6379277c23fc5adb20511e4d23ec2c1bde105dfd"
|
|
||||||
integrity sha512-7ay355oMN34iXhET1BmCJVsHjOTSItEEIIpOs38qUC23AIhOy+xIPnkrTuEFjeLMrTJ7m8KMXWgWfy/2Vn9sDw==
|
|
||||||
dependencies:
|
|
||||||
jsbn "1.1.0"
|
|
||||||
lodash.find "^4.6.0"
|
|
||||||
lodash.max "^4.0.1"
|
|
||||||
lodash.merge "^4.6.0"
|
|
||||||
lodash.padstart "^4.6.1"
|
|
||||||
lodash.repeat "^4.1.0"
|
|
||||||
sprintf-js "1.1.0"
|
|
||||||
|
|
||||||
ipaddr.js@0.1.1:
|
|
||||||
version "0.1.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-0.1.1.tgz#28c6a7c116a021c555544f906ab1ad540b1d635a"
|
|
||||||
integrity sha1-KManwRagIcVVVE+QarGtVAsdY1o=
|
|
||||||
dependencies:
|
|
||||||
coffee-script ">= 1.1.1"
|
|
||||||
|
|
||||||
jsbn@1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
|
|
||||||
integrity sha1-sBMHyym2GKHtJux56RH4A8TaAEA=
|
|
||||||
|
|
||||||
lodash.find@^4.6.0:
|
|
||||||
version "4.6.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
|
|
||||||
integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=
|
|
||||||
|
|
||||||
lodash.max@^4.0.1:
|
|
||||||
version "4.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash.max/-/lodash.max-4.0.1.tgz#8735566c618b35a9f760520b487ae79658af136a"
|
|
||||||
integrity sha1-hzVWbGGLNan3YFILSHrnllivE2o=
|
|
||||||
|
|
||||||
lodash.merge@^4.6.0:
|
|
||||||
version "4.6.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
|
|
||||||
integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
|
|
||||||
|
|
||||||
lodash.padstart@^4.6.1:
|
|
||||||
version "4.6.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b"
|
|
||||||
integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=
|
|
||||||
|
|
||||||
lodash.repeat@^4.1.0:
|
|
||||||
version "4.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/lodash.repeat/-/lodash.repeat-4.1.0.tgz#fc7de8131d8c8ac07e4b49f74ffe829d1f2bec44"
|
|
||||||
integrity sha1-/H3oEx2MisB+S0n3T/6CnR8r7EQ=
|
|
||||||
|
|
||||||
node-named@^0.0.1:
|
|
||||||
version "0.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/node-named/-/node-named-0.0.1.tgz#3607b434cf237ab99440f5ff6d19c05e3a93e217"
|
|
||||||
integrity sha1-Nge0NM8jermUQPX/bRnAXjqT4hc=
|
|
||||||
dependencies:
|
|
||||||
bunyan "0.7.0"
|
|
||||||
ipaddr.js "0.1.1"
|
|
||||||
|
|
||||||
sprintf-js@1.1.0:
|
|
||||||
version "1.1.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.0.tgz#cffcaf702daf65ea39bb4e0fa2b299cec1a1be46"
|
|
||||||
integrity sha1-z/yvcC2vZeo5u04PorKZzsGhvkY=
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@coder/events",
|
|
||||||
"main": "./src/index.ts"
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
import { IDisposable } from "@coder/disposable";
|
|
||||||
|
|
||||||
export interface Event<T> {
|
|
||||||
(listener: (value: T) => void): IDisposable;
|
|
||||||
(id: number | string, listener: (value: T) => void): IDisposable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitter typecasts for a single event type. You can optionally use IDs, but
|
|
||||||
* using undefined with IDs will not work. If you emit without an ID, *all*
|
|
||||||
* listeners regardless of their ID (or lack thereof) will receive the event.
|
|
||||||
* Similarly, if you listen without an ID you will get *all* events for any or
|
|
||||||
* no ID.
|
|
||||||
*/
|
|
||||||
export class Emitter<T> {
|
|
||||||
private listeners = <Array<(value: T) => void>>[];
|
|
||||||
private readonly idListeners = new Map<number | string, Array<(value: T) => void>>();
|
|
||||||
|
|
||||||
public get event(): Event<T> {
|
|
||||||
return (id: number | string | ((value: T) => void), cb?: (value: T) => void): IDisposable => {
|
|
||||||
if (typeof id !== "function") {
|
|
||||||
if (this.idListeners.has(id)) {
|
|
||||||
this.idListeners.get(id)!.push(cb!);
|
|
||||||
} else {
|
|
||||||
this.idListeners.set(id, [cb!]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
dispose: (): void => {
|
|
||||||
if (this.idListeners.has(id)) {
|
|
||||||
const cbs = this.idListeners.get(id)!;
|
|
||||||
const i = cbs.indexOf(cb!);
|
|
||||||
if (i !== -1) {
|
|
||||||
cbs.splice(i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
cb = id;
|
|
||||||
this.listeners.push(cb);
|
|
||||||
|
|
||||||
return {
|
|
||||||
dispose: (): void => {
|
|
||||||
const i = this.listeners.indexOf(cb!);
|
|
||||||
if (i !== -1) {
|
|
||||||
this.listeners.splice(i, 1);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emit an event with a value.
|
|
||||||
*/
|
|
||||||
public emit(value: T): void;
|
|
||||||
public emit(id: number | string, value: T): void;
|
|
||||||
public emit(id: number | string | T, value?: T): void {
|
|
||||||
if ((typeof id === "number" || typeof id === "string") && typeof value !== "undefined") {
|
|
||||||
if (this.idListeners.has(id)) {
|
|
||||||
this.idListeners.get(id)!.forEach((cb) => cb(value!));
|
|
||||||
}
|
|
||||||
this.listeners.forEach((cb) => cb(value!));
|
|
||||||
} else {
|
|
||||||
this.idListeners.forEach((cbs) => cbs.forEach((cb) => cb((id as T)!)));
|
|
||||||
this.listeners.forEach((cb) => cb((id as T)!));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispose the current events.
|
|
||||||
*/
|
|
||||||
public dispose(): void;
|
|
||||||
public dispose(id: number | string): void;
|
|
||||||
public dispose(id?: number | string): void {
|
|
||||||
if (typeof id !== "undefined") {
|
|
||||||
this.idListeners.delete(id);
|
|
||||||
} else {
|
|
||||||
this.listeners = [];
|
|
||||||
this.idListeners.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public get counts(): { [key: string]: number } {
|
|
||||||
const counts = <{ [key: string]: number }>{};
|
|
||||||
if (this.listeners.length > 0) {
|
|
||||||
counts["n/a"] = this.listeners.length;
|
|
||||||
}
|
|
||||||
this.idListeners.forEach((cbs, id) => {
|
|
||||||
if (cbs.length > 0) {
|
|
||||||
counts[`${id}`] = cbs.length;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return counts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from "./events";
|
|
||||||
@@ -1,122 +0,0 @@
|
|||||||
import { Emitter } from "../src/events";
|
|
||||||
|
|
||||||
describe("Event", () => {
|
|
||||||
const emitter = new Emitter<number>();
|
|
||||||
|
|
||||||
it("should listen to global event", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
const d = emitter.event(fn);
|
|
||||||
emitter.emit(10);
|
|
||||||
expect(fn).toHaveBeenCalledWith(10);
|
|
||||||
d.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should listen to id event", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
const d = emitter.event(0, fn);
|
|
||||||
emitter.emit(0, 5);
|
|
||||||
expect(fn).toHaveBeenCalledWith(5);
|
|
||||||
d.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should listen to string id event", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
const d = emitter.event("string", fn);
|
|
||||||
emitter.emit("string", 55);
|
|
||||||
expect(fn).toHaveBeenCalledWith(55);
|
|
||||||
d.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not listen wrong id event", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
const d = emitter.event(1, fn);
|
|
||||||
emitter.emit(0, 5);
|
|
||||||
emitter.emit(1, 6);
|
|
||||||
expect(fn).toHaveBeenCalledWith(6);
|
|
||||||
expect(fn).toHaveBeenCalledTimes(1);
|
|
||||||
d.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should listen to id event globally", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
const d = emitter.event(fn);
|
|
||||||
emitter.emit(1, 11);
|
|
||||||
expect(fn).toHaveBeenCalledWith(11);
|
|
||||||
d.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should listen to global event", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
const d = emitter.event(3, fn);
|
|
||||||
emitter.emit(14);
|
|
||||||
expect(fn).toHaveBeenCalledWith(14);
|
|
||||||
d.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should listen to id event multiple times", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
const disposers = [
|
|
||||||
emitter.event(934, fn),
|
|
||||||
emitter.event(934, fn),
|
|
||||||
emitter.event(934, fn),
|
|
||||||
emitter.event(934, fn),
|
|
||||||
];
|
|
||||||
emitter.emit(934, 324);
|
|
||||||
expect(fn).toHaveBeenCalledTimes(4);
|
|
||||||
expect(fn).toHaveBeenCalledWith(324);
|
|
||||||
disposers.forEach((d) => d.dispose());
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should dispose individually", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
const d = emitter.event(fn);
|
|
||||||
|
|
||||||
const fn2 = jest.fn();
|
|
||||||
const d2 = emitter.event(1, fn2);
|
|
||||||
|
|
||||||
d.dispose();
|
|
||||||
|
|
||||||
emitter.emit(12);
|
|
||||||
emitter.emit(1, 12);
|
|
||||||
|
|
||||||
expect(fn).not.toBeCalled();
|
|
||||||
expect(fn2).toBeCalledTimes(2);
|
|
||||||
|
|
||||||
d2.dispose();
|
|
||||||
|
|
||||||
emitter.emit(12);
|
|
||||||
emitter.emit(1, 12);
|
|
||||||
|
|
||||||
expect(fn).not.toBeCalled();
|
|
||||||
expect(fn2).toBeCalledTimes(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should dispose by id", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
emitter.event(fn);
|
|
||||||
|
|
||||||
const fn2 = jest.fn();
|
|
||||||
emitter.event(1, fn2);
|
|
||||||
|
|
||||||
emitter.dispose(1);
|
|
||||||
|
|
||||||
emitter.emit(12);
|
|
||||||
emitter.emit(1, 12);
|
|
||||||
|
|
||||||
expect(fn).toBeCalledTimes(2);
|
|
||||||
expect(fn2).not.toBeCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should dispose all", () => {
|
|
||||||
const fn = jest.fn();
|
|
||||||
emitter.event(fn);
|
|
||||||
emitter.event(1, fn);
|
|
||||||
|
|
||||||
emitter.dispose();
|
|
||||||
|
|
||||||
emitter.emit(12);
|
|
||||||
emitter.emit(1, 12);
|
|
||||||
|
|
||||||
expect(fn).not.toBeCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
# ide-api
|
|
||||||
|
|
||||||
Provides window listeners for interfacing with the IDE.
|
|
||||||
|
|
||||||
Created for content-scripts.
|
|
||||||
221
packages/ide-api/api.d.ts
vendored
@@ -1,221 +0,0 @@
|
|||||||
// tslint:disable no-any
|
|
||||||
|
|
||||||
export interface EvalHelper { }
|
|
||||||
interface ActiveEvalEmitter {
|
|
||||||
removeAllListeners(event?: string): void;
|
|
||||||
emit(event: string, ...args: any[]): void;
|
|
||||||
on(event: string, cb: (...args: any[]) => void): void;
|
|
||||||
}
|
|
||||||
interface IDisposable {
|
|
||||||
dispose(): void;
|
|
||||||
}
|
|
||||||
interface Disposer extends IDisposable {
|
|
||||||
onDidDispose: (cb: () => void) => void;
|
|
||||||
}
|
|
||||||
interface Event<T> {
|
|
||||||
(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable;
|
|
||||||
}
|
|
||||||
interface IAction extends IDisposable {
|
|
||||||
id: string;
|
|
||||||
label: string;
|
|
||||||
tooltip: string;
|
|
||||||
class: string | undefined;
|
|
||||||
enabled: boolean;
|
|
||||||
checked: boolean;
|
|
||||||
radio: boolean;
|
|
||||||
run(event?: any): Promise<any>;
|
|
||||||
}
|
|
||||||
interface IStatusbarEntry {
|
|
||||||
readonly text: string;
|
|
||||||
readonly tooltip?: string;
|
|
||||||
readonly color?: string;
|
|
||||||
readonly command?: string;
|
|
||||||
readonly arguments?: any[];
|
|
||||||
readonly showBeak?: boolean;
|
|
||||||
}
|
|
||||||
interface IStatusbarService {
|
|
||||||
addEntry(entry: IStatusbarEntry, alignment: ide.StatusbarAlignment, priority?: number): IDisposable;
|
|
||||||
setStatusMessage(message: string, autoDisposeAfter?: number, delayBy?: number): IDisposable;
|
|
||||||
}
|
|
||||||
type NotificationMessage = string | Error;
|
|
||||||
interface INotificationProperties {
|
|
||||||
sticky?: boolean;
|
|
||||||
silent?: boolean;
|
|
||||||
}
|
|
||||||
interface INotification extends INotificationProperties {
|
|
||||||
severity: ide.Severity;
|
|
||||||
message: NotificationMessage;
|
|
||||||
source?: string;
|
|
||||||
actions?: INotificationActions;
|
|
||||||
}
|
|
||||||
interface INotificationActions {
|
|
||||||
primary?: IAction[];
|
|
||||||
secondary?: IAction[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface INotificationProgress {
|
|
||||||
infinite(): void;
|
|
||||||
total(value: number): void;
|
|
||||||
worked(value: number): void;
|
|
||||||
done(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface INotificationHandle {
|
|
||||||
readonly onDidClose: Event<void>;
|
|
||||||
readonly progress: INotificationProgress;
|
|
||||||
updateSeverity(severity: ide.Severity): void;
|
|
||||||
updateMessage(message: NotificationMessage): void;
|
|
||||||
updateActions(actions?: INotificationActions): void;
|
|
||||||
close(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IPromptChoice {
|
|
||||||
label: string;
|
|
||||||
isSecondary?: boolean;
|
|
||||||
keepOpen?: boolean;
|
|
||||||
run: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IPromptOptions extends INotificationProperties {
|
|
||||||
onCancel?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface INotificationService {
|
|
||||||
notify(notification: INotification): INotificationHandle;
|
|
||||||
info(message: NotificationMessage | NotificationMessage[]): void;
|
|
||||||
warn(message: NotificationMessage | NotificationMessage[]): void;
|
|
||||||
error(message: NotificationMessage | NotificationMessage[]): void;
|
|
||||||
prompt(severity: ide.Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IBaseCommandAction {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
category?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ICommandAction extends IBaseCommandAction {
|
|
||||||
// iconLocation?: { dark: URI; light?: URI; };
|
|
||||||
// precondition?: ContextKeyExpr;
|
|
||||||
// toggled?: ContextKeyExpr;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ISerializableCommandAction extends IBaseCommandAction {
|
|
||||||
// iconLocation?: { dark: UriComponents; light?: UriComponents; };
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMenuItem {
|
|
||||||
command: ICommandAction;
|
|
||||||
alt?: ICommandAction;
|
|
||||||
// when?: ContextKeyExpr;
|
|
||||||
group?: "navigation" | string;
|
|
||||||
order?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IMenuRegistry {
|
|
||||||
appendMenuItem(menu: ide.MenuId, item: IMenuItem): IDisposable;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICommandHandler {
|
|
||||||
(accessor: any, ...args: any[]): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICommand {
|
|
||||||
id: string;
|
|
||||||
handler: ICommandHandler;
|
|
||||||
description?: ICommandHandlerDescription | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICommandHandlerDescription {
|
|
||||||
description: string;
|
|
||||||
args: { name: string; description?: string; }[];
|
|
||||||
returns?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ICommandRegistry {
|
|
||||||
registerCommand(command: ICommand): IDisposable;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare namespace ide {
|
|
||||||
export const client: {};
|
|
||||||
|
|
||||||
export const workbench: {
|
|
||||||
readonly statusbarService: IStatusbarService;
|
|
||||||
readonly notificationService: INotificationService;
|
|
||||||
readonly menuRegistry: IMenuRegistry;
|
|
||||||
readonly commandRegistry: ICommandRegistry;
|
|
||||||
|
|
||||||
onFileCreate(cb: (path: string) => void): void;
|
|
||||||
onFileMove(cb: (path: string, target: string) => void): void;
|
|
||||||
onFileDelete(cb: (path: string) => void): void;
|
|
||||||
onFileSaved(cb: (path: string) => void): void;
|
|
||||||
onFileCopy(cb: (path: string, target: string) => void): void;
|
|
||||||
|
|
||||||
onModelAdded(cb: (path: string, languageId: string) => void): void;
|
|
||||||
onModelRemoved(cb: (path: string, languageId: string) => void): void;
|
|
||||||
onModelLanguageChange(cb: (path: string, languageId: string, oldLanguageId: string) => void): void;
|
|
||||||
|
|
||||||
onTerminalAdded(cb: () => void): void;
|
|
||||||
onTerminalRemoved(cb: () => void): void;
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum Severity {
|
|
||||||
Ignore = 0,
|
|
||||||
Info = 1,
|
|
||||||
Warning = 2,
|
|
||||||
Error = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum StatusbarAlignment {
|
|
||||||
LEFT = 0,
|
|
||||||
RIGHT = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum MenuId {
|
|
||||||
CommandPalette,
|
|
||||||
DebugBreakpointsContext,
|
|
||||||
DebugCallStackContext,
|
|
||||||
DebugConsoleContext,
|
|
||||||
DebugVariablesContext,
|
|
||||||
DebugWatchContext,
|
|
||||||
EditorContext,
|
|
||||||
EditorTitle,
|
|
||||||
EditorTitleContext,
|
|
||||||
EmptyEditorGroupContext,
|
|
||||||
ExplorerContext,
|
|
||||||
MenubarAppearanceMenu,
|
|
||||||
MenubarDebugMenu,
|
|
||||||
MenubarEditMenu,
|
|
||||||
MenubarFileMenu,
|
|
||||||
MenubarGoMenu,
|
|
||||||
MenubarHelpMenu,
|
|
||||||
MenubarLayoutMenu,
|
|
||||||
MenubarNewBreakpointMenu,
|
|
||||||
MenubarPreferencesMenu,
|
|
||||||
MenubarRecentMenu,
|
|
||||||
MenubarSelectionMenu,
|
|
||||||
MenubarSwitchEditorMenu,
|
|
||||||
MenubarSwitchGroupMenu,
|
|
||||||
MenubarTerminalMenu,
|
|
||||||
MenubarViewMenu,
|
|
||||||
OpenEditorsContext,
|
|
||||||
ProblemsPanelContext,
|
|
||||||
SCMChangeContext,
|
|
||||||
SCMResourceContext,
|
|
||||||
SCMResourceGroupContext,
|
|
||||||
SCMSourceControl,
|
|
||||||
SCMTitle,
|
|
||||||
SearchContext,
|
|
||||||
TouchBarContext,
|
|
||||||
ViewItemContext,
|
|
||||||
ViewTitle,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
ide?: typeof ide;
|
|
||||||
|
|
||||||
addEventListener(event: "ide-ready", callback: (ide: CustomEvent & { readonly ide: typeof ide }) => void): void;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@coder/ide-api",
|
|
||||||
"version": "1.0.3",
|
|
||||||
"typings": "api.d.ts",
|
|
||||||
"author": "Coder",
|
|
||||||
"license": "MIT",
|
|
||||||
"description": "API for interfacing with the API created for content-scripts"
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
||||||
# yarn lockfile v1
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@coder/ide",
|
|
||||||
"description": "Browser-based IDE client abstraction.",
|
|
||||||
"main": "src/index.ts"
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
import { field, logger, time, Time } from "@coder/logger";
|
|
||||||
import { SharedProcessData } from "@coder/protocol";
|
|
||||||
import { retry } from "./retry";
|
|
||||||
import { upload } from "./upload";
|
|
||||||
import { client } from "./fill/client";
|
|
||||||
import { clipboard } from "./fill/clipboard";
|
|
||||||
import { INotificationService, IProgressService } from "./fill/notification";
|
|
||||||
import "./fill/os"; // Ensure it fills before anything else waiting on initData.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A general abstraction of an IDE client.
|
|
||||||
*
|
|
||||||
* Everything the client provides is asynchronous so you can wait on what
|
|
||||||
* you need from it without blocking anything else.
|
|
||||||
*
|
|
||||||
* It also provides task management to help asynchronously load and time code.
|
|
||||||
*/
|
|
||||||
export abstract class IdeClient {
|
|
||||||
public readonly retry = retry;
|
|
||||||
public readonly clipboard = clipboard;
|
|
||||||
public readonly upload = upload;
|
|
||||||
|
|
||||||
private start: Time | undefined;
|
|
||||||
private readonly tasks = <string[]>[];
|
|
||||||
private finishedTaskCount = 0;
|
|
||||||
private readonly loadTime: Time;
|
|
||||||
|
|
||||||
public readonly initData = client.initData;
|
|
||||||
public readonly sharedProcessData: Promise<SharedProcessData>;
|
|
||||||
public readonly onSharedProcessActive = client.onSharedProcessActive;
|
|
||||||
|
|
||||||
public constructor() {
|
|
||||||
logger.info("Loading IDE");
|
|
||||||
this.loadTime = time(2500);
|
|
||||||
|
|
||||||
let appWindow: Window | undefined;
|
|
||||||
window.addEventListener("message", (event) => {
|
|
||||||
if (event.data === "app") {
|
|
||||||
appWindow = event.source as Window;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.sharedProcessData = new Promise((resolve): void => {
|
|
||||||
client.onSharedProcessActive(resolve);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("contextmenu", (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Prevent Firefox from trying to reconnect when the page unloads.
|
|
||||||
window.addEventListener("unload", () => {
|
|
||||||
this.retry.block();
|
|
||||||
logger.info("Unloaded");
|
|
||||||
});
|
|
||||||
|
|
||||||
this.initialize().then(() => {
|
|
||||||
logger.info("Load completed", field("duration", this.loadTime));
|
|
||||||
if (appWindow) {
|
|
||||||
appWindow.postMessage("loaded", "*");
|
|
||||||
}
|
|
||||||
}).catch((error) => {
|
|
||||||
logger.error(error.message);
|
|
||||||
logger.warn("Load completed with errors", field("duration", this.loadTime));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrap a task in some logging, timing, and progress updates. Can optionally
|
|
||||||
* wait on other tasks which won't count towards this task's time.
|
|
||||||
*/
|
|
||||||
public async task<T>(description: string, duration: number, task: () => Promise<T>): Promise<T>;
|
|
||||||
public async task<T, V>(description: string, duration: number, task: (v: V) => Promise<T>, t: Promise<V>): Promise<T>;
|
|
||||||
public async task<T, V1, V2>(description: string, duration: number, task: (v1: V1, v2: V2) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>): Promise<T>;
|
|
||||||
public async task<T, V1, V2, V3>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>): Promise<T>;
|
|
||||||
public async task<T, V1, V2, V3, V4>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>): Promise<T>;
|
|
||||||
public async task<T, V1, V2, V3, V4, V5>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>): Promise<T>;
|
|
||||||
public async task<T, V1, V2, V3, V4, V5, V6>(description: string, duration: number, task: (v1: V1, v2: V2, v3: V3, v4: V4, v5: V5, v6: V6) => Promise<T>, t1: Promise<V1>, t2: Promise<V2>, t3: Promise<V3>, t4: Promise<V4>, t5: Promise<V5>, t6: Promise<V6>): Promise<T>;
|
|
||||||
public async task<T>(
|
|
||||||
description: string, duration: number = 100, task: (...args: any[]) => Promise<T>, ...after: Array<Promise<any>> // tslint:disable-line no-any
|
|
||||||
): Promise<T> {
|
|
||||||
this.tasks.push(description);
|
|
||||||
if (!this.start) {
|
|
||||||
this.start = time(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
let start: Time | undefined;
|
|
||||||
try {
|
|
||||||
const waitFor = await (after && after.length > 0 ? Promise.all(after) : Promise.resolve([]));
|
|
||||||
start = time(duration);
|
|
||||||
logger.info(description);
|
|
||||||
const value = await task(...waitFor);
|
|
||||||
logger.info(`Finished "${description}"`, field("duration", start));
|
|
||||||
const index = this.tasks.indexOf(description);
|
|
||||||
if (index !== -1) {
|
|
||||||
this.tasks.splice(index, 1);
|
|
||||||
}
|
|
||||||
++this.finishedTaskCount;
|
|
||||||
if (this.tasks.length === 0) {
|
|
||||||
logger.info("Finished all queued tasks", field("duration", this.start), field("count", this.finishedTaskCount));
|
|
||||||
this.start = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
} catch (error) {
|
|
||||||
logger.error(`Failed "${description}"`, field("duration", typeof start !== "undefined" ? start : "not started"), field("error", error));
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public set notificationService(service: INotificationService) {
|
|
||||||
this.retry.notificationService = service;
|
|
||||||
this.upload.notificationService = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set progressService(service: IProgressService) {
|
|
||||||
this.upload.progressService = service;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the IDE.
|
|
||||||
*/
|
|
||||||
protected abstract initialize(): Promise<void>;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { Module } from "@coder/protocol";
|
|
||||||
import { client } from "./client";
|
|
||||||
|
|
||||||
export = client.modules[Module.ChildProcess];
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
import { Emitter } from "@coder/events";
|
|
||||||
import { field, logger } from "@coder/logger";
|
|
||||||
import { Client, ReadWriteConnection } from "@coder/protocol";
|
|
||||||
import { retry } from "../retry";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A connection based on a web socket. Automatically reconnects and buffers
|
|
||||||
* messages during connection.
|
|
||||||
*/
|
|
||||||
class WebsocketConnection implements ReadWriteConnection {
|
|
||||||
private activeSocket: WebSocket | undefined;
|
|
||||||
private readonly messageBuffer = <Uint8Array[]>[];
|
|
||||||
private readonly socketTimeoutDelay = 60 * 1000;
|
|
||||||
private readonly retryName = "Socket";
|
|
||||||
private isUp: boolean = false;
|
|
||||||
private closed: boolean = false;
|
|
||||||
|
|
||||||
private readonly messageEmitter = new Emitter<Uint8Array>();
|
|
||||||
private readonly closeEmitter = new Emitter<void>();
|
|
||||||
private readonly upEmitter = new Emitter<void>();
|
|
||||||
private readonly downEmitter = new Emitter<void>();
|
|
||||||
|
|
||||||
public readonly onUp = this.upEmitter.event;
|
|
||||||
public readonly onClose = this.closeEmitter.event;
|
|
||||||
public readonly onDown = this.downEmitter.event;
|
|
||||||
public readonly onMessage = this.messageEmitter.event;
|
|
||||||
|
|
||||||
public constructor() {
|
|
||||||
retry.register(this.retryName, () => this.connect());
|
|
||||||
retry.block(this.retryName);
|
|
||||||
retry.run(this.retryName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public send(data: Buffer | Uint8Array): void {
|
|
||||||
if (this.closed) {
|
|
||||||
throw new Error("web socket is closed");
|
|
||||||
}
|
|
||||||
if (!this.activeSocket || this.activeSocket.readyState !== this.activeSocket.OPEN) {
|
|
||||||
this.messageBuffer.push(data);
|
|
||||||
} else {
|
|
||||||
this.activeSocket.send(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public close(): void {
|
|
||||||
this.closed = true;
|
|
||||||
this.dispose();
|
|
||||||
this.closeEmitter.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect to the server.
|
|
||||||
*/
|
|
||||||
private async connect(): Promise<void> {
|
|
||||||
const socket = await this.openSocket();
|
|
||||||
|
|
||||||
socket.addEventListener("message", (event: MessageEvent) => {
|
|
||||||
this.messageEmitter.emit(event.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.addEventListener("close", (event) => {
|
|
||||||
if (this.isUp) {
|
|
||||||
this.isUp = false;
|
|
||||||
try {
|
|
||||||
this.downEmitter.emit(undefined);
|
|
||||||
} catch (error) {
|
|
||||||
// Don't let errors here prevent restarting.
|
|
||||||
logger.error(error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.warn(
|
|
||||||
"Web socket closed",
|
|
||||||
field("code", event.code),
|
|
||||||
field("reason", event.reason),
|
|
||||||
field("wasClean", event.wasClean),
|
|
||||||
);
|
|
||||||
if (!this.closed) {
|
|
||||||
retry.block(this.retryName);
|
|
||||||
retry.run(this.retryName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Send any messages that were queued while we were waiting to connect.
|
|
||||||
while (this.messageBuffer.length > 0) {
|
|
||||||
socket.send(this.messageBuffer.shift()!);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.isUp) {
|
|
||||||
this.isUp = true;
|
|
||||||
this.upEmitter.emit(undefined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open a web socket, disposing the previous connection if any.
|
|
||||||
*/
|
|
||||||
private async openSocket(): Promise<WebSocket> {
|
|
||||||
this.dispose();
|
|
||||||
const wsProto = location.protocol === "https:" ? "wss" : "ws";
|
|
||||||
const socket = new WebSocket(
|
|
||||||
`${wsProto}://${location.host}${location.pathname}`,
|
|
||||||
);
|
|
||||||
socket.binaryType = "arraybuffer";
|
|
||||||
this.activeSocket = socket;
|
|
||||||
|
|
||||||
const socketWaitTimeout = window.setTimeout(() => {
|
|
||||||
socket.close();
|
|
||||||
}, this.socketTimeoutDelay);
|
|
||||||
|
|
||||||
await new Promise((resolve, reject): void => {
|
|
||||||
const onClose = (): void => {
|
|
||||||
clearTimeout(socketWaitTimeout);
|
|
||||||
socket.removeEventListener("close", onClose);
|
|
||||||
reject();
|
|
||||||
};
|
|
||||||
socket.addEventListener("close", onClose);
|
|
||||||
|
|
||||||
socket.addEventListener("open", async () => {
|
|
||||||
clearTimeout(socketWaitTimeout);
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispose the current connection.
|
|
||||||
*/
|
|
||||||
private dispose(): void {
|
|
||||||
if (this.activeSocket) {
|
|
||||||
this.activeSocket.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global instance so all fills can use the same client.
|
|
||||||
export const client = new Client(new WebsocketConnection());
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
import { Emitter } from "@coder/events";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper around the native clipboard with some fallbacks.
|
|
||||||
*/
|
|
||||||
export class Clipboard {
|
|
||||||
private readonly enableEmitter = new Emitter<boolean>();
|
|
||||||
public readonly onPermissionChange = this.enableEmitter.event;
|
|
||||||
private _isEnabled: boolean = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask for permission to use the clipboard.
|
|
||||||
*/
|
|
||||||
public initialize(): void {
|
|
||||||
// tslint:disable no-any
|
|
||||||
const navigatorClip = (navigator as any).clipboard;
|
|
||||||
const navigatorPerms = (navigator as any).permissions;
|
|
||||||
// tslint:enable no-any
|
|
||||||
if (navigatorClip && navigatorPerms) {
|
|
||||||
navigatorPerms.query({
|
|
||||||
name: "clipboard-read",
|
|
||||||
}).then((permissionStatus: {
|
|
||||||
onchange: () => void,
|
|
||||||
state: "denied" | "granted" | "prompt",
|
|
||||||
}) => {
|
|
||||||
const updateStatus = (): void => {
|
|
||||||
this._isEnabled = permissionStatus.state !== "denied";
|
|
||||||
this.enableEmitter.emit(this.isEnabled);
|
|
||||||
};
|
|
||||||
updateStatus();
|
|
||||||
permissionStatus.onchange = (): void => {
|
|
||||||
updateStatus();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Paste currently copied text.
|
|
||||||
*/
|
|
||||||
public async paste(): Promise<boolean> {
|
|
||||||
if (this.isEnabled) {
|
|
||||||
try {
|
|
||||||
const element = document.activeElement as HTMLInputElement | HTMLTextAreaElement;
|
|
||||||
const start = element.selectionStart || 0;
|
|
||||||
const end = element.selectionEnd;
|
|
||||||
const allText = element.value;
|
|
||||||
const newText = allText.substring(0, start)
|
|
||||||
+ (await this.readText())
|
|
||||||
+ allText.substring(end || start);
|
|
||||||
element.value = newText;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (ex) {
|
|
||||||
// Will try execCommand below.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return document.execCommand("paste");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the native clipboard is supported.
|
|
||||||
*/
|
|
||||||
public get isSupported(): boolean {
|
|
||||||
// tslint:disable no-any
|
|
||||||
return typeof navigator !== "undefined"
|
|
||||||
&& typeof (navigator as any).clipboard !== "undefined"
|
|
||||||
&& typeof (navigator as any).clipboard.readText !== "undefined";
|
|
||||||
// tslint:enable no-any
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read text from the clipboard.
|
|
||||||
*/
|
|
||||||
public readText(): Promise<string> {
|
|
||||||
return this.instance ? this.instance.readText() : Promise.resolve("");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write text to the clipboard.
|
|
||||||
*/
|
|
||||||
public writeText(value: string): Promise<void> {
|
|
||||||
return this.instance
|
|
||||||
? this.instance.writeText(value)
|
|
||||||
: this.writeTextFallback(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the clipboard is currently enabled.
|
|
||||||
*/
|
|
||||||
public get isEnabled(): boolean {
|
|
||||||
return !!this._isEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return clipboard instance if there is one.
|
|
||||||
*/
|
|
||||||
private get instance(): ({
|
|
||||||
readText(): Promise<string>;
|
|
||||||
writeText(value: string): Promise<void>;
|
|
||||||
}) | undefined {
|
|
||||||
// tslint:disable-next-line no-any
|
|
||||||
return this.isSupported ? (navigator as any).clipboard : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fallback for writing text to the clipboard.
|
|
||||||
* Taken from https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f
|
|
||||||
*/
|
|
||||||
private writeTextFallback(value: string): Promise<void> {
|
|
||||||
// Note the current focus and selection.
|
|
||||||
const active = document.activeElement as HTMLElement;
|
|
||||||
const selection = document.getSelection();
|
|
||||||
const selected = selection && selection.rangeCount > 0
|
|
||||||
? selection.getRangeAt(0)
|
|
||||||
: false;
|
|
||||||
|
|
||||||
// Insert a hidden textarea to put the text to copy in.
|
|
||||||
const el = document.createElement("textarea");
|
|
||||||
el.value = value;
|
|
||||||
el.setAttribute("readonly", "");
|
|
||||||
el.style.position = "absolute";
|
|
||||||
el.style.left = "-9999px";
|
|
||||||
document.body.appendChild(el);
|
|
||||||
|
|
||||||
// Select the textarea and execute a copy (this will only work as part of a
|
|
||||||
// user interaction).
|
|
||||||
el.select();
|
|
||||||
document.execCommand("copy");
|
|
||||||
|
|
||||||
// Remove the textarea and put focus and selection back to where it was
|
|
||||||
// previously.
|
|
||||||
document.body.removeChild(el);
|
|
||||||
active.focus();
|
|
||||||
if (selected && selection) {
|
|
||||||
selection.removeAllRanges();
|
|
||||||
selection.addRange(selected);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global clipboard instance since it's used in the Electron fill.
|
|
||||||
export const clipboard = new Clipboard();
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
.msgbox {
|
|
||||||
padding-top: 25px;
|
|
||||||
padding-left: 40px;
|
|
||||||
padding-right: 40px;
|
|
||||||
padding-bottom: 25px;
|
|
||||||
background: #242424;
|
|
||||||
-webkit-box-shadow: 0px 0px 10px -3px rgba(0,0,0,0.75);
|
|
||||||
-moz-box-shadow: 0px 0px 10px -3px rgba(0,0,0,0.75);
|
|
||||||
box-shadow: 0px 0px 10px -3px rgba(0,0,0,0.75);
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox.input {
|
|
||||||
max-width: 500px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .input {
|
|
||||||
background: #141414;
|
|
||||||
border: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 10px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .msg {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .detail {
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .errors {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .errors {
|
|
||||||
color: #f44747;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .button-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .button-wrapper > button {
|
|
||||||
flex: 1;
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 10px;
|
|
||||||
color: white;
|
|
||||||
background: #3d3d3d;
|
|
||||||
border: 0px;
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .button-wrapper > button:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox > .button-wrapper > button:not(:last-child) {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.msgbox-overlay {
|
|
||||||
align-items: center;
|
|
||||||
background: rgba(0, 0, 0, 0.4);
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
left: 0;
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
transition: 300ms opacity ease;
|
|
||||||
z-index: 15;
|
|
||||||
}
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
import { Emitter } from "@coder/events";
|
|
||||||
|
|
||||||
import "./dialog.scss";
|
|
||||||
|
|
||||||
export interface IDialogOptions {
|
|
||||||
message?: string;
|
|
||||||
detail?: string;
|
|
||||||
buttons?: string[];
|
|
||||||
input?: {
|
|
||||||
value: string;
|
|
||||||
selection?: {
|
|
||||||
start: number;
|
|
||||||
end: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IDialogAction {
|
|
||||||
buttonIndex?: number;
|
|
||||||
key?: IKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum IKey {
|
|
||||||
Enter = "Enter",
|
|
||||||
Escape = "Escape",
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Dialog {
|
|
||||||
private readonly overlay: HTMLElement;
|
|
||||||
private cachedActiveElement: HTMLElement | undefined;
|
|
||||||
private input: HTMLInputElement | undefined;
|
|
||||||
private errors: HTMLElement;
|
|
||||||
private buttons: HTMLElement[] | undefined;
|
|
||||||
private readonly msgBox: HTMLElement;
|
|
||||||
|
|
||||||
private actionEmitter = new Emitter<IDialogAction>();
|
|
||||||
public onAction = this.actionEmitter.event;
|
|
||||||
|
|
||||||
public constructor(private readonly options: IDialogOptions) {
|
|
||||||
this.msgBox = document.createElement("div");
|
|
||||||
this.msgBox.classList.add("msgbox");
|
|
||||||
|
|
||||||
if (this.options.message) {
|
|
||||||
const messageDiv = document.createElement("div");
|
|
||||||
messageDiv.classList.add("msg");
|
|
||||||
messageDiv.innerText = this.options.message;
|
|
||||||
this.msgBox.appendChild(messageDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.options.detail) {
|
|
||||||
const detailDiv = document.createElement("div");
|
|
||||||
detailDiv.classList.add("detail");
|
|
||||||
detailDiv.innerText = this.options.detail;
|
|
||||||
this.msgBox.appendChild(detailDiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.options.input) {
|
|
||||||
this.msgBox.classList.add("input");
|
|
||||||
this.input = document.createElement("input");
|
|
||||||
this.input.classList.add("input");
|
|
||||||
this.input.value = this.options.input.value;
|
|
||||||
this.input.addEventListener("keydown", (event) => {
|
|
||||||
if (event.key === IKey.Enter) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.actionEmitter.emit({
|
|
||||||
buttonIndex: undefined,
|
|
||||||
key: IKey.Enter,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.msgBox.appendChild(this.input);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.errors = document.createElement("div");
|
|
||||||
this.errors.classList.add("errors");
|
|
||||||
|
|
||||||
if (this.options.buttons && this.options.buttons.length > 0) {
|
|
||||||
this.buttons = this.options.buttons.map((buttonText, buttonIndex) => {
|
|
||||||
const button = document.createElement("button");
|
|
||||||
// TODO: support mnemonics.
|
|
||||||
button.innerText = buttonText.replace("&&", "");
|
|
||||||
button.addEventListener("click", () => {
|
|
||||||
this.actionEmitter.emit({
|
|
||||||
buttonIndex,
|
|
||||||
key: undefined,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return button;
|
|
||||||
});
|
|
||||||
|
|
||||||
const buttonWrapper = document.createElement("div");
|
|
||||||
buttonWrapper.classList.add("button-wrapper");
|
|
||||||
this.buttons.forEach((b) => buttonWrapper.appendChild(b));
|
|
||||||
this.msgBox.appendChild(buttonWrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.overlay = document.createElement("div");
|
|
||||||
this.overlay.className = "msgbox-overlay";
|
|
||||||
this.overlay.appendChild(this.msgBox);
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
this.overlay.style.opacity = "1";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Input value if this dialog has an input.
|
|
||||||
*/
|
|
||||||
public get inputValue(): string | undefined {
|
|
||||||
return this.input ? this.input.value : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display or remove an error.
|
|
||||||
*/
|
|
||||||
public set error(error: string | undefined) {
|
|
||||||
while (this.errors.lastChild) {
|
|
||||||
this.errors.removeChild(this.errors.lastChild);
|
|
||||||
}
|
|
||||||
if (error) {
|
|
||||||
const errorDiv = document.createElement("error");
|
|
||||||
errorDiv.innerText = error;
|
|
||||||
this.errors.appendChild(errorDiv);
|
|
||||||
this.msgBox.appendChild(this.errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the dialog.
|
|
||||||
*/
|
|
||||||
public show(): void {
|
|
||||||
if (!this.cachedActiveElement) {
|
|
||||||
this.cachedActiveElement = document.activeElement as HTMLElement;
|
|
||||||
(document.getElementById("workbench.main.container") || document.body).appendChild(this.overlay);
|
|
||||||
document.addEventListener("keydown", this.onKeydown);
|
|
||||||
if (this.input) {
|
|
||||||
this.input.focus();
|
|
||||||
if (this.options.input && this.options.input.selection) {
|
|
||||||
this.input.setSelectionRange(
|
|
||||||
this.options.input.selection.start,
|
|
||||||
this.options.input.selection.end,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (this.buttons) {
|
|
||||||
this.buttons[0].focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the dialog and clean up.
|
|
||||||
*/
|
|
||||||
public hide(): void {
|
|
||||||
if (this.cachedActiveElement) {
|
|
||||||
this.overlay.remove();
|
|
||||||
document.removeEventListener("keydown", this.onKeydown);
|
|
||||||
this.cachedActiveElement.focus();
|
|
||||||
this.cachedActiveElement = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capture escape.
|
|
||||||
*/
|
|
||||||
private onKeydown = (event: KeyboardEvent): void => {
|
|
||||||
if (event.key === "Escape") {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
this.actionEmitter.emit({
|
|
||||||
buttonIndex: undefined,
|
|
||||||
key: IKey.Escape,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,451 +0,0 @@
|
|||||||
/// <reference path="../../../../lib/vscode/src/typings/electron.d.ts" />
|
|
||||||
import { EventEmitter } from "events";
|
|
||||||
import * as fs from "fs";
|
|
||||||
import * as trash from "trash";
|
|
||||||
import { logger, field } from "@coder/logger";
|
|
||||||
import { IKey, Dialog as DialogBox } from "./dialog";
|
|
||||||
import { clipboard } from "./clipboard";
|
|
||||||
|
|
||||||
// tslint:disable-next-line no-any
|
|
||||||
(global as any).getOpenUrls = (): string[] => {
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is required to make the fill load in Node without erroring.
|
|
||||||
if (typeof document === "undefined") {
|
|
||||||
// tslint:disable-next-line no-any
|
|
||||||
(global as any).document = {} as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldCreateElement = document.createElement;
|
|
||||||
const newCreateElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K] => {
|
|
||||||
const createElement = <K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K] => {
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
return oldCreateElement.call(document, tagName as any);
|
|
||||||
};
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
const getPropertyDescriptor = (object: any, id: string): PropertyDescriptor | undefined => {
|
|
||||||
let op = Object.getPrototypeOf(object);
|
|
||||||
while (!Object.getOwnPropertyDescriptor(op, id)) {
|
|
||||||
op = Object.getPrototypeOf(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.getOwnPropertyDescriptor(op, id);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (tagName === "img") {
|
|
||||||
const img = createElement("img");
|
|
||||||
const oldSrc = getPropertyDescriptor(img, "src");
|
|
||||||
if (!oldSrc) {
|
|
||||||
throw new Error("Failed to find src property");
|
|
||||||
}
|
|
||||||
Object.defineProperty(img, "src", {
|
|
||||||
get: (): string => {
|
|
||||||
return oldSrc!.get!.call(img);
|
|
||||||
},
|
|
||||||
set: (value: string): void => {
|
|
||||||
if (value) {
|
|
||||||
value = value.replace(/file:\/\//g, "/resource");
|
|
||||||
}
|
|
||||||
oldSrc!.set!.call(img, value);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return img;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tagName === "style") {
|
|
||||||
const style = createElement("style");
|
|
||||||
const oldInnerHtml = getPropertyDescriptor(style, "innerHTML");
|
|
||||||
if (!oldInnerHtml) {
|
|
||||||
throw new Error("Failed to find innerHTML property");
|
|
||||||
}
|
|
||||||
Object.defineProperty(style, "innerHTML", {
|
|
||||||
get: (): string => {
|
|
||||||
return oldInnerHtml!.get!.call(style);
|
|
||||||
},
|
|
||||||
set: (value: string): void => {
|
|
||||||
if (value) {
|
|
||||||
value = value.replace(/file:\/\//g, "/resource");
|
|
||||||
}
|
|
||||||
oldInnerHtml!.set!.call(style, value);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
let overridden = false;
|
|
||||||
const oldSheet = getPropertyDescriptor(style, "sheet");
|
|
||||||
Object.defineProperty(style, "sheet", {
|
|
||||||
// tslint:disable-next-line:no-any
|
|
||||||
get: (): any => {
|
|
||||||
const sheet = oldSheet!.get!.call(style);
|
|
||||||
if (sheet && !overridden) {
|
|
||||||
const oldInsertRule = sheet.insertRule;
|
|
||||||
sheet.insertRule = (rule: string, index?: number): void => {
|
|
||||||
rule = rule.replace(/file:\/\//g, "/resource");
|
|
||||||
oldInsertRule.call(sheet, rule, index);
|
|
||||||
};
|
|
||||||
overridden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sheet;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tagName === "webview") {
|
|
||||||
const view = createElement("iframe") as HTMLIFrameElement;
|
|
||||||
view.style.border = "0px";
|
|
||||||
const frameID = Math.random().toString();
|
|
||||||
view.addEventListener("error", (event) => {
|
|
||||||
logger.error("iframe error", field("event", event));
|
|
||||||
});
|
|
||||||
window.addEventListener("message", (event) => {
|
|
||||||
if (!event.data || !event.data.id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (event.data.id !== frameID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const e = new CustomEvent("ipc-message");
|
|
||||||
(e as any).channel = event.data.channel; // tslint:disable-line no-any
|
|
||||||
(e as any).args = event.data.data; // tslint:disable-line no-any
|
|
||||||
view.dispatchEvent(e);
|
|
||||||
});
|
|
||||||
view.sandbox.add("allow-same-origin", "allow-scripts", "allow-popups", "allow-forms");
|
|
||||||
Object.defineProperty(view, "preload", {
|
|
||||||
set: (url: string): void => {
|
|
||||||
view.onload = (): void => {
|
|
||||||
if (view.contentDocument) {
|
|
||||||
view.contentDocument.body.id = frameID;
|
|
||||||
view.contentDocument.body.parentElement!.style.overflow = "hidden";
|
|
||||||
const script = createElement("script");
|
|
||||||
script.src = url;
|
|
||||||
script.addEventListener("load", () => {
|
|
||||||
view.contentDocument!.dispatchEvent(new Event("DOMContentLoaded", {
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true,
|
|
||||||
}));
|
|
||||||
// const e = new CustomEvent("ipc-message");
|
|
||||||
// (e as any).channel = "webview-ready"; // tslint:disable-line no-any
|
|
||||||
// (e as any).args = [frameID]; // tslint:disable-line no-any
|
|
||||||
// view.dispatchEvent(e);
|
|
||||||
});
|
|
||||||
view.contentDocument.head.appendChild(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
(view as any).getWebContents = (): void => undefined; // tslint:disable-line no-any
|
|
||||||
(view as any).send = (channel: string, ...args: any[]): void => { // tslint:disable-line no-any
|
|
||||||
if (args[0] && typeof args[0] === "object" && args[0].contents) {
|
|
||||||
// TODO
|
|
||||||
args[0].contents = (args[0].contents as string).replace(/"(file:\/\/[^"]*)"/g, (m1) => `"/resource${m1}"`);
|
|
||||||
args[0].contents = (args[0].contents as string).replace(/"vscode-resource:([^"]*)"/g, (m, m1) => `"/resource${m1}"`);
|
|
||||||
args[0].contents = (args[0].contents as string).replace(/style-src vscode-core-resource:/g, "style-src 'self'");
|
|
||||||
}
|
|
||||||
if (view.contentWindow) {
|
|
||||||
view.contentWindow.postMessage({
|
|
||||||
channel,
|
|
||||||
data: args,
|
|
||||||
id: frameID,
|
|
||||||
}, "*");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
return createElement(tagName);
|
|
||||||
};
|
|
||||||
|
|
||||||
document.createElement = newCreateElement;
|
|
||||||
|
|
||||||
class Clipboard {
|
|
||||||
public has(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public readFindText(): string {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public writeFindText(_text: string): void {
|
|
||||||
// Nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
public writeText(value: string): Promise<void> {
|
|
||||||
return clipboard.writeText(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Shell {
|
|
||||||
public async moveItemToTrash(path: string): Promise<void> {
|
|
||||||
await trash(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class App extends EventEmitter {
|
|
||||||
public isAccessibilitySupportEnabled(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setAsDefaultProtocolClient(): void {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Dialog {
|
|
||||||
public showSaveDialog(_: void, options: Electron.SaveDialogOptions, callback: (filename: string | undefined) => void): void {
|
|
||||||
const defaultPath = options.defaultPath || "/untitled";
|
|
||||||
const fileIndex = defaultPath.lastIndexOf("/");
|
|
||||||
const extensionIndex = defaultPath.lastIndexOf(".");
|
|
||||||
const saveDialogOptions = {
|
|
||||||
buttons: ["Cancel", "Save"],
|
|
||||||
detail: "Enter a path for this file",
|
|
||||||
input: {
|
|
||||||
value: defaultPath,
|
|
||||||
selection: {
|
|
||||||
start: fileIndex === -1 ? 0 : fileIndex + 1,
|
|
||||||
end: extensionIndex === -1 ? defaultPath.length : extensionIndex,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
message: "Save file",
|
|
||||||
};
|
|
||||||
|
|
||||||
const dialog = new DialogBox(saveDialogOptions);
|
|
||||||
dialog.onAction((action) => {
|
|
||||||
if (action.key !== IKey.Enter && action.buttonIndex !== 1) {
|
|
||||||
dialog.hide();
|
|
||||||
|
|
||||||
return callback(undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
const inputValue = dialog.inputValue || "";
|
|
||||||
const filePath = inputValue.replace(/\/+$/, "");
|
|
||||||
const split = filePath.split("/");
|
|
||||||
const fileName = split.pop();
|
|
||||||
const parentName = split.pop() || "/";
|
|
||||||
if (fileName === "") {
|
|
||||||
dialog.error = "You must enter a file name.";
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.stat(filePath, (error, stats) => {
|
|
||||||
if (error && error.code === "ENOENT") {
|
|
||||||
dialog.hide();
|
|
||||||
callback(filePath);
|
|
||||||
} else if (error) {
|
|
||||||
dialog.error = error.message;
|
|
||||||
} else if (stats.isDirectory()) {
|
|
||||||
dialog.error = `A directory named "${fileName}" already exists.`;
|
|
||||||
} else {
|
|
||||||
dialog.error = undefined;
|
|
||||||
|
|
||||||
const confirmDialog = new DialogBox({
|
|
||||||
message: `A file named "${fileName}" already exists. Do you want to replace it?`,
|
|
||||||
detail: `The file already exists in "${parentName}". Replacing it will overwrite its contents.`,
|
|
||||||
buttons: ["Cancel", "Replace"],
|
|
||||||
});
|
|
||||||
|
|
||||||
confirmDialog.onAction((action) => {
|
|
||||||
if (action.buttonIndex === 1) {
|
|
||||||
confirmDialog.hide();
|
|
||||||
|
|
||||||
return callback(filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
confirmDialog.hide();
|
|
||||||
dialog.show();
|
|
||||||
});
|
|
||||||
|
|
||||||
dialog.hide();
|
|
||||||
confirmDialog.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public showOpenDialog(): void {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
public showMessageBox(_: void, options: Electron.MessageBoxOptions, callback: (button: number | undefined, checked: boolean) => void): void {
|
|
||||||
const dialog = new DialogBox(options);
|
|
||||||
dialog.onAction((action) => {
|
|
||||||
dialog.hide();
|
|
||||||
callback(action.buttonIndex, false);
|
|
||||||
});
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebFrame {
|
|
||||||
public getZoomFactor(): number {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getZoomLevel(): number {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setZoomLevel(): void {
|
|
||||||
// Nothing.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Screen {
|
|
||||||
public getAllDisplays(): [] {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebRequest extends EventEmitter {
|
|
||||||
public onBeforeRequest(): void {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
public onBeforeSendHeaders(): void {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
public onHeadersReceived(): void {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Session extends EventEmitter {
|
|
||||||
public webRequest = new WebRequest();
|
|
||||||
|
|
||||||
public resolveProxy(url: string, callback: (proxy: string) => void): void {
|
|
||||||
// TODO: not sure what this actually does.
|
|
||||||
callback(url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebContents extends EventEmitter {
|
|
||||||
public session = new Session();
|
|
||||||
}
|
|
||||||
|
|
||||||
class BrowserWindow extends EventEmitter {
|
|
||||||
public webContents = new WebContents();
|
|
||||||
private representedFilename: string = "";
|
|
||||||
|
|
||||||
public static getFocusedWindow(): undefined {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
public focus(): void {
|
|
||||||
window.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public show(): void {
|
|
||||||
window.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public reload(): void {
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
public isMaximized(): boolean {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setFullScreen(fullscreen: boolean): void {
|
|
||||||
if (fullscreen) {
|
|
||||||
document.documentElement.requestFullscreen();
|
|
||||||
} else {
|
|
||||||
document.exitFullscreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public isFullScreen(): boolean {
|
|
||||||
return document.fullscreenEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isFocused(): boolean {
|
|
||||||
return document.hasFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public setMenuBarVisibility(): void {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
public setAutoHideMenuBar(): void {
|
|
||||||
throw new Error("not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
public setRepresentedFilename(filename: string): void {
|
|
||||||
this.representedFilename = filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getRepresentedFilename(): string {
|
|
||||||
return this.representedFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setTitle(value: string): void {
|
|
||||||
document.title = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We won't be able to do a 1 to 1 fill because things like moveItemToTrash for
|
|
||||||
* example returns a boolean while we need a promise.
|
|
||||||
*/
|
|
||||||
class ElectronFill {
|
|
||||||
public readonly shell = new Shell();
|
|
||||||
public readonly clipboard = new Clipboard();
|
|
||||||
public readonly app = new App();
|
|
||||||
public readonly dialog = new Dialog();
|
|
||||||
public readonly webFrame = new WebFrame();
|
|
||||||
public readonly screen = new Screen();
|
|
||||||
|
|
||||||
private readonly rendererToMainEmitter = new EventEmitter();
|
|
||||||
private readonly mainToRendererEmitter = new EventEmitter();
|
|
||||||
|
|
||||||
public get BrowserWindow(): typeof BrowserWindow {
|
|
||||||
return BrowserWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
// tslint:disable no-any
|
|
||||||
public get ipcRenderer(): object {
|
|
||||||
return {
|
|
||||||
send: (str: string, ...args: any[]): void => {
|
|
||||||
this.rendererToMainEmitter.emit(str, {
|
|
||||||
sender: module.exports.ipcMain,
|
|
||||||
}, ...args);
|
|
||||||
},
|
|
||||||
on: (str: string, listener: (...args: any[]) => void): void => {
|
|
||||||
this.mainToRendererEmitter.on(str, listener);
|
|
||||||
},
|
|
||||||
once: (str: string, listener: (...args: any[]) => void): void => {
|
|
||||||
this.mainToRendererEmitter.once(str, listener);
|
|
||||||
},
|
|
||||||
removeListener: (str: string, listener: (...args: any[]) => void): void => {
|
|
||||||
this.mainToRendererEmitter.removeListener(str, listener);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public get ipcMain(): object {
|
|
||||||
return {
|
|
||||||
send: (str: string, ...args: any[]): void => {
|
|
||||||
this.mainToRendererEmitter.emit(str, {
|
|
||||||
sender: module.exports.ipcRenderer,
|
|
||||||
}, ...args);
|
|
||||||
},
|
|
||||||
on: (str: string, listener: (...args: any[]) => void): void => {
|
|
||||||
this.rendererToMainEmitter.on(str, listener);
|
|
||||||
},
|
|
||||||
once: (str: string, listener: (...args: any[]) => void): void => {
|
|
||||||
this.rendererToMainEmitter.once(str, listener);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// tslint:enable no-any
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = new ElectronFill();
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export = {};
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { Module } from "@coder/protocol";
|
|
||||||
import { client } from "./client";
|
|
||||||
|
|
||||||
export = client.modules[Module.Fs];
|
|
||||||