Upgrade to latest Seed, remove JS WebSocket, remove webpack dependency
This commit is contained in:
parent
9625cde0f6
commit
39ee462e33
358
Cargo.lock
generated
358
Cargo.lock
generated
@ -15,7 +15,7 @@ dependencies = [
|
|||||||
"derive_more",
|
"derive_more",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@ -35,7 +35,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
]
|
]
|
||||||
@ -54,7 +54,7 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"http",
|
"http",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"trust-dns-proto",
|
"trust-dns-proto",
|
||||||
"trust-dns-resolver",
|
"trust-dns-resolver",
|
||||||
]
|
]
|
||||||
@ -84,10 +84,10 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding",
|
||||||
"v_htmlescape",
|
"v_htmlescape",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -124,12 +124,12 @@ dependencies = [
|
|||||||
"indexmap",
|
"indexmap",
|
||||||
"language-tags",
|
"language-tags",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"regex 1.3.6",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
@ -161,7 +161,7 @@ dependencies = [
|
|||||||
"derive_more",
|
"derive_more",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"httparse",
|
"httparse",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
"time 0.1.42",
|
"time 0.1.42",
|
||||||
"twoway",
|
"twoway",
|
||||||
@ -175,8 +175,8 @@ checksum = "9d7a10ca4d94e8c8e7a87c5173aba1b97ba9a6563ca02b0e1cd23531093d3ec8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytestring",
|
"bytestring",
|
||||||
"http",
|
"http",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"regex 1.3.6",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ dependencies = [
|
|||||||
"actix-service",
|
"actix-service",
|
||||||
"actix-utils",
|
"actix-utils",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"mio",
|
"mio",
|
||||||
"mio-uds",
|
"mio-uds",
|
||||||
"net2",
|
"net2",
|
||||||
@ -233,7 +233,7 @@ dependencies = [
|
|||||||
"actix-server",
|
"actix-server",
|
||||||
"actix-service",
|
"actix-service",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"net2",
|
"net2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -246,7 +246,7 @@ dependencies = [
|
|||||||
"derive_more",
|
"derive_more",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"threadpool",
|
"threadpool",
|
||||||
@ -265,7 +265,7 @@ dependencies = [
|
|||||||
"derive_more",
|
"derive_more",
|
||||||
"either",
|
"either",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -281,7 +281,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"either",
|
"either",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
@ -310,16 +310,16 @@ dependencies = [
|
|||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"fxhash",
|
"fxhash",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
"net2",
|
"net2",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"regex 1.3.6",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"time 0.1.42",
|
"time 0.1.42",
|
||||||
"url 2.1.1",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -365,22 +365,13 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aho-corasick"
|
|
||||||
version = "0.5.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
|
||||||
dependencies = [
|
|
||||||
"memchr 0.1.11",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.10"
|
version = "0.7.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr 2.3.3",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -464,9 +455,9 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -709,7 +700,7 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"pest",
|
"pest",
|
||||||
"pest_derive",
|
"pest_derive",
|
||||||
"regex 1.3.6",
|
"regex",
|
||||||
"twoway",
|
"twoway",
|
||||||
"typed-arena",
|
"typed-arena",
|
||||||
"unicode_categories",
|
"unicode_categories",
|
||||||
@ -733,12 +724,12 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cookie"
|
name = "cookie"
|
||||||
version = "0.12.0"
|
version = "0.13.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
|
checksum = "0c60ef6d0bbf56ad2674249b6bb74f2c6aeb98b98dd57b5d3e37cace33011d69"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"time 0.1.42",
|
"percent-encoding",
|
||||||
"url 1.7.2",
|
"time 0.2.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1025,16 +1016,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_logger"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
|
|
||||||
dependencies = [
|
|
||||||
"log 0.3.9",
|
|
||||||
"regex 0.1.80",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@ -1043,8 +1024,8 @@ checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"humantime",
|
"humantime",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"regex 1.3.6",
|
"regex",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1261,7 +1242,7 @@ dependencies = [
|
|||||||
"futures-macro",
|
"futures-macro",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"memchr 2.3.3",
|
"memchr",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
"proc-macro-nested",
|
"proc-macro-nested",
|
||||||
@ -1304,6 +1285,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1312,12 +1294,37 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gloo-events"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "088514ec8ef284891c762c88a66b639b3a730134714692ee31829765c5bc814f"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gloo-file"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f9fecfe46b5dc3cc46f58e98ba580cc714f2c93860796d002eb3527a465ef49"
|
||||||
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"gloo-events",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gloo-timers"
|
name = "gloo-timers"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
|
checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"futures-channel",
|
||||||
|
"futures-core",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
@ -1336,7 +1343,7 @@ dependencies = [
|
|||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
@ -1448,7 +1455,7 @@ dependencies = [
|
|||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
"itoa",
|
"itoa",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"net2",
|
"net2",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"time 0.1.42",
|
"time 0.1.42",
|
||||||
@ -1470,17 +1477,6 @@ dependencies = [
|
|||||||
"tokio-tls",
|
"tokio-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
|
||||||
dependencies = [
|
|
||||||
"matches",
|
|
||||||
"unicode-bidi",
|
|
||||||
"unicode-normalization",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1600,21 +1596,20 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"diesel",
|
"diesel",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"env_logger 0.7.1",
|
"env_logger",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
"jirs-data",
|
"jirs-data",
|
||||||
"lettre",
|
"lettre",
|
||||||
"lettre_email",
|
"lettre_email",
|
||||||
"libc",
|
"libc",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding",
|
||||||
"pq-sys",
|
"pq-sys",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"quickcheck",
|
|
||||||
"r2d2",
|
"r2d2",
|
||||||
"rusoto_core",
|
"rusoto_core",
|
||||||
"rusoto_s3",
|
"rusoto_s3",
|
||||||
@ -1622,7 +1617,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"time 0.1.42",
|
"time 0.1.42",
|
||||||
"toml",
|
"toml",
|
||||||
"url 2.1.1",
|
"url",
|
||||||
"uuid 0.8.1",
|
"uuid 0.8.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1647,9 +1642,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.37"
|
version = "0.3.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a27d435371a2fa5b6d2b028a74bbdb1234f308da363226a2854ca3ff8ba7055"
|
checksum = "fa5a448de267e7358beaf4a5d849518fe9a0c13fce7afd44b06e68550e5562a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@ -1692,7 +1687,7 @@ dependencies = [
|
|||||||
"bufstream",
|
"bufstream",
|
||||||
"fast_chemail",
|
"fast_chemail",
|
||||||
"hostname 0.1.5",
|
"hostname 0.1.5",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"nom",
|
"nom",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1735,15 +1730,6 @@ dependencies = [
|
|||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "log"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
|
||||||
dependencies = [
|
|
||||||
"log 0.4.8",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.8"
|
version = "0.4.8"
|
||||||
@ -1792,15 +1778,6 @@ version = "0.7.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memchr"
|
|
||||||
version = "0.1.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.3.3"
|
version = "2.3.3"
|
||||||
@ -1844,7 +1821,7 @@ dependencies = [
|
|||||||
"iovec",
|
"iovec",
|
||||||
"kernel32-sys",
|
"kernel32-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"miow 0.2.1",
|
"miow 0.2.1",
|
||||||
"net2",
|
"net2",
|
||||||
"slab",
|
"slab",
|
||||||
@ -1858,7 +1835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
|
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazycell",
|
"lazycell",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"mio",
|
"mio",
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
@ -1869,7 +1846,7 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3"
|
checksum = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"mio",
|
"mio",
|
||||||
"miow 0.3.3",
|
"miow 0.3.3",
|
||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
@ -1916,7 +1893,7 @@ checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"openssl",
|
"openssl",
|
||||||
"openssl-probe",
|
"openssl-probe",
|
||||||
"openssl-sys",
|
"openssl-sys",
|
||||||
@ -1943,7 +1920,7 @@ version = "4.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr 2.3.3",
|
"memchr",
|
||||||
"version_check 0.1.5",
|
"version_check 0.1.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2068,12 +2045,6 @@ dependencies = [
|
|||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "percent-encoding"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@ -2182,8 +2153,8 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"env_logger 0.7.1",
|
"env_logger",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2209,13 +2180,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pulldown-cmark"
|
name = "pulldown-cmark"
|
||||||
version = "0.6.1"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c205cc82214f3594e2d50686730314f817c67ffa80fe800cf0db78c3c2b9d9e"
|
checksum = "3e142c3b8f49d2200605ee6ba0b1d757310e9e7a72afe78c36ee2ef67300ee00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"getopts",
|
"getopts",
|
||||||
"memchr 2.3.3",
|
"memchr",
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2225,17 +2196,6 @@ version = "1.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quickcheck"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "02c2411d418cea2364325b18a205664f9ef8252e06b2e911db97c0b0d98b1406"
|
|
||||||
dependencies = [
|
|
||||||
"env_logger 0.3.5",
|
|
||||||
"log 0.3.9",
|
|
||||||
"rand 0.3.23",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@ -2251,21 +2211,11 @@ version = "0.8.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1497e40855348e4a8a40767d8e55174bce1e445a3ac9254ad44ad468ee0485af"
|
checksum = "1497e40855348e4a8a40767d8e55174bce1e445a3ac9254ad44ad468ee0485af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"scheduled-thread-pool",
|
"scheduled-thread-pool",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.3.23"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand 0.4.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@ -2293,7 +2243,7 @@ dependencies = [
|
|||||||
"rand_isaac",
|
"rand_isaac",
|
||||||
"rand_jitter",
|
"rand_jitter",
|
||||||
"rand_os",
|
"rand_os",
|
||||||
"rand_pcg",
|
"rand_pcg 0.1.2",
|
||||||
"rand_xorshift",
|
"rand_xorshift",
|
||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
@ -2309,6 +2259,7 @@ dependencies = [
|
|||||||
"rand_chacha 0.2.2",
|
"rand_chacha 0.2.2",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
"rand_hc 0.2.0",
|
"rand_hc 0.2.0",
|
||||||
|
"rand_pcg 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2417,6 +2368,15 @@ dependencies = [
|
|||||||
"rand_core 0.4.2",
|
"rand_core 0.4.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_pcg"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.5.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_xorshift"
|
name = "rand_xorshift"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -2452,37 +2412,18 @@ dependencies = [
|
|||||||
"rust-argon2",
|
"rust-argon2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex"
|
|
||||||
version = "0.1.80"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
|
||||||
dependencies = [
|
|
||||||
"aho-corasick 0.5.3",
|
|
||||||
"memchr 0.1.11",
|
|
||||||
"regex-syntax 0.3.9",
|
|
||||||
"thread_local 0.2.7",
|
|
||||||
"utf8-ranges",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.3.6"
|
version = "1.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
|
checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.7.10",
|
"aho-corasick",
|
||||||
"memchr 2.3.3",
|
"memchr",
|
||||||
"regex-syntax 0.6.17",
|
"regex-syntax",
|
||||||
"thread_local 1.0.1",
|
"thread_local",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.3.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.17"
|
version = "0.6.17"
|
||||||
@ -2523,9 +2464,9 @@ dependencies = [
|
|||||||
"hyper",
|
"hyper",
|
||||||
"hyper-tls",
|
"hyper-tls",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"md5",
|
"md5",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"rusoto_credential",
|
"rusoto_credential",
|
||||||
"rusoto_signature",
|
"rusoto_signature",
|
||||||
@ -2549,7 +2490,7 @@ dependencies = [
|
|||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"hyper",
|
"hyper",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"regex 1.3.6",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shlex",
|
"shlex",
|
||||||
@ -2583,9 +2524,9 @@ dependencies = [
|
|||||||
"hmac",
|
"hmac",
|
||||||
"http",
|
"http",
|
||||||
"hyper",
|
"hyper",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"md5",
|
"md5",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"rusoto_credential",
|
"rusoto_credential",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
@ -2699,21 +2640,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "seed"
|
name = "seed"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd5d8fd7f12f565f639caf4b6d74a3853d5d7234d0543ec3beae81311492623e"
|
checksum = "882f4569a394bbb2f15f2fc410e0fbcef178fe24fc2d91599607a598443c6df8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"cookie",
|
"cookie",
|
||||||
"dbg",
|
"dbg",
|
||||||
"enclose",
|
"enclose",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
|
"gloo-file",
|
||||||
"gloo-timers",
|
"gloo-timers",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"pulldown-cmark",
|
"pulldown-cmark",
|
||||||
|
"rand 0.7.3",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"uuid 0.8.1",
|
||||||
"version_check 0.9.1",
|
"version_check 0.9.1",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
@ -2737,18 +2681,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.105"
|
version = "1.0.110"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff"
|
checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.105"
|
version = "1.0.110"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8"
|
checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -2757,9 +2701,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.48"
|
version = "1.0.53"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
|
checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@ -2775,7 +2719,7 @@ dependencies = [
|
|||||||
"dtoa",
|
"dtoa",
|
||||||
"itoa",
|
"itoa",
|
||||||
"serde",
|
"serde",
|
||||||
"url 2.1.1",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2970,25 +2914,6 @@ dependencies = [
|
|||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread-id"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
|
||||||
dependencies = [
|
|
||||||
"kernel32-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "thread_local"
|
|
||||||
version = "0.2.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
|
||||||
dependencies = [
|
|
||||||
"thread-id",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -3068,7 +2993,7 @@ dependencies = [
|
|||||||
"iovec",
|
"iovec",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"memchr 2.3.3",
|
"memchr",
|
||||||
"mio",
|
"mio",
|
||||||
"mio-named-pipes",
|
"mio-named-pipes",
|
||||||
"mio-uds",
|
"mio-uds",
|
||||||
@ -3109,7 +3034,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
@ -3139,14 +3064,14 @@ dependencies = [
|
|||||||
"enum-as-inner",
|
"enum-as-inner",
|
||||||
"failure",
|
"failure",
|
||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"idna 0.2.0",
|
"idna",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
"url 2.1.1",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3160,7 +3085,7 @@ dependencies = [
|
|||||||
"futures 0.3.4",
|
"futures 0.3.4",
|
||||||
"ipconfig",
|
"ipconfig",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"lru-cache",
|
"lru-cache",
|
||||||
"resolv-conf",
|
"resolv-conf",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@ -3180,7 +3105,7 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc"
|
checksum = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr 2.3.3",
|
"memchr",
|
||||||
"unchecked-index",
|
"unchecked-index",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3259,34 +3184,17 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "url"
|
|
||||||
version = "1.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
|
||||||
dependencies = [
|
|
||||||
"idna 0.1.5",
|
|
||||||
"matches",
|
|
||||||
"percent-encoding 1.0.1",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
|
checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"idna 0.2.0",
|
"idna",
|
||||||
"matches",
|
"matches",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "utf8-ranges"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
@ -3388,7 +3296,7 @@ version = "0.3.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
|
checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"try-lock",
|
"try-lock",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3400,9 +3308,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.60"
|
version = "0.2.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2cc57ce05287f8376e998cbddfb4c8cb43b84a7ec55cf4551d7c00eef317a47f"
|
checksum = "e3c7d40d09cdbf0f4895ae58cf57d92e1e57a9dd8ed2e8390514b54a47cc5551"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"serde",
|
"serde",
|
||||||
@ -3412,13 +3320,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.60"
|
version = "0.2.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d967d37bf6c16cca2973ca3af071d0a2523392e4a594548155d89a678f4237cd"
|
checksum = "c3972e137ebf830900db522d6c8fd74d1900dcfc733462e9a12e942b00b4ac94"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.8",
|
"log",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
@ -3427,9 +3335,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.10"
|
version = "0.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7add542ea1ac7fdaa9dc25e031a6af33b7d63376292bd24140c637d00d1c312a"
|
checksum = "8a369c5e1dfb7569e14d62af4da642a3cbc2f9a3652fe586e26ac22222aa4b04"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@ -3439,9 +3347,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.60"
|
version = "0.2.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8bd151b63e1ea881bb742cd20e1d6127cef28399558f3b5d415289bc41eee3a4"
|
checksum = "2cd85aa2c579e8892442954685f0d801f9129de24fa2136b2c6a539c76b65776"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@ -3449,9 +3357,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.60"
|
version = "0.2.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d68a5b36eef1be7868f668632863292e37739656a80fc4b9acec7b0bd35a4931"
|
checksum = "8eb197bd3a47553334907ffd2f16507b4f4f01bbec3ac921a7719e0decdfe72a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -3462,9 +3370,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.60"
|
version = "0.2.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "daf76fe7d25ac79748a37538b7daeed1c7a6867c92d3245c12c6222e4a20d639"
|
checksum = "a91c2916119c17a8e316507afaaa2dd94b47646048014bbdf6bef098c1bb58ad"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-test"
|
name = "wasm-bindgen-test"
|
||||||
@ -3492,9 +3400,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.37"
|
version = "0.3.39"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb"
|
checksum = "8bc359e5dd3b46cb9687a051d50a2fdd228e4ba7cf6fcf861a5365c3d671a642"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
@ -19,7 +19,7 @@ opt-level = 's'
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jirs-data = { path = "../jirs-data" }
|
jirs-data = { path = "../jirs-data" }
|
||||||
seed = { version = "*" }
|
seed = { version = "0.7.0" }
|
||||||
serde = "*"
|
serde = "*"
|
||||||
serde_json = "*"
|
serde_json = "*"
|
||||||
bincode = "1.2.1"
|
bincode = "1.2.1"
|
||||||
|
21
jirs-client/jirs.nginx
Normal file
21
jirs-client/jirs.nginx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name jirs.lvh.me;
|
||||||
|
|
||||||
|
charset utf-8;
|
||||||
|
root /home/eraden/code/eraden/jirs/jirs-client/tmp;
|
||||||
|
|
||||||
|
location ~ .wasm {
|
||||||
|
default_type application/wasm;
|
||||||
|
}
|
||||||
|
|
||||||
|
location *.js {
|
||||||
|
default_type application/javascript;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
index index.html index.htm;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_page 404 =200 /index.html;
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
.styledInput {
|
.styledInput {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 32px;
|
min-height: 32px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.styledInput > .inputElement {
|
.styledInput > .inputElement {
|
||||||
|
min-height: 32px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0 7px;
|
padding: 0 7px;
|
||||||
|
@ -2,85 +2,10 @@ const getWsHostName = () => process.env.JIRS_SERVER_BIND === "0.0.0.0" ? 'localh
|
|||||||
const getProtocol = () => window.location.protocol.replace(/^http/, 'ws');
|
const getProtocol = () => window.location.protocol.replace(/^http/, 'ws');
|
||||||
const wsUrl = () => `${ getProtocol() }//${ getWsHostName() }:${ process.env.JIRS_SERVER_PORT }/ws/`;
|
const wsUrl = () => `${ getProtocol() }//${ getWsHostName() }:${ process.env.JIRS_SERVER_PORT }/ws/`;
|
||||||
|
|
||||||
import("../pkg/index.js").then(module => {
|
import("/jirs.js").then(async module => {
|
||||||
let queue = [];
|
window.module = module;
|
||||||
let ws;
|
console.log(module)
|
||||||
|
await module.default();
|
||||||
const buildWebSocket = () => {
|
|
||||||
ws = new WebSocket(wsUrl());
|
|
||||||
ws.binaryType = 'blob';
|
|
||||||
ws.onopen = event => {
|
|
||||||
console.log('open', event);
|
|
||||||
module.reconnected();
|
|
||||||
};
|
|
||||||
ws.onerror = event => {
|
|
||||||
console.error(event);
|
|
||||||
};
|
|
||||||
ws.onmessage = async event => {
|
|
||||||
const arrayBuffer = await event.data.arrayBuffer();
|
|
||||||
const array = new Uint8Array(arrayBuffer);
|
|
||||||
module.handle_ws_message(array);
|
|
||||||
};
|
|
||||||
ws.onclose = () => {
|
|
||||||
setTimeout(() => buildWebSocket(), 600);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
buildWebSocket();
|
|
||||||
|
|
||||||
window.send_bin_code = code => queue.push(code);
|
|
||||||
window.inspectQueue = () => queue;
|
|
||||||
|
|
||||||
let wsCheckDelay = 100;
|
|
||||||
const flush = () => {
|
|
||||||
if (queue.length >= 1000) {
|
|
||||||
ws.close();
|
|
||||||
throw new Error("Message queue overflow");
|
|
||||||
}
|
|
||||||
// if (queue.length && wsCheckDelay <= 0) console.log(ws.readyState, queue);
|
|
||||||
switch (ws.readyState) {
|
|
||||||
case 1: {
|
|
||||||
const [ code, ...rest ] = queue;
|
|
||||||
queue = rest;
|
|
||||||
if (code) {
|
|
||||||
// console.log('open', code);
|
|
||||||
ws.send(Uint8Array.from(code).buffer);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
window.requestAnimationFrame(flush);
|
|
||||||
};
|
|
||||||
window.flush = flush;
|
|
||||||
|
|
||||||
const keepWsOpen = () => {
|
|
||||||
if (wsCheckDelay > 0) {
|
|
||||||
wsCheckDelay -= 1;
|
|
||||||
} else {
|
|
||||||
wsCheckDelay = 100;
|
|
||||||
switch (ws.readyState) {
|
|
||||||
case 1: {
|
|
||||||
// console.log('sending ping');
|
|
||||||
// ws.send(Uint8Array.from([ 0, 0, 0, 0 ]).buffer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0:
|
|
||||||
case 2:
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
throw new Error('web socket has been closed');
|
|
||||||
buildWebSocket();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.requestAnimationFrame(keepWsOpen);
|
|
||||||
};
|
|
||||||
|
|
||||||
keepWsOpen();
|
|
||||||
flush();
|
|
||||||
|
|
||||||
const host_url = `${ location.protocol }//${ process.env.JIRS_SERVER_BIND }:${ process.env.JIRS_SERVER_PORT }`;
|
const host_url = `${ location.protocol }//${ process.env.JIRS_SERVER_BIND }:${ process.env.JIRS_SERVER_PORT }`;
|
||||||
module.set_host_url(host_url);
|
module.render(host_url, wsUrl());
|
||||||
module.render();
|
|
||||||
});
|
});
|
||||||
|
15
jirs-client/js/template.html
Normal file
15
jirs-client/js/template.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="icon" href="/favicon.png">
|
||||||
|
<link rel="icon" href="/logo.svg">
|
||||||
|
<title>JIRS</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main id="app"></main>
|
||||||
|
<script type="module" src="/index.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
16
jirs-client/scripts/dev.sh
Executable file
16
jirs-client/scripts/dev.sh
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
. .env
|
||||||
|
|
||||||
|
rm -Rf tmp
|
||||||
|
mkdir tmp
|
||||||
|
|
||||||
|
wasm-pack build --mode normal --dev --out-name jirs --out-dir ./tmp --target web
|
||||||
|
../target/debug/jirs-css -i ./js/styles.css -O ./tmp/styles.css
|
||||||
|
|
||||||
|
cat ./js/index.js \
|
||||||
|
| sed -e "s/process.env.JIRS_SERVER_BIND/'$JIRS_SERVER_BIND'/g" \
|
||||||
|
| sed -e "s/process.env.JIRS_SERVER_PORT/'$JIRS_SERVER_PORT'/g" &> ./tmp/index.js
|
||||||
|
cp ./js/template.html ./tmp/index.html
|
||||||
|
|
||||||
|
cp -r ./dev/* ./tmp
|
@ -1,10 +0,0 @@
|
|||||||
use jirs_data::*;
|
|
||||||
|
|
||||||
pub fn send_ws_msg(msg: WsMsg) {
|
|
||||||
use crate::send_bin_code;
|
|
||||||
use wasm_bindgen::JsValue;
|
|
||||||
|
|
||||||
let binary = bincode::serialize(&msg).unwrap();
|
|
||||||
let data = JsValue::from_serde(&binary).unwrap();
|
|
||||||
send_bin_code(data);
|
|
||||||
}
|
|
67
jirs-client/src/changes.rs
Normal file
67
jirs-client/src/changes.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use crate::FieldId;
|
||||||
|
use jirs_data::{IssueId, IssueStatusId};
|
||||||
|
|
||||||
|
use crate::shared::styled_editor::Mode as TabMode;
|
||||||
|
use seed::prelude::WebSocketMessage;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum FieldChange {
|
||||||
|
LinkCopied(FieldId, bool),
|
||||||
|
TabChanged(FieldId, TabMode),
|
||||||
|
ToggleCommentForm(FieldId, bool),
|
||||||
|
EditComment(FieldId, i32),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum BoardPageChange {
|
||||||
|
// dragging
|
||||||
|
IssueDragStarted(IssueId),
|
||||||
|
IssueDragStopped(IssueId),
|
||||||
|
DragLeave(IssueId),
|
||||||
|
ExchangePosition(IssueId),
|
||||||
|
IssueDragOverStatus(IssueStatusId),
|
||||||
|
IssueDropZone(IssueStatusId),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum UsersPageChange {
|
||||||
|
ResetForm,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ProjectPageChange {
|
||||||
|
ResetForm,
|
||||||
|
SubmitForm,
|
||||||
|
// dragging
|
||||||
|
ColumnDragStarted(IssueStatusId),
|
||||||
|
ColumnDragStopped(IssueStatusId),
|
||||||
|
ColumnDragLeave(IssueStatusId),
|
||||||
|
ColumnExchangePosition(IssueStatusId),
|
||||||
|
ColumnDragOverStatus(IssueStatusId),
|
||||||
|
ColumnDropZone(IssueStatusId),
|
||||||
|
// edit issue status name
|
||||||
|
EditIssueStatusName(Option<IssueStatusId>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum ProfilePageChange {
|
||||||
|
SubmitForm,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum PageChanged {
|
||||||
|
Users(UsersPageChange),
|
||||||
|
ProjectSettings(ProjectPageChange),
|
||||||
|
Profile(ProfilePageChange),
|
||||||
|
Board(BoardPageChange),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum WebSocketChanged {
|
||||||
|
WsMsg(jirs_data::WsMsg),
|
||||||
|
WebSocketMessage(WebSocketMessage),
|
||||||
|
WebSocketMessageLoaded(Vec<u8>),
|
||||||
|
WebSocketOpened,
|
||||||
|
WebSocketClosed,
|
||||||
|
SendPing,
|
||||||
|
}
|
121
jirs-client/src/fields.rs
Normal file
121
jirs-client/src/fields.rs
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
use jirs_data::{
|
||||||
|
CommentFieldId, InviteFieldId, IssueFieldId, ProjectFieldId, SignInFieldId, SignUpFieldId,
|
||||||
|
UsersFieldId,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub type AvatarFilterActive = bool;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq, Hash)]
|
||||||
|
pub enum EditIssueModalSection {
|
||||||
|
Issue(IssueFieldId),
|
||||||
|
Comment(CommentFieldId),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq, Hash)]
|
||||||
|
pub enum FieldId {
|
||||||
|
SignIn(SignInFieldId),
|
||||||
|
SignUp(SignUpFieldId),
|
||||||
|
Invite(InviteFieldId),
|
||||||
|
Users(UsersFieldId),
|
||||||
|
Profile(UsersFieldId),
|
||||||
|
// issue
|
||||||
|
AddIssueModal(IssueFieldId),
|
||||||
|
EditIssueModal(EditIssueModalSection),
|
||||||
|
// project boards
|
||||||
|
TextFilterBoard,
|
||||||
|
CopyButtonLabel,
|
||||||
|
|
||||||
|
ProjectSettings(ProjectFieldId),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for FieldId {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
FieldId::EditIssueModal(sub) => match sub {
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::Type) => {
|
||||||
|
f.write_str("issueTypeEditModalTop")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::Title) => {
|
||||||
|
f.write_str("titleIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::Description) => {
|
||||||
|
f.write_str("descriptionIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::IssueStatusId) => {
|
||||||
|
f.write_str("statusIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::Assignees) => {
|
||||||
|
f.write_str("assigneesIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::Reporter) => {
|
||||||
|
f.write_str("reporterIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::Priority) => {
|
||||||
|
f.write_str("priorityIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::Estimate) => {
|
||||||
|
f.write_str("estimateIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::TimeSpent) => {
|
||||||
|
f.write_str("timeSpendIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::TimeRemaining) => {
|
||||||
|
f.write_str("timeRemainingIssueEditModal")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Comment(CommentFieldId::Body) => {
|
||||||
|
f.write_str("editIssue-commentBody")
|
||||||
|
}
|
||||||
|
EditIssueModalSection::Issue(IssueFieldId::ListPosition) => {
|
||||||
|
f.write_str("editIssue-listPosition")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FieldId::AddIssueModal(sub) => match sub {
|
||||||
|
IssueFieldId::Type => f.write_str("issueTypeAddIssueModal"),
|
||||||
|
IssueFieldId::Title => f.write_str("summaryAddIssueModal"),
|
||||||
|
IssueFieldId::Description => f.write_str("descriptionAddIssueModal"),
|
||||||
|
IssueFieldId::Reporter => f.write_str("reporterAddIssueModal"),
|
||||||
|
IssueFieldId::Assignees => f.write_str("assigneesAddIssueModal"),
|
||||||
|
IssueFieldId::Priority => f.write_str("issuePriorityAddIssueModal"),
|
||||||
|
IssueFieldId::IssueStatusId => f.write_str("addIssueModal-status"),
|
||||||
|
IssueFieldId::Estimate => f.write_str("addIssueModal-estimate"),
|
||||||
|
IssueFieldId::TimeSpent => f.write_str("addIssueModal-timeSpend"),
|
||||||
|
IssueFieldId::TimeRemaining => f.write_str("addIssueModal-timeRemaining"),
|
||||||
|
IssueFieldId::ListPosition => f.write_str("addIssueModal-listPosition"),
|
||||||
|
},
|
||||||
|
FieldId::TextFilterBoard => f.write_str("textFilterBoard"),
|
||||||
|
FieldId::CopyButtonLabel => f.write_str("copyButtonLabel"),
|
||||||
|
FieldId::ProjectSettings(sub) => match sub {
|
||||||
|
ProjectFieldId::Name => f.write_str("projectSettings-name"),
|
||||||
|
ProjectFieldId::Url => f.write_str("projectSettings-url"),
|
||||||
|
ProjectFieldId::Description => f.write_str("projectSettings-description"),
|
||||||
|
ProjectFieldId::Category => f.write_str("projectSettings-category"),
|
||||||
|
ProjectFieldId::TimeTracking => f.write_str("projectSettings-timeTracking"),
|
||||||
|
ProjectFieldId::IssueStatusName => f.write_str("projectSettings-issueStatusName"),
|
||||||
|
},
|
||||||
|
FieldId::SignIn(sub) => match sub {
|
||||||
|
SignInFieldId::Email => f.write_str("login-email"),
|
||||||
|
SignInFieldId::Username => f.write_str("login-username"),
|
||||||
|
SignInFieldId::Token => f.write_str("login-token"),
|
||||||
|
},
|
||||||
|
FieldId::SignUp(sub) => match sub {
|
||||||
|
SignUpFieldId::Username => f.write_str("signUp-email"),
|
||||||
|
SignUpFieldId::Email => f.write_str("signUp-username"),
|
||||||
|
},
|
||||||
|
FieldId::Invite(sub) => match sub {
|
||||||
|
InviteFieldId::Token => f.write_str("invite-token"),
|
||||||
|
},
|
||||||
|
FieldId::Users(sub) => match sub {
|
||||||
|
UsersFieldId::Username => f.write_str("users-username"),
|
||||||
|
UsersFieldId::Email => f.write_str("users-email"),
|
||||||
|
UsersFieldId::UserRole => f.write_str("users-userRole"),
|
||||||
|
UsersFieldId::Avatar => f.write_str("users-avatar"),
|
||||||
|
},
|
||||||
|
FieldId::Profile(sub) => match sub {
|
||||||
|
UsersFieldId::Username => f.write_str("profile-username"),
|
||||||
|
UsersFieldId::Email => f.write_str("profile-email"),
|
||||||
|
UsersFieldId::UserRole => f.write_str("profile-userRole"),
|
||||||
|
UsersFieldId::Avatar => f.write_str("profile-avatar"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,15 @@
|
|||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
use seed::{prelude::*, *};
|
use seed::{prelude::*, *};
|
||||||
use web_sys::File;
|
use web_sys::File;
|
||||||
|
|
||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{ModalType, Model, Page};
|
use crate::model::{ModalType, Model, Page};
|
||||||
use crate::shared::styled_editor::Mode as TabMode;
|
|
||||||
use crate::shared::styled_select::StyledSelectChange;
|
use crate::shared::styled_select::StyledSelectChange;
|
||||||
|
use crate::shared::{go_to_board, go_to_login};
|
||||||
|
use crate::ws::{open_socket, read_incoming, send_ws_msg};
|
||||||
|
|
||||||
mod api;
|
mod changes;
|
||||||
|
mod fields;
|
||||||
mod invite;
|
mod invite;
|
||||||
mod modal;
|
mod modal;
|
||||||
mod model;
|
mod model;
|
||||||
@ -24,179 +23,13 @@ mod users;
|
|||||||
pub mod validations;
|
pub mod validations;
|
||||||
mod ws;
|
mod ws;
|
||||||
|
|
||||||
pub type AvatarFilterActive = bool;
|
pub use changes::*;
|
||||||
|
pub use fields::*;
|
||||||
|
|
||||||
pub type AppType = App<Msg, Model, Node<Msg>>;
|
pub type AppType = App<Msg, Model, Node<Msg>>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialOrd, PartialEq, Hash)]
|
#[derive(Debug)]
|
||||||
pub enum EditIssueModalSection {
|
|
||||||
Issue(IssueFieldId),
|
|
||||||
Comment(CommentFieldId),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialOrd, PartialEq, Hash)]
|
|
||||||
pub enum FieldId {
|
|
||||||
SignIn(SignInFieldId),
|
|
||||||
SignUp(SignUpFieldId),
|
|
||||||
Invite(InviteFieldId),
|
|
||||||
Users(UsersFieldId),
|
|
||||||
Profile(UsersFieldId),
|
|
||||||
// issue
|
|
||||||
AddIssueModal(IssueFieldId),
|
|
||||||
EditIssueModal(EditIssueModalSection),
|
|
||||||
// project boards
|
|
||||||
TextFilterBoard,
|
|
||||||
CopyButtonLabel,
|
|
||||||
|
|
||||||
ProjectSettings(ProjectFieldId),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for FieldId {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
FieldId::EditIssueModal(sub) => match sub {
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::Type) => {
|
|
||||||
f.write_str("issueTypeEditModalTop")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::Title) => {
|
|
||||||
f.write_str("titleIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::Description) => {
|
|
||||||
f.write_str("descriptionIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::IssueStatusId) => {
|
|
||||||
f.write_str("statusIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::Assignees) => {
|
|
||||||
f.write_str("assigneesIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::Reporter) => {
|
|
||||||
f.write_str("reporterIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::Priority) => {
|
|
||||||
f.write_str("priorityIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::Estimate) => {
|
|
||||||
f.write_str("estimateIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::TimeSpent) => {
|
|
||||||
f.write_str("timeSpendIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::TimeRemaining) => {
|
|
||||||
f.write_str("timeRemainingIssueEditModal")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Comment(CommentFieldId::Body) => {
|
|
||||||
f.write_str("editIssue-commentBody")
|
|
||||||
}
|
|
||||||
EditIssueModalSection::Issue(IssueFieldId::ListPosition) => {
|
|
||||||
f.write_str("editIssue-listPosition")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
FieldId::AddIssueModal(sub) => match sub {
|
|
||||||
IssueFieldId::Type => f.write_str("issueTypeAddIssueModal"),
|
|
||||||
IssueFieldId::Title => f.write_str("summaryAddIssueModal"),
|
|
||||||
IssueFieldId::Description => f.write_str("descriptionAddIssueModal"),
|
|
||||||
IssueFieldId::Reporter => f.write_str("reporterAddIssueModal"),
|
|
||||||
IssueFieldId::Assignees => f.write_str("assigneesAddIssueModal"),
|
|
||||||
IssueFieldId::Priority => f.write_str("issuePriorityAddIssueModal"),
|
|
||||||
IssueFieldId::IssueStatusId => f.write_str("addIssueModal-status"),
|
|
||||||
IssueFieldId::Estimate => f.write_str("addIssueModal-estimate"),
|
|
||||||
IssueFieldId::TimeSpent => f.write_str("addIssueModal-timeSpend"),
|
|
||||||
IssueFieldId::TimeRemaining => f.write_str("addIssueModal-timeRemaining"),
|
|
||||||
IssueFieldId::ListPosition => f.write_str("addIssueModal-listPosition"),
|
|
||||||
},
|
|
||||||
FieldId::TextFilterBoard => f.write_str("textFilterBoard"),
|
|
||||||
FieldId::CopyButtonLabel => f.write_str("copyButtonLabel"),
|
|
||||||
FieldId::ProjectSettings(sub) => match sub {
|
|
||||||
ProjectFieldId::Name => f.write_str("projectSettings-name"),
|
|
||||||
ProjectFieldId::Url => f.write_str("projectSettings-url"),
|
|
||||||
ProjectFieldId::Description => f.write_str("projectSettings-description"),
|
|
||||||
ProjectFieldId::Category => f.write_str("projectSettings-category"),
|
|
||||||
ProjectFieldId::TimeTracking => f.write_str("projectSettings-timeTracking"),
|
|
||||||
ProjectFieldId::IssueStatusName => f.write_str("projectSettings-issueStatusName"),
|
|
||||||
},
|
|
||||||
FieldId::SignIn(sub) => match sub {
|
|
||||||
SignInFieldId::Email => f.write_str("login-email"),
|
|
||||||
SignInFieldId::Username => f.write_str("login-username"),
|
|
||||||
SignInFieldId::Token => f.write_str("login-token"),
|
|
||||||
},
|
|
||||||
FieldId::SignUp(sub) => match sub {
|
|
||||||
SignUpFieldId::Username => f.write_str("signUp-email"),
|
|
||||||
SignUpFieldId::Email => f.write_str("signUp-username"),
|
|
||||||
},
|
|
||||||
FieldId::Invite(sub) => match sub {
|
|
||||||
InviteFieldId::Token => f.write_str("invite-token"),
|
|
||||||
},
|
|
||||||
FieldId::Users(sub) => match sub {
|
|
||||||
UsersFieldId::Username => f.write_str("users-username"),
|
|
||||||
UsersFieldId::Email => f.write_str("users-email"),
|
|
||||||
UsersFieldId::UserRole => f.write_str("users-userRole"),
|
|
||||||
UsersFieldId::Avatar => f.write_str("users-avatar"),
|
|
||||||
},
|
|
||||||
FieldId::Profile(sub) => match sub {
|
|
||||||
UsersFieldId::Username => f.write_str("profile-username"),
|
|
||||||
UsersFieldId::Email => f.write_str("profile-email"),
|
|
||||||
UsersFieldId::UserRole => f.write_str("profile-userRole"),
|
|
||||||
UsersFieldId::Avatar => f.write_str("profile-avatar"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum FieldChange {
|
|
||||||
LinkCopied(FieldId, bool),
|
|
||||||
TabChanged(FieldId, TabMode),
|
|
||||||
ToggleCommentForm(FieldId, bool),
|
|
||||||
EditComment(FieldId, i32),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum BoardPageChange {
|
|
||||||
// dragging
|
|
||||||
IssueDragStarted(IssueId),
|
|
||||||
IssueDragStopped(IssueId),
|
|
||||||
DragLeave(IssueId),
|
|
||||||
ExchangePosition(IssueId),
|
|
||||||
IssueDragOverStatus(IssueStatusId),
|
|
||||||
IssueDropZone(IssueStatusId),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum UsersPageChange {
|
|
||||||
ResetForm,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum ProjectPageChange {
|
|
||||||
ResetForm,
|
|
||||||
SubmitForm,
|
|
||||||
// dragging
|
|
||||||
ColumnDragStarted(IssueStatusId),
|
|
||||||
ColumnDragStopped(IssueStatusId),
|
|
||||||
ColumnDragLeave(IssueStatusId),
|
|
||||||
ColumnExchangePosition(IssueStatusId),
|
|
||||||
ColumnDragOverStatus(IssueStatusId),
|
|
||||||
ColumnDropZone(IssueStatusId),
|
|
||||||
// edit issue status name
|
|
||||||
EditIssueStatusName(Option<IssueStatusId>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum ProfilePageChange {
|
|
||||||
SubmitForm,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum PageChanged {
|
|
||||||
Users(UsersPageChange),
|
|
||||||
ProjectSettings(ProjectPageChange),
|
|
||||||
Profile(ProfilePageChange),
|
|
||||||
Board(BoardPageChange),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
NoOp,
|
|
||||||
GlobalKeyDown {
|
GlobalKeyDown {
|
||||||
key: String,
|
key: String,
|
||||||
shift: bool,
|
shift: bool,
|
||||||
@ -248,35 +81,82 @@ pub enum Msg {
|
|||||||
DeleteComment(CommentId),
|
DeleteComment(CommentId),
|
||||||
|
|
||||||
// profile
|
// profile
|
||||||
AvatarUpdateFetched(seed::fetch::FetchObject<String>),
|
AvatarUpdateFetched(String),
|
||||||
|
|
||||||
// modals
|
// modals
|
||||||
ModalOpened(Box<ModalType>),
|
ModalOpened(Box<ModalType>),
|
||||||
ModalDropped,
|
ModalDropped,
|
||||||
ModalChanged(FieldChange),
|
ModalChanged(FieldChange),
|
||||||
|
|
||||||
WsMsg(jirs_data::WsMsg),
|
// WebSocket
|
||||||
|
WebSocketChange(WebSocketChanged),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
match msg {
|
if model.ws.is_none() {
|
||||||
Msg::NoOp => return,
|
open_socket(model, orders);
|
||||||
_ => (),
|
}
|
||||||
|
|
||||||
|
let msg = match msg {
|
||||||
|
Msg::WebSocketChange(change) => {
|
||||||
|
match change {
|
||||||
|
WebSocketChanged::WebSocketOpened => {
|
||||||
|
authorize_or_redirect(model);
|
||||||
|
send_ws_msg(WsMsg::Ping, model.ws.as_ref());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WebSocketChanged::SendPing => {
|
||||||
|
send_ws_msg(WsMsg::Ping, model.ws.as_ref());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WebSocketMessage(incoming) => {
|
||||||
|
orders.perform_cmd(read_incoming(incoming));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(ref ws_msg) => {
|
||||||
|
ws::update(ws_msg, model, orders);
|
||||||
|
}
|
||||||
|
WebSocketChanged::WebSocketMessageLoaded(v) => {
|
||||||
|
if let Ok(m) = bincode::deserialize(v.clone().as_slice()) {
|
||||||
|
match m {
|
||||||
|
WsMsg::Ping | WsMsg::Pong => {
|
||||||
|
orders.perform_cmd(cmds::timeout(1000, || {
|
||||||
|
Msg::WebSocketChange(WebSocketChanged::SendPing)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
orders
|
||||||
|
.skip()
|
||||||
|
.send_msg(Msg::WebSocketChange(WebSocketChanged::WsMsg(m)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WebSocketClosed => {
|
||||||
|
open_socket(model, orders);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Msg::WebSocketChange(change)
|
||||||
|
}
|
||||||
|
_ => msg,
|
||||||
};
|
};
|
||||||
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
log!(msg);
|
log!(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
match &msg {
|
match &msg {
|
||||||
Msg::AuthTokenStored => {
|
Msg::AuthTokenStored => {
|
||||||
seed::push_route(vec!["dashboard"]);
|
go_to_board();
|
||||||
orders.skip().send_msg(Msg::ChangePage(Page::Project));
|
orders.skip().send_msg(Msg::ChangePage(Page::Project));
|
||||||
authorize_or_redirect();
|
authorize_or_redirect(model);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Msg::AuthTokenErased => {
|
Msg::AuthTokenErased => {
|
||||||
seed::push_route(vec!["login"]);
|
go_to_login();
|
||||||
orders.skip().send_msg(Msg::ChangePage(Page::SignIn));
|
orders.skip().send_msg(Msg::ChangePage(Page::SignIn));
|
||||||
authorize_or_redirect();
|
authorize_or_redirect(model);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Msg::ChangePage(page) => {
|
Msg::ChangePage(page) => {
|
||||||
@ -287,7 +167,6 @@ fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
|||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
crate::ws::update(&msg, model, orders);
|
|
||||||
crate::modal::update(&msg, model, orders);
|
crate::modal::update(&msg, model, orders);
|
||||||
match model.page {
|
match model.page {
|
||||||
Page::Project | Page::AddIssue | Page::EditIssue(..) => project::update(msg, model, orders),
|
Page::Project | Page::AddIssue | Page::EditIssue(..) => project::update(msg, model, orders),
|
||||||
@ -317,116 +196,98 @@ fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn routes(url: Url) -> Option<Msg> {
|
fn routes(url: Url) -> Option<Msg> {
|
||||||
if url.path.is_empty() {
|
match resolve_page(url) {
|
||||||
return Some(Msg::ChangePage(model::Page::Project));
|
Some(page) => Some(Msg::ChangePage(page)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_page(url: Url) -> Option<Page> {
|
||||||
|
if url.path().is_empty() {
|
||||||
|
return Some(Page::Project);
|
||||||
}
|
}
|
||||||
|
|
||||||
match url.path[0].as_ref() {
|
let page = match url.path()[0].as_ref() {
|
||||||
"board" => Some(Msg::ChangePage(model::Page::Project)),
|
"board" => Page::Project,
|
||||||
"issues" => match url.path.get(1).as_ref().map(|s| s.parse::<i32>()) {
|
"issues" => match url.path().get(1).as_ref().map(|s| s.parse::<i32>()) {
|
||||||
Some(Ok(id)) => Some(Msg::ChangePage(model::Page::EditIssue(id))),
|
Some(Ok(id)) => Page::EditIssue(id),
|
||||||
_ => None,
|
_ => return None,
|
||||||
},
|
},
|
||||||
"profile" => Some(Msg::ChangePage(Page::Profile)),
|
"profile" => Page::Profile,
|
||||||
"add-issue" => Some(Msg::ChangePage(Page::AddIssue)),
|
"add-issue" => Page::AddIssue,
|
||||||
"project-settings" => Some(Msg::ChangePage(model::Page::ProjectSettings)),
|
"project-settings" => Page::ProjectSettings,
|
||||||
"login" => Some(Msg::ChangePage(model::Page::SignIn)),
|
"login" => Page::SignIn,
|
||||||
"register" => Some(Msg::ChangePage(model::Page::SignUp)),
|
"register" => Page::SignUp,
|
||||||
"invite" => Some(Msg::ChangePage(model::Page::Invite)),
|
"invite" => Page::Invite,
|
||||||
"users" => Some(Msg::ChangePage(model::Page::Users)),
|
"users" => Page::Users,
|
||||||
_ => Some(Msg::ChangePage(model::Page::Project)),
|
_ => Page::Project,
|
||||||
}
|
};
|
||||||
|
Some(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static mut HOST_URL: String = String::new();
|
pub static mut HOST_URL: String = String::new();
|
||||||
pub static mut APP: Option<RwLock<App<Msg, Model, Node<Msg>>>> = None;
|
pub static mut WS_URL: String = String::new();
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn set_host_url(url: String) {
|
pub fn render(host_url: String, ws_url: String) {
|
||||||
unsafe {
|
unsafe {
|
||||||
HOST_URL = url;
|
HOST_URL = host_url;
|
||||||
}
|
WS_URL = ws_url;
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn handle_ws_message(value: &wasm_bindgen::JsValue) {
|
|
||||||
let a = js_sys::Uint8Array::new(value);
|
|
||||||
let mut v = Vec::new();
|
|
||||||
for idx in 0..a.length() {
|
|
||||||
v.push(a.get_index(idx));
|
|
||||||
}
|
|
||||||
if let Ok(msg) = bincode::deserialize(v.as_slice()) {
|
|
||||||
ws::handle(msg);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn reconnected() {
|
|
||||||
authorize_or_redirect();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
extern "C" {
|
|
||||||
pub fn send_bin_code(data: wasm_bindgen::JsValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn render() {
|
|
||||||
seed::set_interval(
|
|
||||||
Box::new(|| {
|
|
||||||
let binary = bincode::serialize(&jirs_data::WsMsg::Ping).unwrap();
|
|
||||||
let data = JsValue::from_serde(&binary).unwrap();
|
|
||||||
send_bin_code(data);
|
|
||||||
}) as Box<dyn Fn()>,
|
|
||||||
5000,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(body) = seed::html_document().body() {
|
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
|
|
||||||
let body = body.dyn_ref::<web_sys::HtmlBodyElement>().unwrap().clone();
|
|
||||||
let key_up_closure =
|
|
||||||
wasm_bindgen::closure::Closure::wrap(Box::new(|event: web_sys::KeyboardEvent| {
|
|
||||||
if let Some(Ok(app)) = unsafe { APP.as_mut().map(|app| app.write()) } {
|
|
||||||
let msg = Msg::GlobalKeyDown {
|
|
||||||
key: event.key(),
|
|
||||||
shift: event.shift_key(),
|
|
||||||
ctrl: event.ctrl_key(),
|
|
||||||
alt: event.alt_key(),
|
|
||||||
};
|
|
||||||
app.update(msg);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
as Box<dyn Fn(web_sys::KeyboardEvent)>);
|
|
||||||
body.add_event_listener_with_callback("keyup", key_up_closure.as_ref().unchecked_ref())
|
|
||||||
.unwrap();
|
|
||||||
key_up_closure.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let app = seed::App::builder(update, view)
|
// if let Some(body) = seed::html_document().body() {
|
||||||
|
// use wasm_bindgen::JsCast;
|
||||||
|
// let body = body.dyn_ref::<web_sys::HtmlBodyElement>().unwrap().clone();
|
||||||
|
// let key_up_closure =
|
||||||
|
// wasm_bindgen::closure::Closure::wrap(Box::new(|event: web_sys::KeyboardEvent| {
|
||||||
|
// if let Some(Ok(app)) = unsafe { APP.as_mut().map(|app| app.write()) } {
|
||||||
|
// let msg = Msg::GlobalKeyDown {
|
||||||
|
// key: event.key(),
|
||||||
|
// shift: event.shift_key(),
|
||||||
|
// ctrl: event.ctrl_key(),
|
||||||
|
// alt: event.alt_key(),
|
||||||
|
// };
|
||||||
|
// app.update(msg);
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// as Box<dyn Fn(web_sys::KeyboardEvent)>);
|
||||||
|
// body.add_event_listener_with_callback("keyup", key_up_closure.as_ref().unchecked_ref())
|
||||||
|
// .unwrap();
|
||||||
|
// key_up_closure.forget();
|
||||||
|
// }
|
||||||
|
|
||||||
|
let _app = seed::App::builder(update, view)
|
||||||
.routes(routes)
|
.routes(routes)
|
||||||
|
.after_mount(after_mount)
|
||||||
.build_and_start();
|
.build_and_start();
|
||||||
|
}
|
||||||
|
|
||||||
authorize_or_redirect();
|
fn after_mount(url: Url, orders: &mut impl Orders<Msg>) -> AfterMount<Model> {
|
||||||
|
let host_url = unsafe { HOST_URL.clone() };
|
||||||
let cell_app = std::sync::RwLock::new(app);
|
let ws_url = unsafe { WS_URL.clone() };
|
||||||
|
let mut model = Model::new(host_url, ws_url);
|
||||||
unsafe {
|
unsafe {
|
||||||
APP = Some(cell_app);
|
HOST_URL = "".to_string();
|
||||||
};
|
WS_URL = "".to_string();
|
||||||
|
}
|
||||||
|
model.page = resolve_page(url).unwrap_or_else(|| Page::Project);
|
||||||
|
log!(model);
|
||||||
|
open_socket(&mut model, orders);
|
||||||
|
AfterMount::new(model).url_handling(UrlHandling::PassToRoutes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn authorize_or_redirect() {
|
fn authorize_or_redirect(model: &Model) {
|
||||||
match crate::shared::read_auth_token() {
|
match crate::shared::read_auth_token() {
|
||||||
Ok(token) => {
|
Ok(token) => {
|
||||||
send_ws_msg(WsMsg::AuthorizeRequest(token));
|
send_ws_msg(WsMsg::AuthorizeRequest(token), model.ws.as_ref());
|
||||||
}
|
}
|
||||||
Err(..) => {
|
Err(..) => {
|
||||||
let pathname = seed::document().location().unwrap().pathname().unwrap();
|
let pathname = seed::document().location().unwrap().pathname().unwrap();
|
||||||
match pathname.as_str() {
|
match pathname.as_str() {
|
||||||
"/login" | "/register" | "/invite" => {}
|
"/login" | "/register" | "/invite" => {}
|
||||||
_ => {
|
_ => {
|
||||||
seed::push_route(vec!["login"]);
|
go_to_login();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use seed::{prelude::*, *};
|
use seed::{prelude::*, *};
|
||||||
|
|
||||||
use jirs_data::IssueFieldId;
|
use jirs_data::{IssueFieldId, WsMsg};
|
||||||
use jirs_data::{IssuePriority, IssueType, ToVec};
|
use jirs_data::{IssuePriority, IssueType, ToVec};
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{AddIssueModal, ModalType, Model};
|
use crate::model::{AddIssueModal, ModalType, Model};
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_field::StyledField;
|
use crate::shared::styled_field::StyledField;
|
||||||
@ -14,7 +13,8 @@ use crate::shared::styled_select::StyledSelect;
|
|||||||
use crate::shared::styled_select::StyledSelectChange;
|
use crate::shared::styled_select::StyledSelectChange;
|
||||||
use crate::shared::styled_textarea::StyledTextarea;
|
use crate::shared::styled_textarea::StyledTextarea;
|
||||||
use crate::shared::{ToChild, ToNode};
|
use crate::shared::{ToChild, ToNode};
|
||||||
use crate::{FieldId, Msg};
|
use crate::ws::send_ws_msg;
|
||||||
|
use crate::{FieldId, Msg, WebSocketChanged};
|
||||||
|
|
||||||
pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
let modal = model.modals.iter_mut().find(|modal| match modal {
|
let modal = model.modals.iter_mut().find(|modal| match modal {
|
||||||
@ -50,9 +50,12 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
|
|||||||
user_ids: modal.user_ids.clone(),
|
user_ids: modal.user_ids.clone(),
|
||||||
reporter_id: modal.reporter_id.unwrap_or_else(|| user_id),
|
reporter_id: modal.reporter_id.unwrap_or_else(|| user_id),
|
||||||
};
|
};
|
||||||
send_ws_msg(jirs_data::WsMsg::IssueCreateRequest(payload));
|
send_ws_msg(
|
||||||
|
jirs_data::WsMsg::IssueCreateRequest(payload),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::WsMsg(jirs_data::WsMsg::IssueCreated(issue)) => {
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::IssueCreated(issue))) => {
|
||||||
model.issues.push(issue.clone());
|
model.issues.push(issue.clone());
|
||||||
orders.skip().send_msg(Msg::ModalDropped);
|
orders.skip().send_msg(Msg::ModalDropped);
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,10 @@ use seed::prelude::*;
|
|||||||
|
|
||||||
use jirs_data::{IssueStatusId, WsMsg};
|
use jirs_data::{IssueStatusId, WsMsg};
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{DeleteIssueStatusModal, ModalType, Model};
|
use crate::model::{DeleteIssueStatusModal, ModalType, Model};
|
||||||
use crate::shared::styled_confirm_modal::StyledConfirmModal;
|
use crate::shared::styled_confirm_modal::StyledConfirmModal;
|
||||||
use crate::shared::ToNode;
|
use crate::shared::ToNode;
|
||||||
use crate::{model, Msg};
|
use crate::{model, Msg, WebSocketChanged};
|
||||||
|
|
||||||
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
let _modal: &mut Box<DeleteIssueStatusModal> =
|
let _modal: &mut Box<DeleteIssueStatusModal> =
|
||||||
@ -20,9 +19,12 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Msg::DeleteIssueStatus(issue_status_id) => {
|
Msg::DeleteIssueStatus(issue_status_id) => {
|
||||||
send_ws_msg(WsMsg::IssueStatusDelete(*issue_status_id));
|
crate::ws::send_ws_msg(
|
||||||
|
WsMsg::IssueStatusDelete(*issue_status_id),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::IssueStatusDelete(_)) => {
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::IssueStatusDelete(_))) => {
|
||||||
orders.skip().send_msg(Msg::ModalDropped);
|
orders.skip().send_msg(Msg::ModalDropped);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -2,7 +2,6 @@ use seed::{prelude::*, *};
|
|||||||
|
|
||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::modal::time_tracking::time_tracking_field;
|
use crate::modal::time_tracking::time_tracking_field;
|
||||||
use crate::model::{CommentForm, EditIssueModal, ModalType, Model};
|
use crate::model::{CommentForm, EditIssueModal, ModalType, Model};
|
||||||
use crate::shared::styled_avatar::StyledAvatar;
|
use crate::shared::styled_avatar::StyledAvatar;
|
||||||
@ -15,7 +14,8 @@ use crate::shared::styled_select::{StyledSelect, StyledSelectChange};
|
|||||||
use crate::shared::styled_textarea::StyledTextarea;
|
use crate::shared::styled_textarea::StyledTextarea;
|
||||||
use crate::shared::tracking_widget::tracking_link;
|
use crate::shared::tracking_widget::tracking_link;
|
||||||
use crate::shared::{ToChild, ToNode};
|
use crate::shared::{ToChild, ToNode};
|
||||||
use crate::{EditIssueModalSection, FieldChange, FieldId, Msg};
|
use crate::ws::send_ws_msg;
|
||||||
|
use crate::{EditIssueModalSection, FieldChange, FieldId, Msg, WebSocketChanged};
|
||||||
|
|
||||||
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
let modal: &mut EditIssueModal = match model.modals.get_mut(0) {
|
let modal: &mut EditIssueModal = match model.modals.get_mut(0) {
|
||||||
@ -35,7 +35,7 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
modal.time_remaining_select.update(msg, orders);
|
modal.time_remaining_select.update(msg, orders);
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Msg::WsMsg(WsMsg::IssueUpdated(issue)) => {
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::IssueUpdated(issue))) => {
|
||||||
modal.payload = issue.clone().into();
|
modal.payload = issue.clone().into();
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
@ -43,44 +43,56 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
StyledSelectChange::Changed(value),
|
StyledSelectChange::Changed(value),
|
||||||
) => {
|
) => {
|
||||||
modal.payload.issue_type = (*value).into();
|
modal.payload.issue_type = (*value).into();
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Type,
|
modal.id,
|
||||||
PayloadVariant::IssueType(modal.payload.issue_type),
|
IssueFieldId::Type,
|
||||||
));
|
PayloadVariant::IssueType(modal.payload.issue_type),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::IssueStatusId)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::IssueStatusId)),
|
||||||
StyledSelectChange::Changed(value),
|
StyledSelectChange::Changed(value),
|
||||||
) => {
|
) => {
|
||||||
modal.payload.issue_status_id = *value as IssueStatusId;
|
modal.payload.issue_status_id = *value as IssueStatusId;
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::IssueStatusId,
|
modal.id,
|
||||||
PayloadVariant::I32(modal.payload.issue_status_id),
|
IssueFieldId::IssueStatusId,
|
||||||
));
|
PayloadVariant::I32(modal.payload.issue_status_id),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Reporter)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Reporter)),
|
||||||
StyledSelectChange::Changed(value),
|
StyledSelectChange::Changed(value),
|
||||||
) => {
|
) => {
|
||||||
modal.payload.reporter_id = *value as i32;
|
modal.payload.reporter_id = *value as i32;
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Reporter,
|
modal.id,
|
||||||
PayloadVariant::I32(modal.payload.reporter_id),
|
IssueFieldId::Reporter,
|
||||||
));
|
PayloadVariant::I32(modal.payload.reporter_id),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Assignees)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Assignees)),
|
||||||
StyledSelectChange::Changed(value),
|
StyledSelectChange::Changed(value),
|
||||||
) => {
|
) => {
|
||||||
modal.payload.user_ids.push(*value as i32);
|
modal.payload.user_ids.push(*value as i32);
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Assignees,
|
modal.id,
|
||||||
PayloadVariant::VecI32(modal.payload.user_ids.clone()),
|
IssueFieldId::Assignees,
|
||||||
));
|
PayloadVariant::VecI32(modal.payload.user_ids.clone()),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Assignees)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Assignees)),
|
||||||
@ -94,33 +106,42 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
modal.payload.user_ids.push(id);
|
modal.payload.user_ids.push(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Assignees,
|
modal.id,
|
||||||
PayloadVariant::VecI32(modal.payload.user_ids.clone()),
|
IssueFieldId::Assignees,
|
||||||
));
|
PayloadVariant::VecI32(modal.payload.user_ids.clone()),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Priority)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Priority)),
|
||||||
StyledSelectChange::Changed(value),
|
StyledSelectChange::Changed(value),
|
||||||
) => {
|
) => {
|
||||||
modal.payload.priority = (*value).into();
|
modal.payload.priority = (*value).into();
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Priority,
|
modal.id,
|
||||||
PayloadVariant::IssuePriority(modal.payload.priority),
|
IssueFieldId::Priority,
|
||||||
));
|
PayloadVariant::IssuePriority(modal.payload.priority),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StrInputChanged(
|
Msg::StrInputChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Title)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Title)),
|
||||||
value,
|
value,
|
||||||
) => {
|
) => {
|
||||||
modal.payload.title = value.clone();
|
modal.payload.title = value.clone();
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Title,
|
modal.id,
|
||||||
PayloadVariant::String(modal.payload.title.clone()),
|
IssueFieldId::Title,
|
||||||
));
|
PayloadVariant::String(modal.payload.title.clone()),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StrInputChanged(
|
Msg::StrInputChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Description)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Description)),
|
||||||
@ -128,18 +149,21 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
) => {
|
) => {
|
||||||
modal.payload.description = Some(value.clone());
|
modal.payload.description = Some(value.clone());
|
||||||
modal.payload.description_text = Some(value.clone());
|
modal.payload.description_text = Some(value.clone());
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Description,
|
modal.id,
|
||||||
PayloadVariant::String(
|
IssueFieldId::Description,
|
||||||
modal
|
PayloadVariant::String(
|
||||||
.payload
|
modal
|
||||||
.description
|
.payload
|
||||||
.as_ref()
|
.description
|
||||||
.cloned()
|
.as_ref()
|
||||||
.unwrap_or_default(),
|
.cloned()
|
||||||
|
.unwrap_or_default(),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
));
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// TimeSpent
|
// TimeSpent
|
||||||
Msg::StrInputChanged(
|
Msg::StrInputChanged(
|
||||||
@ -147,22 +171,28 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
..,
|
..,
|
||||||
) => {
|
) => {
|
||||||
modal.payload.time_spent = modal.time_spent.represent_f64_as_i32();
|
modal.payload.time_spent = modal.time_spent.represent_f64_as_i32();
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::TimeSpent,
|
modal.id,
|
||||||
PayloadVariant::OptionI32(modal.payload.time_spent),
|
IssueFieldId::TimeSpent,
|
||||||
));
|
PayloadVariant::OptionI32(modal.payload.time_spent),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeSpent)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeSpent)),
|
||||||
StyledSelectChange::Changed(..),
|
StyledSelectChange::Changed(..),
|
||||||
) => {
|
) => {
|
||||||
modal.payload.time_spent = modal.time_spent_select.values.get(0).map(|n| *n as i32);
|
modal.payload.time_spent = modal.time_spent_select.values.get(0).map(|n| *n as i32);
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::TimeSpent,
|
modal.id,
|
||||||
PayloadVariant::OptionI32(modal.payload.time_spent),
|
IssueFieldId::TimeSpent,
|
||||||
));
|
PayloadVariant::OptionI32(modal.payload.time_spent),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Time Remaining
|
// Time Remaining
|
||||||
Msg::StrInputChanged(
|
Msg::StrInputChanged(
|
||||||
@ -170,11 +200,14 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
..,
|
..,
|
||||||
) => {
|
) => {
|
||||||
modal.payload.time_remaining = modal.time_remaining.represent_f64_as_i32();
|
modal.payload.time_remaining = modal.time_remaining.represent_f64_as_i32();
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::TimeRemaining,
|
modal.id,
|
||||||
PayloadVariant::OptionI32(modal.payload.time_remaining),
|
IssueFieldId::TimeRemaining,
|
||||||
));
|
PayloadVariant::OptionI32(modal.payload.time_remaining),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeRemaining)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeRemaining)),
|
||||||
@ -182,11 +215,14 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
) => {
|
) => {
|
||||||
modal.payload.time_remaining =
|
modal.payload.time_remaining =
|
||||||
modal.time_remaining_select.values.get(0).map(|n| *n as i32);
|
modal.time_remaining_select.values.get(0).map(|n| *n as i32);
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::TimeRemaining,
|
modal.id,
|
||||||
PayloadVariant::OptionI32(modal.payload.time_remaining),
|
IssueFieldId::TimeRemaining,
|
||||||
));
|
PayloadVariant::OptionI32(modal.payload.time_remaining),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Estimate
|
// Estimate
|
||||||
Msg::StrInputChanged(
|
Msg::StrInputChanged(
|
||||||
@ -194,22 +230,28 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
..,
|
..,
|
||||||
) => {
|
) => {
|
||||||
modal.payload.estimate = modal.estimate.represent_f64_as_i32();
|
modal.payload.estimate = modal.estimate.represent_f64_as_i32();
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Estimate,
|
modal.id,
|
||||||
PayloadVariant::OptionI32(modal.payload.estimate),
|
IssueFieldId::Estimate,
|
||||||
));
|
PayloadVariant::OptionI32(modal.payload.estimate),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Estimate)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Estimate)),
|
||||||
StyledSelectChange::Changed(..),
|
StyledSelectChange::Changed(..),
|
||||||
) => {
|
) => {
|
||||||
modal.payload.estimate = modal.estimate_select.values.get(0).map(|n| *n as i32);
|
modal.payload.estimate = modal.estimate_select.values.get(0).map(|n| *n as i32);
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
modal.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::Estimate,
|
modal.id,
|
||||||
PayloadVariant::OptionI32(modal.payload.estimate),
|
IssueFieldId::Estimate,
|
||||||
));
|
PayloadVariant::OptionI32(modal.payload.estimate),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::ModalChanged(FieldChange::TabChanged(
|
Msg::ModalChanged(FieldChange::TabChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Description)),
|
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Description)),
|
||||||
@ -248,7 +290,7 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
issue_id: modal.id,
|
issue_id: modal.id,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
send_ws_msg(msg);
|
send_ws_msg(msg, model.ws.as_ref());
|
||||||
orders
|
orders
|
||||||
.skip()
|
.skip()
|
||||||
.send_msg(Msg::ModalChanged(FieldChange::ToggleCommentForm(
|
.send_msg(Msg::ModalChanged(FieldChange::ToggleCommentForm(
|
||||||
@ -272,7 +314,7 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
modal.comment_form.creating = true;
|
modal.comment_form.creating = true;
|
||||||
}
|
}
|
||||||
Msg::DeleteComment(comment_id) => {
|
Msg::DeleteComment(comment_id) => {
|
||||||
send_ws_msg(WsMsg::CommentDeleteRequest(*comment_id));
|
send_ws_msg(WsMsg::CommentDeleteRequest(*comment_id), model.ws.as_ref());
|
||||||
orders.skip().send_msg(Msg::ModalDropped);
|
orders.skip().send_msg(Msg::ModalDropped);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,15 +356,13 @@ fn top_modal_row(_model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
|||||||
let issue_id = *id;
|
let issue_id = *id;
|
||||||
|
|
||||||
let click_handler = mouse_ev(Ev::Click, move |_| {
|
let click_handler = mouse_ev(Ev::Click, move |_| {
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
|
|
||||||
let link = format!("http://localhost:7000/issues/{id}", id = issue_id);
|
let link = format!("http://localhost:7000/issues/{id}", id = issue_id);
|
||||||
let el = match seed::html_document().create_element("textarea") {
|
let el = match seed::html_document().create_element("textarea") {
|
||||||
Ok(el) => el
|
Ok(el) => el
|
||||||
.dyn_ref::<web_sys::HtmlTextAreaElement>()
|
.dyn_ref::<web_sys::HtmlTextAreaElement>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone(),
|
.clone(),
|
||||||
_ => return Msg::NoOp,
|
_ => return None as Option<Msg>,
|
||||||
};
|
};
|
||||||
seed::body().append_child(&el).unwrap();
|
seed::body().append_child(&el).unwrap();
|
||||||
el.set_text_content(Some(link.as_str()));
|
el.set_text_content(Some(link.as_str()));
|
||||||
@ -330,7 +370,10 @@ fn top_modal_row(_model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
|||||||
el.set_selection_range(0, 9999).unwrap();
|
el.set_selection_range(0, 9999).unwrap();
|
||||||
seed::html_document().exec_command("copy").unwrap();
|
seed::html_document().exec_command("copy").unwrap();
|
||||||
seed::body().remove_child(&el).unwrap();
|
seed::body().remove_child(&el).unwrap();
|
||||||
Msg::ModalChanged(FieldChange::LinkCopied(FieldId::CopyButtonLabel, true))
|
Some(Msg::ModalChanged(FieldChange::LinkCopied(
|
||||||
|
FieldId::CopyButtonLabel,
|
||||||
|
true,
|
||||||
|
)))
|
||||||
});
|
});
|
||||||
let close_handler = mouse_ev(Ev::Click, |_| Msg::ModalDropped);
|
let close_handler = mouse_ev(Ev::Click, |_| Msg::ModalDropped);
|
||||||
let delete_confirmation_handler = mouse_ev(Ev::Click, move |_| {
|
let delete_confirmation_handler = mouse_ev(Ev::Click, move |_| {
|
||||||
@ -579,7 +622,7 @@ fn comment(model: &Model, modal: &EditIssueModal, comment: &Comment) -> Option<N
|
|||||||
div![
|
div![
|
||||||
class!["content"],
|
class!["content"],
|
||||||
div![class!["userName"], user.name.as_str()],
|
div![class!["userName"], user.name.as_str()],
|
||||||
p![class!["body"], comment.body],
|
p![class!["body"], comment.body.as_str()],
|
||||||
buttons,
|
buttons,
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
@ -2,12 +2,12 @@ use seed::{prelude::*, *};
|
|||||||
|
|
||||||
use jirs_data::{TimeTracking, WsMsg};
|
use jirs_data::{TimeTracking, WsMsg};
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{AddIssueModal, EditIssueModal, ModalType, Model, Page};
|
use crate::model::{AddIssueModal, EditIssueModal, ModalType, Model, Page};
|
||||||
use crate::shared::styled_confirm_modal::StyledConfirmModal;
|
use crate::shared::styled_confirm_modal::StyledConfirmModal;
|
||||||
use crate::shared::styled_modal::{StyledModal, Variant as ModalVariant};
|
use crate::shared::styled_modal::{StyledModal, Variant as ModalVariant};
|
||||||
use crate::shared::{find_issue, ToNode};
|
use crate::shared::{find_issue, go_to_board, ToNode};
|
||||||
use crate::{model, FieldChange, FieldId, Msg};
|
use crate::ws::send_ws_msg;
|
||||||
|
use crate::{model, FieldChange, FieldId, Msg, WebSocketChanged};
|
||||||
|
|
||||||
mod add_issue;
|
mod add_issue;
|
||||||
mod confirm_delete_issue;
|
mod confirm_delete_issue;
|
||||||
@ -19,7 +19,7 @@ pub fn update(msg: &Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>
|
|||||||
match msg {
|
match msg {
|
||||||
Msg::ModalDropped => match model.modals.pop() {
|
Msg::ModalDropped => match model.modals.pop() {
|
||||||
Some(ModalType::EditIssue(..)) | Some(ModalType::AddIssue(..)) => {
|
Some(ModalType::EditIssue(..)) | Some(ModalType::AddIssue(..)) => {
|
||||||
seed::push_route(vec!["board"]);
|
go_to_board();
|
||||||
orders.send_msg(Msg::ChangePage(Page::Project));
|
orders.send_msg(Msg::ChangePage(Page::Project));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -37,12 +37,14 @@ pub fn update(msg: &Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>
|
|||||||
model.modals.push(modal_type.as_ref().clone());
|
model.modals.push(modal_type.as_ref().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
Msg::WsMsg(jirs_data::WsMsg::ProjectIssuesLoaded(_issues)) => match model.page {
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::ProjectIssuesLoaded(_issues))) => {
|
||||||
Page::EditIssue(issue_id) if model.modals.is_empty() => {
|
match model.page {
|
||||||
push_edit_modal(issue_id, model)
|
Page::EditIssue(issue_id) if model.modals.is_empty() => {
|
||||||
|
push_edit_modal(issue_id, model)
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
_ => (),
|
}
|
||||||
},
|
|
||||||
|
|
||||||
Msg::ChangePage(Page::EditIssue(issue_id)) => {
|
Msg::ChangePage(Page::EditIssue(issue_id)) => {
|
||||||
push_edit_modal(*issue_id, model);
|
push_edit_modal(*issue_id, model);
|
||||||
@ -116,6 +118,6 @@ fn push_edit_modal(issue_id: i32, model: &mut Model) {
|
|||||||
Box::new(EditIssueModal::new(issue, time_tracking_type)),
|
Box::new(EditIssueModal::new(issue, time_tracking_type)),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
send_ws_msg(WsMsg::IssueCommentsRequest(issue_id));
|
send_ws_msg(WsMsg::IssueCommentsRequest(issue_id), model.ws.as_ref());
|
||||||
model.modals.push(modal);
|
model.modals.push(modal);
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,8 @@ use crate::shared::styled_editor::Mode;
|
|||||||
use crate::shared::styled_image_input::StyledImageInputState;
|
use crate::shared::styled_image_input::StyledImageInputState;
|
||||||
use crate::shared::styled_input::StyledInputState;
|
use crate::shared::styled_input::StyledInputState;
|
||||||
use crate::shared::styled_select::StyledSelectState;
|
use crate::shared::styled_select::StyledSelectState;
|
||||||
use crate::{EditIssueModalSection, FieldId, ProjectFieldId, HOST_URL};
|
use crate::{EditIssueModalSection, FieldId, ProjectFieldId /*HOST_URL*/};
|
||||||
|
use seed::browser::web_socket::WebSocket;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
pub enum ModalType {
|
pub enum ModalType {
|
||||||
@ -269,6 +270,7 @@ pub struct ProjectSettingsPage {
|
|||||||
pub time_tracking: StyledCheckboxState,
|
pub time_tracking: StyledCheckboxState,
|
||||||
pub column_drag: DragState,
|
pub column_drag: DragState,
|
||||||
pub edit_column_id: Option<IssueStatusId>,
|
pub edit_column_id: Option<IssueStatusId>,
|
||||||
|
pub creating_issue_status: bool,
|
||||||
pub name: StyledInputState,
|
pub name: StyledInputState,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,6 +306,7 @@ impl ProjectSettingsPage {
|
|||||||
),
|
),
|
||||||
column_drag: Default::default(),
|
column_drag: Default::default(),
|
||||||
edit_column_id: None,
|
edit_column_id: None,
|
||||||
|
creating_issue_status: false,
|
||||||
name: StyledInputState::new(
|
name: StyledInputState::new(
|
||||||
FieldId::ProjectSettings(ProjectFieldId::IssueStatusName),
|
FieldId::ProjectSettings(ProjectFieldId::IssueStatusName),
|
||||||
"",
|
"",
|
||||||
@ -424,7 +427,9 @@ pub enum PageContent {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
pub ws: Option<WebSocket>,
|
||||||
pub host_url: String,
|
pub host_url: String,
|
||||||
|
pub ws_url: String,
|
||||||
pub access_token: Option<Uuid>,
|
pub access_token: Option<Uuid>,
|
||||||
pub about_tooltip_visible: bool,
|
pub about_tooltip_visible: bool,
|
||||||
|
|
||||||
@ -451,10 +456,10 @@ pub struct Model {
|
|||||||
pub issue_statuses: Vec<IssueStatus>,
|
pub issue_statuses: Vec<IssueStatus>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Model {
|
impl Model {
|
||||||
fn default() -> Self {
|
pub fn new(host_url: String, ws_url: String) -> Self {
|
||||||
let host_url = unsafe { HOST_URL.clone() };
|
|
||||||
Self {
|
Self {
|
||||||
|
ws: None,
|
||||||
access_token: None,
|
access_token: None,
|
||||||
user: None,
|
user: None,
|
||||||
issue_form: None,
|
issue_form: None,
|
||||||
@ -465,6 +470,7 @@ impl Default for Model {
|
|||||||
comments_by_project_id: Default::default(),
|
comments_by_project_id: Default::default(),
|
||||||
page: Page::Project,
|
page: Page::Project,
|
||||||
host_url,
|
host_url,
|
||||||
|
ws_url,
|
||||||
page_content: PageContent::Project(Box::new(ProjectPage::default())),
|
page_content: PageContent::Project(Box::new(ProjectPage::default())),
|
||||||
modals: vec![],
|
modals: vec![],
|
||||||
project: None,
|
project: None,
|
||||||
|
@ -3,7 +3,6 @@ use web_sys::FormData;
|
|||||||
|
|
||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{Model, Page, PageContent, ProfilePage};
|
use crate::model::{Model, Page, PageContent, ProfilePage};
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_field::StyledField;
|
use crate::shared::styled_field::StyledField;
|
||||||
@ -11,7 +10,8 @@ use crate::shared::styled_form::StyledForm;
|
|||||||
use crate::shared::styled_image_input::StyledImageInput;
|
use crate::shared::styled_image_input::StyledImageInput;
|
||||||
use crate::shared::styled_input::StyledInput;
|
use crate::shared::styled_input::StyledInput;
|
||||||
use crate::shared::{inner_layout, ToNode};
|
use crate::shared::{inner_layout, ToNode};
|
||||||
use crate::{FieldId, Msg, PageChanged, ProfilePageChange, HOST_URL};
|
use crate::ws::send_ws_msg;
|
||||||
|
use crate::{FieldId, Msg, PageChanged, ProfilePageChange, WebSocketChanged};
|
||||||
|
|
||||||
pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
let user = match model.user {
|
let user = match model.user {
|
||||||
@ -20,8 +20,9 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
};
|
};
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Msg::WsMsg(WsMsg::AuthorizeLoaded(..)) | Msg::ChangePage(Page::Profile) => {
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(..)))
|
||||||
send_ws_msg(WsMsg::ProjectRequest);
|
| Msg::ChangePage(Page::Profile) => {
|
||||||
|
send_ws_msg(WsMsg::ProjectRequest, model.ws.as_ref());
|
||||||
model.page_content = PageContent::Profile(Box::new(ProfilePage::new(user)));
|
model.page_content = PageContent::Profile(Box::new(ProfilePage::new(user)));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@ -50,10 +51,13 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
fd.set_with_str("token", format!("{}", token).as_str())
|
fd.set_with_str("token", format!("{}", token).as_str())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
fd.set_with_blob("avatar", file).unwrap();
|
fd.set_with_blob("avatar", file).unwrap();
|
||||||
orders.perform_cmd(update_avatar(fd));
|
orders.perform_cmd(update_avatar(fd, model.host_url.clone()));
|
||||||
orders.skip();
|
orders.skip();
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::AvatarUrlChanged(user_id, avatar_url)) => {
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::AvatarUrlChanged(
|
||||||
|
user_id,
|
||||||
|
avatar_url,
|
||||||
|
))) => {
|
||||||
if let Some(me) = model.user.as_mut() {
|
if let Some(me) = model.user.as_mut() {
|
||||||
if me.id == user_id {
|
if me.id == user_id {
|
||||||
profile_page.avatar.url = Some(avatar_url.clone());
|
profile_page.avatar.url = Some(avatar_url.clone());
|
||||||
@ -61,10 +65,13 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::PageChanged(PageChanged::Profile(ProfilePageChange::SubmitForm)) => {
|
Msg::PageChanged(PageChanged::Profile(ProfilePageChange::SubmitForm)) => {
|
||||||
send_ws_msg(WsMsg::ProfileUpdate(
|
send_ws_msg(
|
||||||
profile_page.email.value.clone(),
|
WsMsg::ProfileUpdate(
|
||||||
profile_page.name.value.clone(),
|
profile_page.email.value.clone(),
|
||||||
))
|
profile_page.name.value.clone(),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -132,12 +139,17 @@ pub fn view(model: &Model) -> Node<Msg> {
|
|||||||
inner_layout(model, "profile", vec![content], empty![])
|
inner_layout(model, "profile", vec![content], empty![])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_avatar(data: FormData) -> Result<Msg, Msg> {
|
async fn update_avatar(data: FormData, host_url: String) -> Option<Msg> {
|
||||||
let host_url = unsafe { HOST_URL.clone() };
|
|
||||||
let path = format!("{}/avatar/", host_url);
|
let path = format!("{}/avatar/", host_url);
|
||||||
Request::new(path)
|
let result = Request::new(path)
|
||||||
.method(Method::Post)
|
.method(Method::Post)
|
||||||
.body(data.into())
|
.body(data.into())
|
||||||
.fetch_string(Msg::AvatarUpdateFetched)
|
.fetch()
|
||||||
.await
|
.await;
|
||||||
|
let response = match result {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(_) => return None,
|
||||||
|
};
|
||||||
|
let text = response.text().await.ok()?;
|
||||||
|
Some(Msg::AvatarUpdateFetched(text))
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,15 @@ use seed::{prelude::*, *};
|
|||||||
|
|
||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{ModalType, Model, Page, PageContent, ProjectPage};
|
use crate::model::{ModalType, Model, Page, PageContent, ProjectPage};
|
||||||
use crate::shared::styled_avatar::StyledAvatar;
|
use crate::shared::styled_avatar::StyledAvatar;
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_icon::{Icon, StyledIcon};
|
use crate::shared::styled_icon::{Icon, StyledIcon};
|
||||||
use crate::shared::styled_input::StyledInput;
|
use crate::shared::styled_input::StyledInput;
|
||||||
use crate::shared::styled_select::StyledSelectChange;
|
use crate::shared::styled_select::StyledSelectChange;
|
||||||
use crate::shared::{drag_ev, inner_layout, ToNode};
|
use crate::shared::{inner_layout, ToNode};
|
||||||
use crate::{BoardPageChange, EditIssueModalSection, FieldId, Msg, PageChanged};
|
use crate::ws::send_ws_msg;
|
||||||
|
use crate::{BoardPageChange, EditIssueModalSection, FieldId, Msg, PageChanged, WebSocketChanged};
|
||||||
|
|
||||||
pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
if model.user.is_none() {
|
if model.user.is_none() {
|
||||||
@ -33,16 +33,16 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
};
|
};
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Msg::WsMsg(WsMsg::AuthorizeLoaded(..))
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(..)))
|
||||||
| Msg::ChangePage(Page::Project)
|
| Msg::ChangePage(Page::Project)
|
||||||
| Msg::ChangePage(Page::AddIssue)
|
| Msg::ChangePage(Page::AddIssue)
|
||||||
| Msg::ChangePage(Page::EditIssue(..)) => {
|
| Msg::ChangePage(Page::EditIssue(..)) => {
|
||||||
send_ws_msg(jirs_data::WsMsg::ProjectRequest);
|
send_ws_msg(jirs_data::WsMsg::ProjectRequest, model.ws.as_ref());
|
||||||
send_ws_msg(jirs_data::WsMsg::ProjectIssuesRequest);
|
send_ws_msg(jirs_data::WsMsg::ProjectIssuesRequest, model.ws.as_ref());
|
||||||
send_ws_msg(jirs_data::WsMsg::ProjectUsersRequest);
|
send_ws_msg(jirs_data::WsMsg::ProjectUsersRequest, model.ws.as_ref());
|
||||||
send_ws_msg(jirs_data::WsMsg::IssueStatusesRequest);
|
send_ws_msg(jirs_data::WsMsg::IssueStatusesRequest, model.ws.as_ref());
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::IssueUpdated(issue)) => {
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::IssueUpdated(issue))) => {
|
||||||
let mut old: Vec<Issue> = vec![];
|
let mut old: Vec<Issue> = vec![];
|
||||||
std::mem::swap(&mut old, &mut model.issues);
|
std::mem::swap(&mut old, &mut model.issues);
|
||||||
for is in old {
|
for is in old {
|
||||||
@ -53,7 +53,7 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::IssueDeleted(id)) => {
|
Msg::WebSocketChange(WebSocketChanged::WsMsg(WsMsg::IssueDeleted(id))) => {
|
||||||
let mut old: Vec<Issue> = vec![];
|
let mut old: Vec<Issue> = vec![];
|
||||||
std::mem::swap(&mut old, &mut model.issues);
|
std::mem::swap(&mut old, &mut model.issues);
|
||||||
for is in old {
|
for is in old {
|
||||||
@ -123,7 +123,10 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
project_page.issue_drag.clear_last();
|
project_page.issue_drag.clear_last();
|
||||||
}
|
}
|
||||||
Msg::DeleteIssue(issue_id) => {
|
Msg::DeleteIssue(issue_id) => {
|
||||||
send_ws_msg(jirs_data::WsMsg::IssueDeleteRequest(issue_id));
|
send_ws_msg(
|
||||||
|
jirs_data::WsMsg::IssueDeleteRequest(issue_id),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -306,16 +309,16 @@ fn project_issue_list(model: &Model, status: &jirs_data::IssueStatus) -> Node<Ms
|
|||||||
let send_status = status.id;
|
let send_status = status.id;
|
||||||
let drop_handler = drag_ev(Ev::Drop, move |ev| {
|
let drop_handler = drag_ev(Ev::Drop, move |ev| {
|
||||||
ev.prevent_default();
|
ev.prevent_default();
|
||||||
Msg::PageChanged(PageChanged::Board(BoardPageChange::IssueDropZone(
|
Some(Msg::PageChanged(PageChanged::Board(
|
||||||
send_status,
|
BoardPageChange::IssueDropZone(send_status),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
|
|
||||||
let send_status = status.id;
|
let send_status = status.id;
|
||||||
let drag_over_handler = drag_ev(Ev::DragOver, move |ev| {
|
let drag_over_handler = drag_ev(Ev::DragOver, move |ev| {
|
||||||
ev.prevent_default();
|
ev.prevent_default();
|
||||||
Msg::PageChanged(PageChanged::Board(BoardPageChange::IssueDragOverStatus(
|
Some(Msg::PageChanged(PageChanged::Board(
|
||||||
send_status,
|
BoardPageChange::IssueDragOverStatus(send_status),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -395,25 +398,27 @@ fn project_issue(model: &Model, issue: &Issue) -> Node<Msg> {
|
|||||||
|
|
||||||
let issue_id = issue.id;
|
let issue_id = issue.id;
|
||||||
let drag_started = drag_ev(Ev::DragStart, move |_| {
|
let drag_started = drag_ev(Ev::DragStart, move |_| {
|
||||||
Msg::PageChanged(PageChanged::Board(BoardPageChange::IssueDragStarted(
|
Some(Msg::PageChanged(PageChanged::Board(
|
||||||
issue_id,
|
BoardPageChange::IssueDragStarted(issue_id),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let drag_stopped = drag_ev(Ev::DragEnd, move |_| {
|
let drag_stopped = drag_ev(Ev::DragEnd, move |_| {
|
||||||
Msg::PageChanged(PageChanged::Board(BoardPageChange::IssueDragStopped(
|
Some(Msg::PageChanged(PageChanged::Board(
|
||||||
issue_id,
|
BoardPageChange::IssueDragStopped(issue_id),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let drag_over_handler = drag_ev(Ev::DragOver, move |ev| {
|
let drag_over_handler = drag_ev(Ev::DragOver, move |ev| {
|
||||||
ev.prevent_default();
|
ev.prevent_default();
|
||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
Msg::PageChanged(PageChanged::Board(BoardPageChange::ExchangePosition(
|
Some(Msg::PageChanged(PageChanged::Board(
|
||||||
issue_id,
|
BoardPageChange::ExchangePosition(issue_id),
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let issue_id = issue.id;
|
let issue_id = issue.id;
|
||||||
let drag_out = drag_ev(Ev::DragLeave, move |_| {
|
let drag_out = drag_ev(Ev::DragLeave, move |_| {
|
||||||
Msg::PageChanged(PageChanged::Board(BoardPageChange::DragLeave(issue_id)))
|
Some(Msg::PageChanged(PageChanged::Board(
|
||||||
|
BoardPageChange::DragLeave(issue_id),
|
||||||
|
)))
|
||||||
});
|
});
|
||||||
|
|
||||||
let class_list = vec!["issue"];
|
let class_list = vec!["issue"];
|
||||||
@ -428,7 +433,7 @@ fn project_issue(model: &Model, issue: &Issue) -> Node<Msg> {
|
|||||||
drag_stopped,
|
drag_stopped,
|
||||||
drag_over_handler,
|
drag_over_handler,
|
||||||
drag_out,
|
drag_out,
|
||||||
p![attrs![At::Class => "title"], issue.title,],
|
p![attrs![At::Class => "title"], issue.title.as_str()],
|
||||||
div![
|
div![
|
||||||
attrs![At::Class => "bottom"],
|
attrs![At::Class => "bottom"],
|
||||||
div![
|
div![
|
||||||
|
@ -5,7 +5,6 @@ use jirs_data::{
|
|||||||
IssueStatus, IssueStatusId, ProjectCategory, TimeTracking, ToVec, UpdateProjectPayload, WsMsg,
|
IssueStatus, IssueStatusId, ProjectCategory, TimeTracking, ToVec, UpdateProjectPayload, WsMsg,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{
|
use crate::model::{
|
||||||
DeleteIssueStatusModal, ModalType, Model, Page, PageContent, ProjectSettingsPage,
|
DeleteIssueStatusModal, ModalType, Model, Page, PageContent, ProjectSettingsPage,
|
||||||
};
|
};
|
||||||
@ -18,9 +17,12 @@ use crate::shared::styled_icon::{Icon, StyledIcon};
|
|||||||
use crate::shared::styled_input::StyledInput;
|
use crate::shared::styled_input::StyledInput;
|
||||||
use crate::shared::styled_select::{StyledSelect, StyledSelectChange};
|
use crate::shared::styled_select::{StyledSelect, StyledSelectChange};
|
||||||
use crate::shared::styled_textarea::StyledTextarea;
|
use crate::shared::styled_textarea::StyledTextarea;
|
||||||
use crate::shared::{drag_ev, inner_layout, ToChild, ToNode};
|
use crate::shared::{inner_layout, ToChild, ToNode};
|
||||||
|
use crate::ws::send_ws_msg;
|
||||||
use crate::FieldChange::TabChanged;
|
use crate::FieldChange::TabChanged;
|
||||||
use crate::{model, FieldId, Msg, PageChanged, ProjectFieldId, ProjectPageChange};
|
use crate::{
|
||||||
|
model, FieldId, Msg, PageChanged, ProjectFieldId, ProjectPageChange, WebSocketChanged,
|
||||||
|
};
|
||||||
|
|
||||||
static TIME_TRACKING_FIBONACCI: &'static str = "Tracking employees’ time carries the risk of having them feel like they are being spied on. This is one of the most common fears that employees have when a time tracking system is implemented. No one likes to feel like they’re always being watched.";
|
static TIME_TRACKING_FIBONACCI: &'static str = "Tracking employees’ time carries the risk of having them feel like they are being spied on. This is one of the most common fears that employees have when a time tracking system is implemented. No one likes to feel like they’re always being watched.";
|
||||||
static TIME_TRACKING_HOURLY: &'static str = "Employees may feel intimidated by demands to track their time. Or they could feel that they’re constantly being watched and evaluated. And for overly ambitious managers, employee time tracking may open the doors to excessive micromanaging.";
|
static TIME_TRACKING_HOURLY: &'static str = "Employees may feel intimidated by demands to track their time. Or they could feel that they’re constantly being watched and evaluated. And for overly ambitious managers, employee time tracking may open the doors to excessive micromanaging.";
|
||||||
@ -31,22 +33,25 @@ pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Msg::WsMsg(WsMsg::AuthorizeLoaded(..)) => {
|
Msg::WebSocketChange(ref change) => match change {
|
||||||
send_ws_msg(WsMsg::ProjectRequest);
|
WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(..)) => {
|
||||||
send_ws_msg(WsMsg::IssueStatusesRequest);
|
send_ws_msg(WsMsg::ProjectRequest, model.ws.as_ref());
|
||||||
send_ws_msg(WsMsg::ProjectIssuesRequest);
|
send_ws_msg(WsMsg::IssueStatusesRequest, model.ws.as_ref());
|
||||||
}
|
send_ws_msg(WsMsg::ProjectIssuesRequest, model.ws.as_ref());
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::ProjectLoaded(..)) => {
|
||||||
|
build_page_content(model);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
Msg::ChangePage(Page::ProjectSettings) => {
|
Msg::ChangePage(Page::ProjectSettings) => {
|
||||||
build_page_content(model);
|
build_page_content(model);
|
||||||
if model.user.is_some() {
|
if model.user.is_some() {
|
||||||
send_ws_msg(WsMsg::ProjectRequest);
|
send_ws_msg(WsMsg::ProjectRequest, model.ws.as_ref());
|
||||||
send_ws_msg(WsMsg::IssueStatusesRequest);
|
send_ws_msg(WsMsg::IssueStatusesRequest, model.ws.as_ref());
|
||||||
send_ws_msg(WsMsg::ProjectIssuesRequest);
|
send_ws_msg(WsMsg::ProjectIssuesRequest, model.ws.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::ProjectLoaded(..)) => {
|
|
||||||
build_page_content(model);
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,14 +91,17 @@ pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>)
|
|||||||
page.description_mode = mode;
|
page.description_mode = mode;
|
||||||
}
|
}
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::SubmitForm)) => {
|
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::SubmitForm)) => {
|
||||||
send_ws_msg(WsMsg::ProjectUpdateRequest(UpdateProjectPayload {
|
send_ws_msg(
|
||||||
id: page.payload.id,
|
WsMsg::ProjectUpdateRequest(UpdateProjectPayload {
|
||||||
name: page.payload.name.clone(),
|
id: page.payload.id,
|
||||||
url: page.payload.url.clone(),
|
name: page.payload.name.clone(),
|
||||||
description: page.payload.description.clone(),
|
url: page.payload.url.clone(),
|
||||||
category: page.payload.category.clone(),
|
description: page.payload.description.clone(),
|
||||||
time_tracking: Some(page.time_tracking.value.into()),
|
category: page.payload.category.clone(),
|
||||||
}));
|
time_tracking: Some(page.time_tracking.value.into()),
|
||||||
|
}),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::ColumnDragStarted(
|
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::ColumnDragStarted(
|
||||||
issue_status_id,
|
issue_status_id,
|
||||||
@ -128,7 +136,10 @@ pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>)
|
|||||||
.find(|is| Some(is.id) == old_id)
|
.find(|is| Some(is.id) == old_id)
|
||||||
.map(|is| (is.id, is.position))
|
.map(|is| (is.id, is.position))
|
||||||
{
|
{
|
||||||
send_ws_msg(WsMsg::IssueStatusUpdate(id, name.to_string(), pos))
|
send_ws_msg(
|
||||||
|
WsMsg::IssueStatusUpdate(id, name.to_string(), pos),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
page.name.value = model
|
page.name.value = model
|
||||||
@ -259,91 +270,15 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
let columns: Vec<Node<Msg>> = model
|
let columns: Vec<Node<Msg>> = model
|
||||||
.issue_statuses
|
.issue_statuses
|
||||||
.iter()
|
.iter()
|
||||||
.map(|is| {
|
.map(|is| column_preview(is, page, &per_column_issue_count, column_style.as_str()))
|
||||||
let id = is.id;
|
|
||||||
let drag_started = drag_ev(Ev::DragStart, move |_| {
|
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::ColumnDragStarted(
|
|
||||||
id,
|
|
||||||
)))
|
|
||||||
});
|
|
||||||
let drag_stopped = drag_ev(Ev::DragEnd, move |_| {
|
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::ColumnDragStopped(
|
|
||||||
id,
|
|
||||||
)))
|
|
||||||
});
|
|
||||||
let drag_over_handler = drag_ev(Ev::DragOver, move |ev| {
|
|
||||||
ev.prevent_default();
|
|
||||||
ev.stop_propagation();
|
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::ColumnExchangePosition(
|
|
||||||
id,
|
|
||||||
)))
|
|
||||||
});
|
|
||||||
let drag_out = drag_ev(Ev::DragLeave, move |_| {
|
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::ColumnDragLeave(id)))
|
|
||||||
});
|
|
||||||
|
|
||||||
if page.edit_column_id == Some(id) {
|
|
||||||
let blur = ev("focusout", |_| {
|
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::EditIssueStatusName(None)))
|
|
||||||
});
|
|
||||||
let input = StyledInput::build(FieldId::ProjectSettings(ProjectFieldId::IssueStatusName))
|
|
||||||
.state(&page.name)
|
|
||||||
.primary()
|
|
||||||
.auto_focus()
|
|
||||||
.on_input_ev(blur)
|
|
||||||
.build()
|
|
||||||
.into_node();
|
|
||||||
|
|
||||||
div![
|
|
||||||
class!["columnPreview"],
|
|
||||||
div![class!["columnName"], input]
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
let on_edit = mouse_ev(Ev::Click, move |_| {
|
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::EditIssueStatusName(Some(id))))
|
|
||||||
});
|
|
||||||
let issue_count_in_column = per_column_issue_count.get(&id).cloned().unwrap_or_default();
|
|
||||||
let delete_row = if issue_count_in_column == 0 {
|
|
||||||
let on_delete = mouse_ev(Ev::Click, move |ev| {
|
|
||||||
ev.prevent_default();
|
|
||||||
ev.stop_propagation();
|
|
||||||
Msg::ModalOpened(Box::new(ModalType::DeleteIssueStatusModal(Box::new(DeleteIssueStatusModal::new(id)))))
|
|
||||||
});
|
|
||||||
let delete = StyledButton::build()
|
|
||||||
.primary()
|
|
||||||
.add_class("removeColumn")
|
|
||||||
.icon(Icon::Trash)
|
|
||||||
.on_click(on_delete)
|
|
||||||
.build()
|
|
||||||
.into_node();
|
|
||||||
div![class!["removeColumn"], delete]
|
|
||||||
} else {
|
|
||||||
div![class!["issueCount"], format!("Issues in column: {}", issue_count_in_column)]
|
|
||||||
};
|
|
||||||
|
|
||||||
div![
|
|
||||||
class!["columnPreview"],
|
|
||||||
attrs![At::Style => column_style.as_str(), At::Draggable => "true", At::DropZone => "true"],
|
|
||||||
div![class!["columnName"], span![is.name], on_edit, delete_row],
|
|
||||||
drag_started,
|
|
||||||
drag_stopped,
|
|
||||||
drag_over_handler,
|
|
||||||
drag_out,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
let add_column = StyledIcon::build(Icon::Plus).build().into_node();
|
|
||||||
let columns_section = section![
|
let columns_section = section![
|
||||||
class!["columnsSection"],
|
class!["columnsSection"],
|
||||||
div![
|
div![
|
||||||
class!["columns"],
|
class!["columns"],
|
||||||
columns,
|
columns,
|
||||||
div![
|
add_column(page, column_style.as_str())
|
||||||
class!["columnPreview"],
|
|
||||||
attrs![At::Style => column_style.as_str()],
|
|
||||||
div![class!["columnName addColumn"], add_column]
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
let columns_field = StyledField::build()
|
let columns_field = StyledField::build()
|
||||||
@ -451,7 +386,10 @@ fn sync(model: &mut Model) {
|
|||||||
Some(is) => is,
|
Some(is) => is,
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
send_ws_msg(WsMsg::IssueStatusUpdate(*id, name.clone(), *position))
|
send_ws_msg(
|
||||||
|
WsMsg::IssueStatusUpdate(*id, name.clone(), *position),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,3 +400,137 @@ fn build_page_content(model: &mut Model) {
|
|||||||
};
|
};
|
||||||
model.page_content = PageContent::ProjectSettings(Box::new(ProjectSettingsPage::new(project)));
|
model.page_content = PageContent::ProjectSettings(Box::new(ProjectSettingsPage::new(project)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_column(page: &ProjectSettingsPage, column_style: &str) -> Node<Msg> {
|
||||||
|
let on_click = mouse_ev(Ev::Click, move |_| {
|
||||||
|
Msg::PageChanged(PageChanged::ProjectSettings(
|
||||||
|
ProjectPageChange::EditIssueStatusName(Some(0)),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
|
||||||
|
if page.edit_column_id == Some(0) {
|
||||||
|
let blur = ev("focusout", |_| {
|
||||||
|
Msg::PageChanged(PageChanged::ProjectSettings(
|
||||||
|
ProjectPageChange::EditIssueStatusName(None),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
|
||||||
|
let input = StyledInput::build(FieldId::ProjectSettings(ProjectFieldId::IssueStatusName))
|
||||||
|
.state(&page.name)
|
||||||
|
.primary()
|
||||||
|
.auto_focus()
|
||||||
|
.on_input_ev(blur)
|
||||||
|
.build()
|
||||||
|
.into_node();
|
||||||
|
|
||||||
|
div![class!["columnPreview"], div![class!["columnName"], input]]
|
||||||
|
} else {
|
||||||
|
let add_column = StyledIcon::build(Icon::Plus).build().into_node();
|
||||||
|
div![
|
||||||
|
class!["columnPreview"],
|
||||||
|
attrs![At::Style => column_style],
|
||||||
|
div![class!["columnName addColumn"], add_column],
|
||||||
|
on_click,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn column_preview(
|
||||||
|
is: &IssueStatus,
|
||||||
|
page: &ProjectSettingsPage,
|
||||||
|
per_column_issue_count: &HashMap<i32, i32>,
|
||||||
|
column_style: &str,
|
||||||
|
) -> Node<Msg> {
|
||||||
|
if page.edit_column_id == Some(is.id) {
|
||||||
|
let blur = ev("focusout", |_| {
|
||||||
|
Msg::PageChanged(PageChanged::ProjectSettings(
|
||||||
|
ProjectPageChange::EditIssueStatusName(None),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
let input = StyledInput::build(FieldId::ProjectSettings(ProjectFieldId::IssueStatusName))
|
||||||
|
.state(&page.name)
|
||||||
|
.primary()
|
||||||
|
.auto_focus()
|
||||||
|
.on_input_ev(blur)
|
||||||
|
.build()
|
||||||
|
.into_node();
|
||||||
|
|
||||||
|
div![class!["columnPreview"], div![class!["columnName"], input]]
|
||||||
|
} else {
|
||||||
|
show_column_preview(is, per_column_issue_count, column_style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_column_preview(
|
||||||
|
is: &IssueStatus,
|
||||||
|
per_column_issue_count: &HashMap<i32, i32>,
|
||||||
|
column_style: &str,
|
||||||
|
) -> Node<Msg> {
|
||||||
|
let id = is.id;
|
||||||
|
let drag_started = drag_ev(Ev::DragStart, move |_| {
|
||||||
|
Some(Msg::PageChanged(PageChanged::ProjectSettings(
|
||||||
|
ProjectPageChange::ColumnDragStarted(id),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let drag_stopped = drag_ev(Ev::DragEnd, move |_| {
|
||||||
|
Some(Msg::PageChanged(PageChanged::ProjectSettings(
|
||||||
|
ProjectPageChange::ColumnDragStopped(id),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let drag_over_handler = drag_ev(Ev::DragOver, move |ev| {
|
||||||
|
ev.prevent_default();
|
||||||
|
ev.stop_propagation();
|
||||||
|
Some(Msg::PageChanged(PageChanged::ProjectSettings(
|
||||||
|
ProjectPageChange::ColumnExchangePosition(id),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let drag_out = drag_ev(Ev::DragLeave, move |_| {
|
||||||
|
Some(Msg::PageChanged(PageChanged::ProjectSettings(
|
||||||
|
ProjectPageChange::ColumnDragLeave(id),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
|
||||||
|
let on_edit = mouse_ev(Ev::Click, move |_| {
|
||||||
|
Msg::PageChanged(PageChanged::ProjectSettings(
|
||||||
|
ProjectPageChange::EditIssueStatusName(Some(id)),
|
||||||
|
))
|
||||||
|
});
|
||||||
|
let issue_count_in_column = per_column_issue_count.get(&id).cloned().unwrap_or_default();
|
||||||
|
let delete_row = if issue_count_in_column == 0 {
|
||||||
|
let on_delete = mouse_ev(Ev::Click, move |ev| {
|
||||||
|
ev.prevent_default();
|
||||||
|
ev.stop_propagation();
|
||||||
|
Msg::ModalOpened(Box::new(ModalType::DeleteIssueStatusModal(Box::new(
|
||||||
|
DeleteIssueStatusModal::new(id),
|
||||||
|
))))
|
||||||
|
});
|
||||||
|
let delete = StyledButton::build()
|
||||||
|
.primary()
|
||||||
|
.add_class("removeColumn")
|
||||||
|
.icon(Icon::Trash)
|
||||||
|
.on_click(on_delete)
|
||||||
|
.build()
|
||||||
|
.into_node();
|
||||||
|
div![class!["removeColumn"], delete]
|
||||||
|
} else {
|
||||||
|
div![
|
||||||
|
class!["issueCount"],
|
||||||
|
format!("Issues in column: {}", issue_count_in_column)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
div![
|
||||||
|
class!["columnPreview"],
|
||||||
|
attrs![At::Style => column_style, At::Draggable => "true", At::DropZone => "true"],
|
||||||
|
div![
|
||||||
|
class!["columnName"],
|
||||||
|
span![is.name.as_str()],
|
||||||
|
on_edit,
|
||||||
|
delete_row
|
||||||
|
],
|
||||||
|
drag_started,
|
||||||
|
drag_stopped,
|
||||||
|
drag_over_handler,
|
||||||
|
drag_out,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ pub fn render(model: &Model) -> Node<Msg> {
|
|||||||
project_icon,
|
project_icon,
|
||||||
div![
|
div![
|
||||||
class!["projectTexts"],
|
class!["projectTexts"],
|
||||||
div![class!["projectName"], project.name],
|
div![class!["projectName"], project.name.as_str()],
|
||||||
div![class!["projectCategory"], project.category.to_string()]
|
div![class!["projectCategory"], project.category.to_string()]
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use seed::{prelude::*, *};
|
use seed::{prelude::*, *};
|
||||||
use wasm_bindgen::JsCast;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
@ -33,6 +33,18 @@ pub trait ToChild {
|
|||||||
fn to_child(&self) -> Self::Builder;
|
fn to_child(&self) -> Self::Builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn go_to_board() {
|
||||||
|
go_to("/board");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn go_to_login() {
|
||||||
|
go_to("/login");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn go_to(url: &str) {
|
||||||
|
seed::push_route(Url::from_str(url).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_issue(model: &Model, issue_id: IssueId) -> Option<&Issue> {
|
pub fn find_issue(model: &Model, issue_id: IssueId) -> Option<&Issue> {
|
||||||
model.issues.iter().find(|issue| issue.id == issue_id)
|
model.issues.iter().find(|issue| issue.id == issue_id)
|
||||||
}
|
}
|
||||||
@ -107,13 +119,3 @@ pub fn read_auth_token() -> Result<uuid::Uuid, String> {
|
|||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| "Bad token format".to_string())
|
.map_err(|_| "Bad token format".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drag_ev<Ms>(
|
|
||||||
trigger: impl Into<Ev>,
|
|
||||||
handler: impl FnOnce(web_sys::DragEvent) -> Ms + 'static + Clone,
|
|
||||||
) -> EventHandler<Ms> {
|
|
||||||
let closure_handler = move |event: web_sys::Event| {
|
|
||||||
(handler.clone())(event.dyn_ref::<web_sys::DragEvent>().unwrap().clone())
|
|
||||||
};
|
|
||||||
EventHandler::new(trigger, closure_handler)
|
|
||||||
}
|
|
||||||
|
@ -102,11 +102,10 @@ impl ToNode for ChildBuilder {
|
|||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let id = field_id.as_ref().map(|f| f.to_string()).unwrap_or_default();
|
let id = field_id.as_ref().map(|f| f.to_string()).unwrap_or_default();
|
||||||
let handler = if let Some(field_id) = field_id {
|
let field_id_clone = field_id.clone();
|
||||||
mouse_ev(Ev::Click, move |_| Msg::U32InputChanged(field_id, value))
|
let handler: EventHandler<Msg> = mouse_ev(Ev::Click, move |_| {
|
||||||
} else {
|
field_id_clone.map(|field_id| Msg::U32InputChanged(field_id, value))
|
||||||
ev(Ev::FullScreenError, move |_| Msg::NoOp)
|
});
|
||||||
};
|
|
||||||
|
|
||||||
class_list.push("styledCheckboxChild".to_string());
|
class_list.push("styledCheckboxChild".to_string());
|
||||||
class_list.push(if selected { "selected" } else { "" }.to_string());
|
class_list.push(if selected { "selected" } else { "" }.to_string());
|
||||||
|
@ -222,11 +222,11 @@ pub fn render(values: StyledInput) -> Node<Msg> {
|
|||||||
}));
|
}));
|
||||||
input_handlers.push(ev(Ev::KeyUp, move |event| {
|
input_handlers.push(ev(Ev::KeyUp, move |event| {
|
||||||
event.stop_propagation();
|
event.stop_propagation();
|
||||||
Msg::NoOp
|
None as Option<Msg>
|
||||||
}));
|
}));
|
||||||
input_handlers.push(ev(Ev::Click, move |event| {
|
input_handlers.push(ev(Ev::Click, move |event| {
|
||||||
event.stop_propagation();
|
event.stop_propagation();
|
||||||
Msg::NoOp
|
None as Option<Msg>
|
||||||
}));
|
}));
|
||||||
|
|
||||||
div![
|
div![
|
||||||
|
@ -122,7 +122,7 @@ pub fn render(values: StyledModal) -> Node<Msg> {
|
|||||||
let close_handler = mouse_ev(Ev::Click, |_| Msg::ModalDropped);
|
let close_handler = mouse_ev(Ev::Click, |_| Msg::ModalDropped);
|
||||||
let body_handler = mouse_ev(Ev::Click, |ev| {
|
let body_handler = mouse_ev(Ev::Click, |ev| {
|
||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
Msg::NoOp
|
None as Option<Msg>
|
||||||
});
|
});
|
||||||
|
|
||||||
let clickable_class = format!("clickableOverlay {}", variant.to_class_name());
|
let clickable_class = format!("clickableOverlay {}", variant.to_class_name());
|
||||||
|
@ -343,7 +343,7 @@ pub fn render(values: StyledSelect) -> Node<Msg> {
|
|||||||
attrs![At::Class => select_class.join(" "), At::Style => dropdown_style.as_str()],
|
attrs![At::Class => select_class.join(" "), At::Style => dropdown_style.as_str()],
|
||||||
keyboard_ev(Ev::KeyUp, |ev| {
|
keyboard_ev(Ev::KeyUp, |ev| {
|
||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
Msg::NoOp
|
None as Option<Msg>
|
||||||
}),
|
}),
|
||||||
div![
|
div![
|
||||||
attrs![At::Class => format!("valueContainer {}", variant)],
|
attrs![At::Class => format!("valueContainer {}", variant)],
|
||||||
|
@ -161,7 +161,7 @@ pub fn render(values: StyledTextarea) -> Node<Msg> {
|
|||||||
let resize_handler = ev(Ev::KeyUp, move |event| {
|
let resize_handler = ev(Ev::KeyUp, move |event| {
|
||||||
event.stop_propagation();
|
event.stop_propagation();
|
||||||
if handler_disable_auto_resize {
|
if handler_disable_auto_resize {
|
||||||
return Msg::NoOp;
|
return None as Option<Msg>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let target = event.target().unwrap();
|
let target = event.target().unwrap();
|
||||||
@ -172,7 +172,7 @@ pub fn render(values: StyledTextarea) -> Node<Msg> {
|
|||||||
textarea
|
textarea
|
||||||
.style()
|
.style()
|
||||||
.set_css_text(format!("height: {min_height}px", min_height = min_height).as_str());
|
.set_css_text(format!("height: {min_height}px", min_height = min_height).as_str());
|
||||||
Msg::NoOp
|
None as Option<Msg>
|
||||||
});
|
});
|
||||||
|
|
||||||
let handler_disable_auto_resize = disable_auto_resize;
|
let handler_disable_auto_resize = disable_auto_resize;
|
||||||
|
@ -5,7 +5,6 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use jirs_data::WsMsg;
|
use jirs_data::WsMsg;
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{Page, PageContent, SignInPage};
|
use crate::model::{Page, PageContent, SignInPage};
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_field::StyledField;
|
use crate::shared::styled_field::StyledField;
|
||||||
@ -15,7 +14,8 @@ use crate::shared::styled_input::StyledInput;
|
|||||||
use crate::shared::styled_link::StyledLink;
|
use crate::shared::styled_link::StyledLink;
|
||||||
use crate::shared::{outer_layout, write_auth_token, ToNode};
|
use crate::shared::{outer_layout, write_auth_token, ToNode};
|
||||||
use crate::validations::{is_email, is_token};
|
use crate::validations::{is_email, is_token};
|
||||||
use crate::{model, FieldId, Msg, SignInFieldId};
|
use crate::ws::send_ws_msg;
|
||||||
|
use crate::{model, FieldId, Msg, SignInFieldId, WebSocketChanged};
|
||||||
|
|
||||||
pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
if model.page != Page::SignIn {
|
if model.page != Page::SignIn {
|
||||||
@ -49,10 +49,10 @@ pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>)
|
|||||||
page.token_touched = true;
|
page.token_touched = true;
|
||||||
}
|
}
|
||||||
Msg::SignInRequest => {
|
Msg::SignInRequest => {
|
||||||
send_ws_msg(WsMsg::AuthenticateRequest(
|
send_ws_msg(
|
||||||
page.email.clone(),
|
WsMsg::AuthenticateRequest(page.email.clone(), page.username.clone()),
|
||||||
page.username.clone(),
|
model.ws.as_ref(),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
Msg::BindClientRequest => {
|
Msg::BindClientRequest => {
|
||||||
let bind_token: uuid::Uuid = match Uuid::from_str(page.token.as_str()) {
|
let bind_token: uuid::Uuid = match Uuid::from_str(page.token.as_str()) {
|
||||||
@ -62,21 +62,24 @@ pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
send_ws_msg(WsMsg::BindTokenCheck(bind_token));
|
send_ws_msg(WsMsg::BindTokenCheck(bind_token), model.ws.as_ref());
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::AuthenticateSuccess) => {
|
Msg::WebSocketChange(change) => match change {
|
||||||
page.login_success = true;
|
WebSocketChanged::WsMsg(WsMsg::AuthenticateSuccess) => {
|
||||||
}
|
page.login_success = true;
|
||||||
Msg::WsMsg(WsMsg::BindTokenOk(access_token)) => {
|
}
|
||||||
match write_auth_token(Some(access_token)) {
|
WebSocketChanged::WsMsg(WsMsg::BindTokenOk(access_token)) => {
|
||||||
Ok(msg) => {
|
match write_auth_token(Some(access_token)) {
|
||||||
orders.skip().send_msg(msg);
|
Ok(msg) => {
|
||||||
}
|
orders.skip().send_msg(msg);
|
||||||
Err(e) => {
|
}
|
||||||
error!(e);
|
Err(e) => {
|
||||||
|
error!(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
_ => (),
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ use seed::{prelude::*, *};
|
|||||||
|
|
||||||
use jirs_data::{SignUpFieldId, WsMsg};
|
use jirs_data::{SignUpFieldId, WsMsg};
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{Page, PageContent, SignUpPage};
|
use crate::model::{Page, PageContent, SignUpPage};
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_field::StyledField;
|
use crate::shared::styled_field::StyledField;
|
||||||
@ -12,7 +11,8 @@ use crate::shared::styled_input::StyledInput;
|
|||||||
use crate::shared::styled_link::StyledLink;
|
use crate::shared::styled_link::StyledLink;
|
||||||
use crate::shared::{outer_layout, ToNode};
|
use crate::shared::{outer_layout, ToNode};
|
||||||
use crate::validations::is_email;
|
use crate::validations::is_email;
|
||||||
use crate::{model, FieldId, Msg};
|
use crate::ws::send_ws_msg;
|
||||||
|
use crate::{model, FieldId, Msg, WebSocketChanged};
|
||||||
|
|
||||||
pub fn update(msg: Msg, model: &mut model::Model, _orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: Msg, model: &mut model::Model, _orders: &mut impl Orders<Msg>) {
|
||||||
if model.page != Page::SignUp {
|
if model.page != Page::SignUp {
|
||||||
@ -42,17 +42,20 @@ pub fn update(msg: Msg, model: &mut model::Model, _orders: &mut impl Orders<Msg>
|
|||||||
page.email_touched = true;
|
page.email_touched = true;
|
||||||
}
|
}
|
||||||
Msg::SignUpRequest => {
|
Msg::SignUpRequest => {
|
||||||
send_ws_msg(WsMsg::SignUpRequest(
|
send_ws_msg(
|
||||||
page.email.clone(),
|
WsMsg::SignUpRequest(page.email.clone(), page.username.clone()),
|
||||||
page.username.clone(),
|
model.ws.as_ref(),
|
||||||
));
|
);
|
||||||
}
|
|
||||||
Msg::WsMsg(WsMsg::SignUpSuccess) => {
|
|
||||||
page.sign_up_success = true;
|
|
||||||
}
|
|
||||||
Msg::WsMsg(WsMsg::SignUpPairTaken) => {
|
|
||||||
page.error = "Pair you give is either taken or is not matching".to_string();
|
|
||||||
}
|
}
|
||||||
|
Msg::WebSocketChange(change) => match change {
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::SignUpSuccess) => {
|
||||||
|
page.sign_up_success = true;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::SignUpPairTaken) => {
|
||||||
|
page.error = "Pair you give is either taken or is not matching".to_string();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,7 +129,7 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
let error_row = if page.error.is_empty() {
|
let error_row = if page.error.is_empty() {
|
||||||
empty![]
|
empty![]
|
||||||
} else {
|
} else {
|
||||||
div![class!["error"], p![page.error]]
|
div![class!["error"], p![page.error.as_str()]]
|
||||||
};
|
};
|
||||||
|
|
||||||
let sign_up_form = StyledForm::build()
|
let sign_up_form = StyledForm::build()
|
||||||
|
@ -2,7 +2,6 @@ use seed::{prelude::*, *};
|
|||||||
|
|
||||||
use jirs_data::{InvitationState, ToVec, UserRole, UsersFieldId, WsMsg};
|
use jirs_data::{InvitationState, ToVec, UserRole, UsersFieldId, WsMsg};
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::*;
|
use crate::model::*;
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_field::StyledField;
|
use crate::shared::styled_field::StyledField;
|
||||||
@ -11,7 +10,8 @@ use crate::shared::styled_input::StyledInput;
|
|||||||
use crate::shared::styled_select::*;
|
use crate::shared::styled_select::*;
|
||||||
use crate::shared::{inner_layout, ToChild, ToNode};
|
use crate::shared::{inner_layout, ToChild, ToNode};
|
||||||
use crate::validations::is_email;
|
use crate::validations::is_email;
|
||||||
use crate::{FieldId, Msg, PageChanged, UsersPageChange};
|
use crate::ws::send_ws_msg;
|
||||||
|
use crate::{FieldId, Msg, PageChanged, UsersPageChange, WebSocketChanged};
|
||||||
|
|
||||||
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
if let Msg::ChangePage(Page::Users) = msg {
|
if let Msg::ChangePage(Page::Users) = msg {
|
||||||
@ -27,18 +27,50 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
page.user_role_state.update(&msg, orders);
|
page.user_role_state.update(&msg, orders);
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Msg::WsMsg(WsMsg::AuthorizeLoaded(Ok(_))) | Msg::ChangePage(Page::Users)
|
Msg::ChangePage(Page::Users) if model.user.is_some() => {
|
||||||
if model.user.is_some() =>
|
send_ws_msg(WsMsg::InvitationListRequest, model.ws.as_ref());
|
||||||
{
|
send_ws_msg(WsMsg::InvitedUsersRequest, model.ws.as_ref());
|
||||||
send_ws_msg(WsMsg::InvitationListRequest);
|
|
||||||
send_ws_msg(WsMsg::InvitedUsersRequest);
|
|
||||||
}
|
|
||||||
Msg::WsMsg(WsMsg::InvitedUsersLoaded(users)) => {
|
|
||||||
page.invited_users = users;
|
|
||||||
}
|
|
||||||
Msg::WsMsg(WsMsg::InvitationListLoaded(invitations)) => {
|
|
||||||
page.invitations = invitations;
|
|
||||||
}
|
}
|
||||||
|
Msg::WebSocketChange(change) => match change {
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::AuthorizeLoaded(Ok(_))) if model.user.is_some() => {
|
||||||
|
send_ws_msg(WsMsg::InvitationListRequest, model.ws.as_ref());
|
||||||
|
send_ws_msg(WsMsg::InvitedUsersRequest, model.ws.as_ref());
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitedUsersLoaded(users)) => {
|
||||||
|
page.invited_users = users;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitationListLoaded(invitations)) => {
|
||||||
|
page.invitations = invitations;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitationRevokeSuccess(id)) => {
|
||||||
|
let mut old = vec![];
|
||||||
|
std::mem::swap(&mut page.invitations, &mut old);
|
||||||
|
for mut invitation in old {
|
||||||
|
if id == invitation.id {
|
||||||
|
invitation.state = InvitationState::Revoked;
|
||||||
|
}
|
||||||
|
page.invitations.push(invitation);
|
||||||
|
}
|
||||||
|
send_ws_msg(WsMsg::InvitationListRequest, model.ws.as_ref());
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitedUserRemoveSuccess(email)) => {
|
||||||
|
let mut old = vec![];
|
||||||
|
std::mem::swap(&mut page.invited_users, &mut old);
|
||||||
|
for user in old {
|
||||||
|
if user.email != email {
|
||||||
|
page.invited_users.push(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitationSendSuccess) => {
|
||||||
|
send_ws_msg(WsMsg::InvitationListRequest, model.ws.as_ref());
|
||||||
|
page.form_state = InvitationFormState::Succeed;
|
||||||
|
}
|
||||||
|
WebSocketChanged::WsMsg(WsMsg::InvitationSendFailure) => {
|
||||||
|
page.form_state = InvitationFormState::Failed;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
Msg::PageChanged(PageChanged::Users(UsersPageChange::ResetForm)) => {
|
Msg::PageChanged(PageChanged::Users(UsersPageChange::ResetForm)) => {
|
||||||
page.name.clear();
|
page.name.clear();
|
||||||
page.name_touched = false;
|
page.name_touched = false;
|
||||||
@ -64,43 +96,22 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
}
|
}
|
||||||
Msg::InviteRequest => {
|
Msg::InviteRequest => {
|
||||||
page.form_state = InvitationFormState::Sent;
|
page.form_state = InvitationFormState::Sent;
|
||||||
send_ws_msg(WsMsg::InvitationSendRequest {
|
send_ws_msg(
|
||||||
name: page.name.clone(),
|
WsMsg::InvitationSendRequest {
|
||||||
email: page.email.clone(),
|
name: page.name.clone(),
|
||||||
})
|
email: page.email.clone(),
|
||||||
}
|
},
|
||||||
Msg::WsMsg(WsMsg::InvitationRevokeSuccess(id)) => {
|
model.ws.as_ref(),
|
||||||
let mut old = vec![];
|
);
|
||||||
std::mem::swap(&mut page.invitations, &mut old);
|
|
||||||
for mut invitation in old {
|
|
||||||
if id == invitation.id {
|
|
||||||
invitation.state = InvitationState::Revoked;
|
|
||||||
}
|
|
||||||
page.invitations.push(invitation);
|
|
||||||
}
|
|
||||||
send_ws_msg(WsMsg::InvitationListRequest);
|
|
||||||
}
|
}
|
||||||
Msg::InviteRevokeRequest(invitation_id) => {
|
Msg::InviteRevokeRequest(invitation_id) => {
|
||||||
send_ws_msg(WsMsg::InvitationRevokeRequest(invitation_id));
|
send_ws_msg(
|
||||||
|
WsMsg::InvitationRevokeRequest(invitation_id),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Msg::InvitedUserRemove(email) => {
|
Msg::InvitedUserRemove(email) => {
|
||||||
send_ws_msg(WsMsg::InvitedUserRemoveRequest(email));
|
send_ws_msg(WsMsg::InvitedUserRemoveRequest(email), model.ws.as_ref());
|
||||||
}
|
|
||||||
Msg::WsMsg(WsMsg::InvitedUserRemoveSuccess(email)) => {
|
|
||||||
let mut old = vec![];
|
|
||||||
std::mem::swap(&mut page.invited_users, &mut old);
|
|
||||||
for user in old {
|
|
||||||
if user.email != email {
|
|
||||||
page.invited_users.push(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Msg::WsMsg(WsMsg::InvitationSendSuccess) => {
|
|
||||||
send_ws_msg(WsMsg::InvitationListRequest);
|
|
||||||
page.form_state = InvitationFormState::Succeed;
|
|
||||||
}
|
|
||||||
Msg::WsMsg(WsMsg::InvitationSendFailure) => {
|
|
||||||
page.form_state = InvitationFormState::Failed;
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@ -210,8 +221,8 @@ pub fn view(model: &Model) -> Node<Msg> {
|
|||||||
.into_node();
|
.into_node();
|
||||||
li![
|
li![
|
||||||
class!["user"],
|
class!["user"],
|
||||||
span![user.name],
|
span![user.name.as_str()],
|
||||||
span![user.email],
|
span![user.email.as_str()],
|
||||||
span![format!("{}", user.user_role)],
|
span![format!("{}", user.user_role)],
|
||||||
remove,
|
remove,
|
||||||
]
|
]
|
||||||
@ -238,8 +249,8 @@ pub fn view(model: &Model) -> Node<Msg> {
|
|||||||
li![
|
li![
|
||||||
class!["invitation"],
|
class!["invitation"],
|
||||||
attrs![At::Class => format!("{}", invitation.state)],
|
attrs![At::Class => format!("{}", invitation.state)],
|
||||||
span![invitation.name],
|
span![invitation.name.as_str()],
|
||||||
span![invitation.email],
|
span![invitation.email.as_str()],
|
||||||
span![format!("{}", invitation.state)],
|
span![format!("{}", invitation.state)],
|
||||||
revoke,
|
revoke,
|
||||||
]
|
]
|
||||||
|
@ -2,8 +2,8 @@ use seed::*;
|
|||||||
|
|
||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
|
||||||
use crate::model::{Model, PageContent};
|
use crate::model::{Model, PageContent};
|
||||||
|
use crate::ws::send_ws_msg;
|
||||||
|
|
||||||
pub fn drag_started(issue_id: IssueId, model: &mut Model) {
|
pub fn drag_started(issue_id: IssueId, model: &mut Model) {
|
||||||
let project_page = match &mut model.page_content {
|
let project_page = match &mut model.page_content {
|
||||||
@ -90,16 +90,22 @@ pub fn sync(model: &mut Model) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
send_ws_msg(
|
||||||
issue.id,
|
WsMsg::IssueUpdateRequest(
|
||||||
IssueFieldId::IssueStatusId,
|
issue.id,
|
||||||
PayloadVariant::I32(issue.issue_status_id),
|
IssueFieldId::IssueStatusId,
|
||||||
));
|
PayloadVariant::I32(issue.issue_status_id),
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
),
|
||||||
issue.id,
|
model.ws.as_ref(),
|
||||||
IssueFieldId::ListPosition,
|
);
|
||||||
PayloadVariant::I32(issue.list_position),
|
send_ws_msg(
|
||||||
));
|
WsMsg::IssueUpdateRequest(
|
||||||
|
issue.id,
|
||||||
|
IssueFieldId::ListPosition,
|
||||||
|
PayloadVariant::I32(issue.list_position),
|
||||||
|
),
|
||||||
|
model.ws.as_ref(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
project_page.issue_drag.clear();
|
project_page.issue_drag.clear();
|
||||||
}
|
}
|
||||||
|
@ -4,57 +4,75 @@ use jirs_data::WsMsg;
|
|||||||
|
|
||||||
use crate::model::*;
|
use crate::model::*;
|
||||||
use crate::shared::write_auth_token;
|
use crate::shared::write_auth_token;
|
||||||
use crate::{Msg, APP};
|
use crate::{Msg, WebSocketChanged};
|
||||||
|
|
||||||
pub mod issue;
|
pub mod issue;
|
||||||
|
|
||||||
pub fn handle(msg: WsMsg) {
|
pub fn send_ws_msg(msg: WsMsg, ws: Option<&WebSocket>) {
|
||||||
let app = match unsafe { APP.as_mut().unwrap() }.write() {
|
let ws = match ws {
|
||||||
Ok(app) => app,
|
Some(ws) => ws,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
let binary = bincode::serialize(&msg).unwrap();
|
||||||
match msg {
|
ws.send_bytes(binary.as_slice())
|
||||||
WsMsg::Ping | WsMsg::Pong => {}
|
.expect("Failed to send ws msg");
|
||||||
_ => app.update(Msg::WsMsg(msg)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
pub fn open_socket(model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
|
if model.host_url.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let url = model.ws_url.as_str();
|
||||||
|
|
||||||
|
model.ws = WebSocket::builder(url, orders)
|
||||||
|
.on_message(|msg| Msg::WebSocketChange(WebSocketChanged::WebSocketMessage(msg)))
|
||||||
|
.on_open(|| Msg::WebSocketChange(WebSocketChanged::WebSocketOpened))
|
||||||
|
.on_close(|_| Msg::WebSocketChange(WebSocketChanged::WebSocketClosed))
|
||||||
|
.on_error(|| {})
|
||||||
|
.build_and_open()
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn read_incoming(msg: WebSocketMessage) -> Msg {
|
||||||
|
let bytes = msg.bytes().await.unwrap_or_default();
|
||||||
|
Msg::WebSocketChange(WebSocketChanged::WebSocketMessageLoaded(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(msg: &WsMsg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
match msg {
|
match msg {
|
||||||
// auth
|
// auth
|
||||||
Msg::WsMsg(WsMsg::AuthorizeLoaded(Ok(user))) => {
|
WsMsg::AuthorizeLoaded(Ok(user)) => {
|
||||||
model.user = Some(user.clone());
|
model.user = Some(user.clone());
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::AuthorizeExpired) => {
|
WsMsg::AuthorizeExpired => {
|
||||||
if let Ok(msg) = write_auth_token(None) {
|
if let Ok(msg) = write_auth_token(None) {
|
||||||
orders.skip().send_msg(msg);
|
orders.skip().send_msg(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// project
|
// project
|
||||||
Msg::WsMsg(WsMsg::ProjectLoaded(project)) => {
|
WsMsg::ProjectLoaded(project) => {
|
||||||
model.project = Some(project.clone());
|
model.project = Some(project.clone());
|
||||||
}
|
}
|
||||||
// issues
|
// issues
|
||||||
Msg::WsMsg(WsMsg::ProjectIssuesLoaded(v)) => {
|
WsMsg::ProjectIssuesLoaded(v) => {
|
||||||
let mut v = v.clone();
|
let mut v = v.clone();
|
||||||
v.sort_by(|a, b| (a.list_position as i64).cmp(&(b.list_position as i64)));
|
v.sort_by(|a, b| (a.list_position as i64).cmp(&(b.list_position as i64)));
|
||||||
model.issues = v;
|
model.issues = v;
|
||||||
}
|
}
|
||||||
// issue statuses
|
// issue statuses
|
||||||
Msg::WsMsg(WsMsg::IssueStatusesResponse(v)) => {
|
WsMsg::IssueStatusesResponse(v) => {
|
||||||
model.issue_statuses = v.clone();
|
model.issue_statuses = v.clone();
|
||||||
model
|
model
|
||||||
.issue_statuses
|
.issue_statuses
|
||||||
.sort_by(|a, b| a.position.cmp(&b.position));
|
.sort_by(|a, b| a.position.cmp(&b.position));
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::IssueStatusCreated(is)) => {
|
WsMsg::IssueStatusCreated(is) => {
|
||||||
model.issue_statuses.push(is.clone());
|
model.issue_statuses.push(is.clone());
|
||||||
model
|
model
|
||||||
.issue_statuses
|
.issue_statuses
|
||||||
.sort_by(|a, b| a.position.cmp(&b.position));
|
.sort_by(|a, b| a.position.cmp(&b.position));
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::IssueStatusUpdated(changed)) => {
|
WsMsg::IssueStatusUpdated(changed) => {
|
||||||
let mut old = vec![];
|
let mut old = vec![];
|
||||||
std::mem::swap(&mut model.issue_statuses, &mut old);
|
std::mem::swap(&mut model.issue_statuses, &mut old);
|
||||||
for is in old {
|
for is in old {
|
||||||
@ -68,7 +86,7 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
.issue_statuses
|
.issue_statuses
|
||||||
.sort_by(|a, b| a.position.cmp(&b.position));
|
.sort_by(|a, b| a.position.cmp(&b.position));
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::IssueDeleted(id)) => {
|
WsMsg::IssueDeleted(id) => {
|
||||||
let mut old = vec![];
|
let mut old = vec![];
|
||||||
std::mem::swap(&mut model.issue_statuses, &mut old);
|
std::mem::swap(&mut model.issue_statuses, &mut old);
|
||||||
for is in old {
|
for is in old {
|
||||||
@ -82,11 +100,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
.sort_by(|a, b| a.position.cmp(&b.position));
|
.sort_by(|a, b| a.position.cmp(&b.position));
|
||||||
}
|
}
|
||||||
// users
|
// users
|
||||||
Msg::WsMsg(WsMsg::ProjectUsersLoaded(v)) => {
|
WsMsg::ProjectUsersLoaded(v) => {
|
||||||
model.users = v.clone();
|
model.users = v.clone();
|
||||||
}
|
}
|
||||||
// comments
|
// comments
|
||||||
Msg::WsMsg(WsMsg::IssueCommentsLoaded(comments)) => {
|
WsMsg::IssueCommentsLoaded(comments) => {
|
||||||
let issue_id = match model.modals.get(0) {
|
let issue_id = match model.modals.get(0) {
|
||||||
Some(ModalType::EditIssue(issue_id, _)) => *issue_id,
|
Some(ModalType::EditIssue(issue_id, _)) => *issue_id,
|
||||||
_ => return,
|
_ => return,
|
||||||
@ -98,7 +116,7 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
v.sort_by(|a, b| a.updated_at.cmp(&b.updated_at));
|
v.sort_by(|a, b| a.updated_at.cmp(&b.updated_at));
|
||||||
model.comments = v;
|
model.comments = v;
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::CommentDeleted(comment_id)) => {
|
WsMsg::CommentDeleted(comment_id) => {
|
||||||
let mut old = vec![];
|
let mut old = vec![];
|
||||||
std::mem::swap(&mut model.comments, &mut old);
|
std::mem::swap(&mut model.comments, &mut old);
|
||||||
for comment in old.into_iter() {
|
for comment in old.into_iter() {
|
||||||
@ -107,7 +125,7 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::AvatarUrlChanged(user_id, avatar_url)) => {
|
WsMsg::AvatarUrlChanged(user_id, avatar_url) => {
|
||||||
for user in model.users.iter_mut() {
|
for user in model.users.iter_mut() {
|
||||||
if user.id == *user_id {
|
if user.id == *user_id {
|
||||||
user.avatar_url = Some(avatar_url.clone());
|
user.avatar_url = Some(avatar_url.clone());
|
||||||
|
@ -24,7 +24,7 @@ if (process.env.NODE_ENV === "production") {
|
|||||||
execSync('cargo build --bin jirs-css', {
|
execSync('cargo build --bin jirs-css', {
|
||||||
cwd: jirDir,
|
cwd: jirDir,
|
||||||
});
|
});
|
||||||
const css = spawn('./target/debug/jirs-css', [
|
spawn('./target/debug/jirs-css', [
|
||||||
'-W',
|
'-W',
|
||||||
'-O',
|
'-O',
|
||||||
'./jirs-client/dev/styles.css'
|
'./jirs-client/dev/styles.css'
|
||||||
@ -70,7 +70,7 @@ module.exports = {
|
|||||||
devServer: {
|
devServer: {
|
||||||
contentBase: path.join(__dirname, 'dev'),
|
contentBase: path.join(__dirname, 'dev'),
|
||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
hot: true,
|
hot: false,
|
||||||
port: process.env.JIRS_CLIENT_PORT || 6000,
|
port: process.env.JIRS_CLIENT_PORT || 6000,
|
||||||
host: process.env.JIRS_CLIENT_BIND || '0.0.0.0',
|
host: process.env.JIRS_CLIENT_BIND || '0.0.0.0',
|
||||||
allowedHosts: [
|
allowedHosts: [
|
||||||
|
@ -50,7 +50,6 @@ byteorder = "1.0"
|
|||||||
chrono = { version = "0.4", features = [ "serde" ] }
|
chrono = { version = "0.4", features = [ "serde" ] }
|
||||||
libc = { version = "0.2.0" }
|
libc = { version = "0.2.0" }
|
||||||
pq-sys = { version = ">=0.3.0, <0.5.0" }
|
pq-sys = { version = ">=0.3.0, <0.5.0" }
|
||||||
quickcheck = { version = "0.4" }
|
|
||||||
serde_json = { version = ">=0.8.0, <2.0" }
|
serde_json = { version = ">=0.8.0, <2.0" }
|
||||||
toml = "0.5.6"
|
toml = "0.5.6"
|
||||||
bincode = "1.2.1"
|
bincode = "1.2.1"
|
||||||
|
@ -153,53 +153,6 @@ table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table! {
|
|
||||||
use diesel::sql_types::*;
|
|
||||||
use jirs_data::sql::*;
|
|
||||||
|
|
||||||
/// Representation of the `issue_statuses` table.
|
|
||||||
///
|
|
||||||
/// (Automatically generated by Diesel.)
|
|
||||||
issue_statuses (id) {
|
|
||||||
/// The `id` column of the `issue_statuses` table.
|
|
||||||
///
|
|
||||||
/// Its SQL type is `Int4`.
|
|
||||||
///
|
|
||||||
/// (Automatically generated by Diesel.)
|
|
||||||
id -> Int4,
|
|
||||||
/// The `name` column of the `issue_statuses` table.
|
|
||||||
///
|
|
||||||
/// Its SQL type is `Varchar`.
|
|
||||||
///
|
|
||||||
/// (Automatically generated by Diesel.)
|
|
||||||
name -> Varchar,
|
|
||||||
/// The `position` column of the `issue_statuses` table.
|
|
||||||
///
|
|
||||||
/// Its SQL type is `Int4`.
|
|
||||||
///
|
|
||||||
/// (Automatically generated by Diesel.)
|
|
||||||
position -> Int4,
|
|
||||||
/// The `project_id` column of the `issue_statuses` table.
|
|
||||||
///
|
|
||||||
/// Its SQL type is `Int4`.
|
|
||||||
///
|
|
||||||
/// (Automatically generated by Diesel.)
|
|
||||||
project_id -> Int4,
|
|
||||||
/// The `created_at` column of the `issue_statuses` table.
|
|
||||||
///
|
|
||||||
/// Its SQL type is `Timestamp`.
|
|
||||||
///
|
|
||||||
/// (Automatically generated by Diesel.)
|
|
||||||
created_at -> Timestamp,
|
|
||||||
/// The `updated_at` column of the `issue_statuses` table.
|
|
||||||
///
|
|
||||||
/// Its SQL type is `Timestamp`.
|
|
||||||
///
|
|
||||||
/// (Automatically generated by Diesel.)
|
|
||||||
updated_at -> Timestamp,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
use jirs_data::sql::*;
|
use jirs_data::sql::*;
|
||||||
@ -301,6 +254,53 @@ table! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table! {
|
||||||
|
use diesel::sql_types::*;
|
||||||
|
use jirs_data::sql::*;
|
||||||
|
|
||||||
|
/// Representation of the `issue_statuses` table.
|
||||||
|
///
|
||||||
|
/// (Automatically generated by Diesel.)
|
||||||
|
issue_statuses (id) {
|
||||||
|
/// The `id` column of the `issue_statuses` table.
|
||||||
|
///
|
||||||
|
/// Its SQL type is `Int4`.
|
||||||
|
///
|
||||||
|
/// (Automatically generated by Diesel.)
|
||||||
|
id -> Int4,
|
||||||
|
/// The `name` column of the `issue_statuses` table.
|
||||||
|
///
|
||||||
|
/// Its SQL type is `Varchar`.
|
||||||
|
///
|
||||||
|
/// (Automatically generated by Diesel.)
|
||||||
|
name -> Varchar,
|
||||||
|
/// The `position` column of the `issue_statuses` table.
|
||||||
|
///
|
||||||
|
/// Its SQL type is `Int4`.
|
||||||
|
///
|
||||||
|
/// (Automatically generated by Diesel.)
|
||||||
|
position -> Int4,
|
||||||
|
/// The `project_id` column of the `issue_statuses` table.
|
||||||
|
///
|
||||||
|
/// Its SQL type is `Int4`.
|
||||||
|
///
|
||||||
|
/// (Automatically generated by Diesel.)
|
||||||
|
project_id -> Int4,
|
||||||
|
/// The `created_at` column of the `issue_statuses` table.
|
||||||
|
///
|
||||||
|
/// Its SQL type is `Timestamp`.
|
||||||
|
///
|
||||||
|
/// (Automatically generated by Diesel.)
|
||||||
|
created_at -> Timestamp,
|
||||||
|
/// The `updated_at` column of the `issue_statuses` table.
|
||||||
|
///
|
||||||
|
/// Its SQL type is `Timestamp`.
|
||||||
|
///
|
||||||
|
/// (Automatically generated by Diesel.)
|
||||||
|
updated_at -> Timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table! {
|
table! {
|
||||||
use diesel::sql_types::*;
|
use diesel::sql_types::*;
|
||||||
use jirs_data::sql::*;
|
use jirs_data::sql::*;
|
||||||
@ -489,8 +489,8 @@ allow_tables_to_appear_in_same_query!(
|
|||||||
comments,
|
comments,
|
||||||
invitations,
|
invitations,
|
||||||
issue_assignees,
|
issue_assignees,
|
||||||
issue_statuses,
|
|
||||||
issues,
|
issues,
|
||||||
|
issue_statuses,
|
||||||
projects,
|
projects,
|
||||||
tokens,
|
tokens,
|
||||||
users,
|
users,
|
||||||
|
Loading…
Reference in New Issue
Block a user