mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-19 18:17:58 +01:00
Compare commits
14 Commits
v2024.3.7
...
v2024.3.10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a58f73aa4 | ||
|
|
bd17650799 | ||
|
|
db6a7dcabb | ||
|
|
00b1f90074 | ||
|
|
e292235792 | ||
|
|
5f86802d88 | ||
|
|
acb7f2e49b | ||
|
|
e2a15609bf | ||
|
|
aa3bfd78c4 | ||
|
|
23c4971127 | ||
|
|
40669217fb | ||
|
|
8089ea87e8 | ||
|
|
9de24e3a40 | ||
|
|
5afb8e7383 |
@@ -37,10 +37,11 @@ export function pluginHookImport(contents: string): { resources: ExportResources
|
||||
id: generateId('wk'),
|
||||
name: info.name || 'Postman Import',
|
||||
description: info.description || '',
|
||||
variables: root.variable?.map((v: any) => ({
|
||||
name: v.key,
|
||||
value: v.value,
|
||||
})),
|
||||
variables:
|
||||
root.variable?.map((v: any) => ({
|
||||
name: v.key,
|
||||
value: v.value,
|
||||
})) ?? [],
|
||||
};
|
||||
exportResources.workspaces.push(workspace);
|
||||
|
||||
@@ -190,6 +191,20 @@ function importBody(rawBody: any): Pick<HttpRequest, 'body' | 'bodyType' | 'head
|
||||
),
|
||||
},
|
||||
};
|
||||
} else if ('raw' in body) {
|
||||
return {
|
||||
headers: [
|
||||
{
|
||||
name: 'Content-Type',
|
||||
value: body.options?.raw?.language === 'json' ? 'application/json' : '',
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
bodyType: body.options?.raw?.language === 'json' ? 'application/json' : 'other',
|
||||
body: {
|
||||
text: body.raw ?? '',
|
||||
},
|
||||
};
|
||||
} else {
|
||||
// TODO: support other body types
|
||||
return { headers: [], bodyType: null, body: {} };
|
||||
|
||||
80
src-tauri/Cargo.lock
generated
80
src-tauri/Cargo.lock
generated
@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.6"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom 0.2.11",
|
||||
@@ -161,16 +161,6 @@ dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-write-file"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
@@ -249,6 +239,12 @@ version = "0.21.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
@@ -2654,17 +2650,6 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.27.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nodrop"
|
||||
version = "0.1.14"
|
||||
@@ -4314,9 +4299,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
|
||||
checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa"
|
||||
dependencies = [
|
||||
"sqlx-core",
|
||||
"sqlx-macros",
|
||||
@@ -4327,9 +4312,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-core"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
|
||||
checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"atoi",
|
||||
@@ -4338,7 +4323,6 @@ dependencies = [
|
||||
"chrono",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"dotenvy",
|
||||
"either",
|
||||
"event-listener",
|
||||
"futures-channel",
|
||||
@@ -4372,9 +4356,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-macros"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
|
||||
checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4385,11 +4369,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-macros-core"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
|
||||
checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8"
|
||||
dependencies = [
|
||||
"atomic-write-file",
|
||||
"dotenvy",
|
||||
"either",
|
||||
"heck 0.4.1",
|
||||
@@ -4412,9 +4395,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-mysql"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
|
||||
checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.5",
|
||||
@@ -4456,9 +4439,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-postgres"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
|
||||
checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64 0.21.5",
|
||||
@@ -4484,7 +4467,6 @@ dependencies = [
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"smallvec",
|
||||
"sqlx-core",
|
||||
@@ -4497,9 +4479,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-sqlite"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
|
||||
checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"chrono",
|
||||
@@ -5123,9 +5105,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.34.0"
|
||||
version = "1.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9"
|
||||
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -5181,9 +5163,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.14"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
|
||||
checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
@@ -6332,7 +6314,7 @@ dependencies = [
|
||||
name = "yaak-app"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"base64 0.21.5",
|
||||
"base64 0.22.0",
|
||||
"boa_engine",
|
||||
"boa_runtime",
|
||||
"chrono",
|
||||
@@ -6387,18 +6369,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.25"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cd369a67c0edfef15010f980c3cbe45d7f651deac2cd67ce097cd801de16557"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.25"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2f140bda219a26ccc0cdb03dba58af72590c53b22642577d88a927bc5c87d6b"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -22,7 +22,7 @@ cocoa = "0.25.0"
|
||||
openssl-sys = { version = "0.9", features = ["vendored"] } # For Ubuntu installation to work
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.21.0"
|
||||
base64 = "0.22.0"
|
||||
boa_engine = { version = "0.17.3", features = ["annex-b"] }
|
||||
boa_runtime = { version = "0.17.3" }
|
||||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
@@ -33,7 +33,7 @@ reqwest = { version = "0.11.23", features = ["multipart", "cookies", "gzip", "br
|
||||
cookie = { version = "0.18.0" }
|
||||
serde = { version = "1.0.195", features = ["derive"] }
|
||||
serde_json = { version = "1.0.111", features = ["raw_value"] }
|
||||
sqlx = { version = "0.7.3", features = ["sqlite", "runtime-tokio-rustls", "json", "chrono", "time"] }
|
||||
sqlx = { version = "0.7.4", features = ["sqlite", "runtime-tokio-rustls", "json", "chrono", "time"] }
|
||||
tauri = { version = "1.5.4", features = [
|
||||
"config-toml",
|
||||
"path-all",
|
||||
@@ -56,14 +56,14 @@ tauri = { version = "1.5.4", features = [
|
||||
] }
|
||||
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
|
||||
tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1", features = ["colored"] }
|
||||
tokio = { version = "1.25.0", features = ["sync"] }
|
||||
tokio = { version = "1.36.0", features = ["sync"] }
|
||||
uuid = "1.3.0"
|
||||
log = "0.4.20"
|
||||
datetime = "0.5.2"
|
||||
window-shadows = "0.2.2"
|
||||
reqwest_cookie_store = "0.6.0"
|
||||
grpc = { path = "./grpc" }
|
||||
tokio-stream = "0.1.14"
|
||||
tokio-stream = "0.1.15"
|
||||
|
||||
[features]
|
||||
# by default Tauri runs in production mode
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
const q = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", S = "https://schema.getpostman.com/json/collection/v2.0.0/collection.json", _ = [S, q];
|
||||
function v(t) {
|
||||
var b;
|
||||
const e = w(t);
|
||||
function j(t) {
|
||||
var g;
|
||||
const e = A(t);
|
||||
if (e == null)
|
||||
return;
|
||||
const n = o(e.info);
|
||||
if (!_.includes(n.schema) || !Array.isArray(e.item))
|
||||
const a = l(e.info);
|
||||
if (!_.includes(a.schema) || !Array.isArray(e.item))
|
||||
return;
|
||||
const A = g(e.auth), i = {
|
||||
const c = w(e.auth), s = {
|
||||
workspaces: [],
|
||||
environments: [],
|
||||
httpRequests: [],
|
||||
folders: []
|
||||
}, c = {
|
||||
}, n = {
|
||||
model: "workspace",
|
||||
id: m("wk"),
|
||||
name: n.name || "Postman Import",
|
||||
description: n.description || "",
|
||||
variables: (b = e.variable) == null ? void 0 : b.map((r) => ({
|
||||
id: y("wk"),
|
||||
name: a.name || "Postman Import",
|
||||
description: a.description || "",
|
||||
variables: ((g = e.variable) == null ? void 0 : g.map((r) => ({
|
||||
name: r.key,
|
||||
value: r.value
|
||||
}))
|
||||
}))) ?? []
|
||||
};
|
||||
i.workspaces.push(c);
|
||||
const f = (r, u = null) => {
|
||||
s.workspaces.push(n);
|
||||
const f = (r, d = null) => {
|
||||
if (typeof r.name == "string" && Array.isArray(r.item)) {
|
||||
const a = {
|
||||
const o = {
|
||||
model: "folder",
|
||||
workspaceId: c.id,
|
||||
id: m("fl"),
|
||||
workspaceId: n.id,
|
||||
id: y("fl"),
|
||||
name: r.name,
|
||||
folderId: u
|
||||
folderId: d
|
||||
};
|
||||
i.folders.push(a);
|
||||
for (const s of r.item)
|
||||
f(s, a.id);
|
||||
s.folders.push(o);
|
||||
for (const u of r.item)
|
||||
f(u, o.id);
|
||||
} else if (typeof r.name == "string" && "request" in r) {
|
||||
const a = o(r.request), s = O(a.body), T = g(a.auth), d = T.authenticationType == null ? A : T, k = {
|
||||
const o = l(r.request), u = O(o.body), T = w(o.auth), p = T.authenticationType == null ? c : T, k = {
|
||||
model: "http_request",
|
||||
id: m("rq"),
|
||||
workspaceId: c.id,
|
||||
folderId: u,
|
||||
id: y("rq"),
|
||||
workspaceId: n.id,
|
||||
folderId: d,
|
||||
name: r.name,
|
||||
method: a.method || "GET",
|
||||
url: typeof a.url == "string" ? a.url : o(a.url).raw,
|
||||
body: s.body,
|
||||
bodyType: s.bodyType,
|
||||
authentication: d.authentication,
|
||||
authenticationType: d.authenticationType,
|
||||
method: o.method || "GET",
|
||||
url: typeof o.url == "string" ? o.url : l(o.url).raw,
|
||||
body: u.body,
|
||||
bodyType: u.bodyType,
|
||||
authentication: p.authentication,
|
||||
authenticationType: p.authenticationType,
|
||||
headers: [
|
||||
...s.headers,
|
||||
...d.headers,
|
||||
...y(a.header).map((p) => ({
|
||||
name: p.key,
|
||||
value: p.value,
|
||||
enabled: !p.disabled
|
||||
...u.headers,
|
||||
...p.headers,
|
||||
...h(o.header).map((m) => ({
|
||||
name: m.key,
|
||||
value: m.value,
|
||||
enabled: !m.disabled
|
||||
}))
|
||||
]
|
||||
};
|
||||
i.httpRequests.push(k);
|
||||
s.httpRequests.push(k);
|
||||
} else
|
||||
console.log("Unknown item", r, u);
|
||||
console.log("Unknown item", r, d);
|
||||
};
|
||||
for (const r of e.item)
|
||||
f(r);
|
||||
return { resources: h(i) };
|
||||
return { resources: b(s) };
|
||||
}
|
||||
function g(t) {
|
||||
const e = o(t);
|
||||
function w(t) {
|
||||
const e = l(t);
|
||||
return "basic" in e ? {
|
||||
headers: [],
|
||||
authenticationType: "basic",
|
||||
@@ -84,7 +84,8 @@ function g(t) {
|
||||
} : { headers: [], authenticationType: null, authentication: {} };
|
||||
}
|
||||
function O(t) {
|
||||
const e = o(t);
|
||||
var a, i, c, s;
|
||||
const e = l(t);
|
||||
return "graphql" in e ? {
|
||||
headers: [
|
||||
{
|
||||
@@ -96,7 +97,7 @@ function O(t) {
|
||||
bodyType: "graphql",
|
||||
body: {
|
||||
text: JSON.stringify(
|
||||
{ query: e.graphql.query, variables: w(e.graphql.variables) },
|
||||
{ query: e.graphql.query, variables: A(e.graphql.variables) },
|
||||
null,
|
||||
2
|
||||
)
|
||||
@@ -111,7 +112,7 @@ function O(t) {
|
||||
],
|
||||
bodyType: "application/x-www-form-urlencoded",
|
||||
body: {
|
||||
form: y(e.urlencoded).map((n) => ({
|
||||
form: h(e.urlencoded).map((n) => ({
|
||||
enabled: !n.disabled,
|
||||
name: n.key ?? "",
|
||||
value: n.value ?? ""
|
||||
@@ -127,7 +128,7 @@ function O(t) {
|
||||
],
|
||||
bodyType: "multipart/form-data",
|
||||
body: {
|
||||
form: y(e.formdata).map(
|
||||
form: h(e.formdata).map(
|
||||
(n) => n.src != null ? {
|
||||
enabled: !n.disabled,
|
||||
name: n.key ?? "",
|
||||
@@ -139,34 +140,46 @@ function O(t) {
|
||||
}
|
||||
)
|
||||
}
|
||||
} : "raw" in e ? {
|
||||
headers: [
|
||||
{
|
||||
name: "Content-Type",
|
||||
value: ((i = (a = e.options) == null ? void 0 : a.raw) == null ? void 0 : i.language) === "json" ? "application/json" : "",
|
||||
enabled: !0
|
||||
}
|
||||
],
|
||||
bodyType: ((s = (c = e.options) == null ? void 0 : c.raw) == null ? void 0 : s.language) === "json" ? "application/json" : "other",
|
||||
body: {
|
||||
text: e.raw ?? ""
|
||||
}
|
||||
} : { headers: [], bodyType: null, body: {} };
|
||||
}
|
||||
function w(t) {
|
||||
function A(t) {
|
||||
try {
|
||||
return o(JSON.parse(t));
|
||||
return l(JSON.parse(t));
|
||||
} catch {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function o(t) {
|
||||
function l(t) {
|
||||
return Object.prototype.toString.call(t) === "[object Object]" ? t : {};
|
||||
}
|
||||
function y(t) {
|
||||
function h(t) {
|
||||
return Object.prototype.toString.call(t) === "[object Array]" ? t : [];
|
||||
}
|
||||
function h(t) {
|
||||
return typeof t == "string" ? t.replace(/{{\s*(_\.)?([^}]+)\s*}}/g, "${[$2]}") : Array.isArray(t) && t != null ? t.map(h) : typeof t == "object" && t != null ? Object.fromEntries(
|
||||
Object.entries(t).map(([e, n]) => [e, h(n)])
|
||||
function b(t) {
|
||||
return typeof t == "string" ? t.replace(/{{\s*(_\.)?([^}]+)\s*}}/g, "${[$2]}") : Array.isArray(t) && t != null ? t.map(b) : typeof t == "object" && t != null ? Object.fromEntries(
|
||||
Object.entries(t).map(([e, a]) => [e, b(a)])
|
||||
) : t;
|
||||
}
|
||||
function m(t) {
|
||||
function y(t) {
|
||||
const e = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
let n = `${t}_`;
|
||||
for (let l = 0; l < 10; l++)
|
||||
n += e[Math.floor(Math.random() * e.length)];
|
||||
return n;
|
||||
let a = `${t}_`;
|
||||
for (let i = 0; i < 10; i++)
|
||||
a += e[Math.floor(Math.random() * e.length)];
|
||||
return a;
|
||||
}
|
||||
export {
|
||||
m as generateId,
|
||||
v as pluginHookImport
|
||||
y as generateId,
|
||||
j as pluginHookImport
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ use log::{debug, error, info, warn};
|
||||
use rand::random;
|
||||
use serde_json::{json, Value};
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::sqlite::{SqliteConnectOptions};
|
||||
use sqlx::types::Json;
|
||||
use sqlx::{Pool, Sqlite, SqlitePool};
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -749,7 +750,7 @@ async fn cmd_import_data(
|
||||
let mut imported_resources = WorkspaceExportResources::default();
|
||||
|
||||
info!("Importing resources");
|
||||
for mut v in r.resources.workspaces {
|
||||
for v in r.resources.workspaces {
|
||||
let x = upsert_workspace(&w, v).await.map_err(|e| e.to_string())?;
|
||||
imported_resources.workspaces.push(x.clone());
|
||||
info!("Imported workspace: {}", x.name);
|
||||
@@ -1430,7 +1431,8 @@ fn main() {
|
||||
|
||||
// Add DB handle
|
||||
tauri::async_runtime::block_on(async move {
|
||||
let pool = SqlitePool::connect(p.to_str().unwrap())
|
||||
let opts = SqliteConnectOptions::from_str(p.to_str().unwrap()).unwrap();
|
||||
let pool = SqlitePool::connect_with(opts)
|
||||
.await
|
||||
.expect("Failed to connect to database");
|
||||
let m = Mutex::new(pool.clone());
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"package": {
|
||||
"productName": "Yaak",
|
||||
"version": "2024.3.7"
|
||||
"version": "2024.3.10"
|
||||
},
|
||||
"tauri": {
|
||||
"windows": [],
|
||||
|
||||
@@ -13,7 +13,7 @@ export function BasicAuth<T extends HttpRequest | GrpcRequest>({ request }: Prop
|
||||
const updateGrpcRequest = useUpdateGrpcRequest(request.id);
|
||||
|
||||
return (
|
||||
<VStack className="my-2" space={2}>
|
||||
<VStack className="py-2 overflow-y-auto h-full" space={2}>
|
||||
<Input
|
||||
useTemplating
|
||||
autocompleteVariables
|
||||
|
||||
@@ -15,6 +15,7 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
const workspaces = useWorkspaces();
|
||||
const requests = useRequests();
|
||||
const [command, setCommand] = useState<string>('');
|
||||
|
||||
const items = useMemo<{ label: string; onSelect: () => void; key: string }[]>(() => {
|
||||
const items = [];
|
||||
@@ -47,10 +48,17 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
return items;
|
||||
}, [activeEnvironmentId, requests, routes, workspaces]);
|
||||
|
||||
const handleSelectAndClose = (cb: () => void) => {
|
||||
onClose();
|
||||
cb();
|
||||
};
|
||||
const filteredItems = useMemo(() => {
|
||||
return items.filter((v) => v.label.toLowerCase().includes(command.toLowerCase()));
|
||||
}, [command, items]);
|
||||
|
||||
const handleSelectAndClose = useCallback(
|
||||
(cb: () => void) => {
|
||||
onClose();
|
||||
cb();
|
||||
},
|
||||
[onClose],
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: KeyboardEvent) => {
|
||||
@@ -59,13 +67,13 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
setSelectedIndex((prev) => prev - 1);
|
||||
} else if (e.key === 'Enter') {
|
||||
const item = items[selectedIndex];
|
||||
const item = filteredItems[selectedIndex];
|
||||
if (item) {
|
||||
handleSelectAndClose(item.onSelect);
|
||||
}
|
||||
}
|
||||
},
|
||||
[items, onClose, selectedIndex],
|
||||
[filteredItems, handleSelectAndClose, selectedIndex],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -76,11 +84,13 @@ export function CommandPalette({ onClose }: { onClose: () => void }) {
|
||||
name="command"
|
||||
label="Command"
|
||||
placeholder="Type a command"
|
||||
defaultValue=""
|
||||
onChange={setCommand}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
</div>
|
||||
<div className="h-full px-1.5 overflow-y-auto">
|
||||
{items.map((v, i) => (
|
||||
{filteredItems.map((v, i) => (
|
||||
<CommandPaletteItem
|
||||
active={i === selectedIndex}
|
||||
key={v.key}
|
||||
|
||||
@@ -5,14 +5,9 @@ import { Dropdown } from './core/Dropdown';
|
||||
interface Props {
|
||||
hideFolder?: boolean;
|
||||
children: DropdownProps['children'];
|
||||
openOnHotKeyAction?: DropdownProps['openOnHotKeyAction'];
|
||||
}
|
||||
|
||||
export function CreateDropdown({ hideFolder, children, openOnHotKeyAction }: Props) {
|
||||
export function CreateDropdown({ hideFolder, children }: Props) {
|
||||
const items = useCreateDropdownItems({ hideFolder, hideIcons: true });
|
||||
return (
|
||||
<Dropdown openOnHotKeyAction={openOnHotKeyAction} items={items}>
|
||||
{children}
|
||||
</Dropdown>
|
||||
);
|
||||
return <Dropdown items={items}>{children}</Dropdown>;
|
||||
}
|
||||
|
||||
@@ -41,10 +41,6 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
||||
dropdownRef.current?.prev?.();
|
||||
});
|
||||
|
||||
useHotKey('request_switcher.toggle', () => {
|
||||
dropdownRef.current?.toggle();
|
||||
});
|
||||
|
||||
const items = useMemo<DropdownItem[]>(() => {
|
||||
if (activeWorkspaceId === null) return [];
|
||||
|
||||
@@ -87,6 +83,7 @@ export function RecentRequestsDropdown({ className }: Pick<ButtonProps, 'classNa
|
||||
<Button
|
||||
data-tauri-drag-region
|
||||
size="sm"
|
||||
hotkeyAction="request_switcher.toggle"
|
||||
className={classNames(
|
||||
className,
|
||||
'text-gray-800 text-sm truncate pointer-events-auto',
|
||||
|
||||
@@ -346,7 +346,7 @@ export const RequestPane = memo(function RequestPane({
|
||||
onChangeContentType={handleContentTypeChange}
|
||||
/>
|
||||
) : (
|
||||
<EmptyStateText>No Body</EmptyStateText>
|
||||
<EmptyStateText>Empty Body</EmptyStateText>
|
||||
)}
|
||||
</TabContent>
|
||||
</Tabs>
|
||||
|
||||
@@ -56,7 +56,7 @@ interface TreeNode {
|
||||
}
|
||||
|
||||
export function Sidebar({ className }: Props) {
|
||||
const { hidden, show, hide } = useSidebarHidden();
|
||||
const [hidden, setHidden] = useSidebarHidden();
|
||||
const sidebarRef = useRef<HTMLLIElement>(null);
|
||||
const activeRequest = useActiveRequest();
|
||||
const activeEnvironmentId = useActiveEnvironmentId();
|
||||
@@ -241,16 +241,15 @@ export function Sidebar({ className }: Props) {
|
||||
useKeyPressEvent('Delete', handleDeleteKey);
|
||||
|
||||
useHotKey('sidebar.focus', async () => {
|
||||
console.log('sidebar.focus', { hidden, hasFocus });
|
||||
// Hide the sidebar if it's already focused
|
||||
if (!hidden && hasFocus) {
|
||||
await hide();
|
||||
await setHidden(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show the sidebar if it's hidden
|
||||
if (hidden) {
|
||||
await show();
|
||||
await setHidden(false);
|
||||
}
|
||||
|
||||
// Select 0 index on focus if none selected
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
import { memo } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
||||
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
|
||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||
import { trackEvent } from '../lib/analytics';
|
||||
import { IconButton } from './core/IconButton';
|
||||
import { HStack } from './core/Stacks';
|
||||
import { CreateDropdown } from './CreateDropdown';
|
||||
|
||||
export const SidebarActions = memo(function SidebarActions() {
|
||||
const { hidden, show, hide } = useSidebarHidden();
|
||||
export function SidebarActions() {
|
||||
const floating = useShouldFloatSidebar();
|
||||
const [normalHidden, setNormalHidden] = useSidebarHidden();
|
||||
const [floatingHidden, setFloatingHidden] = useFloatingSidebarHidden();
|
||||
|
||||
const hidden = floating ? floatingHidden : normalHidden;
|
||||
const setHidden = useMemo(
|
||||
() => (floating ? setFloatingHidden : setNormalHidden),
|
||||
[floating, setFloatingHidden, setNormalHidden],
|
||||
);
|
||||
|
||||
return (
|
||||
<HStack className="h-full" alignItems="center">
|
||||
@@ -14,10 +24,9 @@ export const SidebarActions = memo(function SidebarActions() {
|
||||
onClick={async () => {
|
||||
trackEvent('sidebar', 'toggle');
|
||||
|
||||
// NOTE: We're not using `toggle` because it may be out of sync
|
||||
// from changes in other windows
|
||||
if (hidden) await show();
|
||||
else await hide();
|
||||
// NOTE: We're not using the (h) => !h pattern here because the data
|
||||
// might be different if another window changed it (out of sync)
|
||||
await setHidden(!hidden);
|
||||
}}
|
||||
className="pointer-events-auto"
|
||||
size="sm"
|
||||
@@ -25,9 +34,14 @@ export const SidebarActions = memo(function SidebarActions() {
|
||||
hotkeyAction="sidebar.toggle"
|
||||
icon={hidden ? 'leftPanelHidden' : 'leftPanelVisible'}
|
||||
/>
|
||||
<CreateDropdown openOnHotKeyAction="http_request.create">
|
||||
<IconButton size="sm" icon="plusCircle" title="Add Resource" />
|
||||
<CreateDropdown>
|
||||
<IconButton
|
||||
size="sm"
|
||||
icon="plusCircle"
|
||||
title="Add Resource"
|
||||
hotkeyAction="http_request.create"
|
||||
/>
|
||||
</CreateDropdown>
|
||||
</HStack>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ export const UrlBar = memo(function UrlBar({
|
||||
hideLabel
|
||||
useTemplating
|
||||
contentType="url"
|
||||
className="px-0 py-0.5"
|
||||
className="pl-0 pr-1.5 py-0.5"
|
||||
name="url"
|
||||
label="Enter URL"
|
||||
forceUpdateKey={forceUpdateKey}
|
||||
@@ -76,7 +76,7 @@ export const UrlBar = memo(function UrlBar({
|
||||
<RequestMethodDropdown
|
||||
method={method}
|
||||
onChange={onMethodChange}
|
||||
className="!h-auto my-0.5 ml-0.5"
|
||||
className="my-0.5 ml-0.5"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ export const UrlBar = memo(function UrlBar({
|
||||
iconSize="md"
|
||||
title="Send Request"
|
||||
type="submit"
|
||||
className="w-8 !h-auto my-0.5 mr-0.5"
|
||||
className="w-8 my-0.5 mr-0.5"
|
||||
icon={isLoading ? 'x' : submitIcon}
|
||||
hotkeyAction="http_request.send"
|
||||
/>
|
||||
|
||||
@@ -6,14 +6,16 @@ import type {
|
||||
MouseEvent as ReactMouseEvent,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useWindowSize } from 'react-use';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useActiveWorkspaceId } from '../hooks/useActiveWorkspaceId';
|
||||
import { useFloatingSidebarHidden } from '../hooks/useFloatingSidebarHidden';
|
||||
import { useImportData } from '../hooks/useImportData';
|
||||
import { useIsFullscreen } from '../hooks/useIsFullscreen';
|
||||
import { useOsInfo } from '../hooks/useOsInfo';
|
||||
import { useShouldFloatSidebar } from '../hooks/useShouldFloatSidebar';
|
||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||
import { useSidebarWidth } from '../hooks/useSidebarWidth';
|
||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||
@@ -37,34 +39,22 @@ const head = { gridArea: 'head' };
|
||||
const body = { gridArea: 'body' };
|
||||
const drag = { gridArea: 'drag' };
|
||||
|
||||
const WINDOW_FLOATING_SIDEBAR_WIDTH = 600;
|
||||
|
||||
export default function Workspace() {
|
||||
const workspaces = useWorkspaces();
|
||||
const activeWorkspace = useActiveWorkspace();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const { setWidth, width, resetWidth } = useSidebarWidth();
|
||||
const { hide, show, hidden } = useSidebarHidden();
|
||||
const [sidebarHidden, setSidebarHidden] = useSidebarHidden();
|
||||
const [floatingSidebarHidden, setFloatingSidebarHidden] = useFloatingSidebarHidden();
|
||||
const activeRequest = useActiveRequest();
|
||||
const windowSize = useWindowSize();
|
||||
const importData = useImportData();
|
||||
const [floating, setFloating] = useState<boolean>(false);
|
||||
const floating = useShouldFloatSidebar();
|
||||
const [isResizing, setIsResizing] = useState<boolean>(false);
|
||||
const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void } | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
// float/un-float sidebar on window resize
|
||||
useEffect(() => {
|
||||
const shouldHide = windowSize.width <= WINDOW_FLOATING_SIDEBAR_WIDTH;
|
||||
if (shouldHide && !floating) {
|
||||
setFloating(true);
|
||||
hide().catch(console.error);
|
||||
} else if (!shouldHide && floating) {
|
||||
setFloating(false);
|
||||
}
|
||||
}, [floating, hide, windowSize.width]);
|
||||
|
||||
const unsub = () => {
|
||||
if (moveState.current !== null) {
|
||||
document.documentElement.removeEventListener('mousemove', moveState.current.move);
|
||||
@@ -84,10 +74,10 @@ export default function Workspace() {
|
||||
e.preventDefault(); // Prevent text selection and things
|
||||
const newWidth = startWidth + (e.clientX - mouseStartX);
|
||||
if (newWidth < 50) {
|
||||
await hide();
|
||||
await setSidebarHidden(true);
|
||||
resetWidth();
|
||||
} else {
|
||||
await show();
|
||||
await setSidebarHidden(false);
|
||||
setWidth(newWidth);
|
||||
}
|
||||
},
|
||||
@@ -101,10 +91,10 @@ export default function Workspace() {
|
||||
document.documentElement.addEventListener('mouseup', moveState.current.up);
|
||||
setIsResizing(true);
|
||||
},
|
||||
[setWidth, resetWidth, width, hide, show],
|
||||
[width, setSidebarHidden, resetWidth, setWidth],
|
||||
);
|
||||
|
||||
const sideWidth = hidden ? 0 : width;
|
||||
const sideWidth = sidebarHidden ? 0 : width;
|
||||
const styles = useMemo<CSSProperties>(
|
||||
() => ({
|
||||
gridTemplate: floating
|
||||
@@ -144,7 +134,11 @@ export default function Workspace() {
|
||||
)}
|
||||
>
|
||||
{floating ? (
|
||||
<Overlay open={!hidden} portalName="sidebar" onClose={hide}>
|
||||
<Overlay
|
||||
open={!floatingSidebarHidden}
|
||||
portalName="sidebar"
|
||||
onClose={() => setFloatingSidebarHidden(true)}
|
||||
>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, x: -20 }}
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
|
||||
@@ -16,7 +16,7 @@ export function Banner({ children, className, color = 'gray' }: Props) {
|
||||
color === 'gray' && 'border-gray-500/60 bg-gray-300/10 text-gray-800',
|
||||
color === 'warning' && 'border-orange-500/60 bg-orange-300/10 text-orange-800',
|
||||
color === 'danger' && 'border-red-500/60 bg-red-300/10 text-red-800',
|
||||
color === 'success' && 'border-green-500/60 bg-green-300/10 text-green-800',
|
||||
color === 'success' && 'border-violet-500/60 bg-violet-300/10 text-violet-800',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -34,8 +34,8 @@ export function Checkbox({
|
||||
<input
|
||||
aria-hidden
|
||||
className={classNames(
|
||||
'opacity-50 appearance-none w-4 h-4 flex-shrink-0 border border-[currentColor]',
|
||||
'rounded hocus:border-focus hocus:bg-focus/[5%] hocus:opacity-100 outline-none ring-0',
|
||||
'appearance-none w-4 h-4 flex-shrink-0 border border-highlight',
|
||||
'rounded hocus:border-focus hocus:bg-focus/[5%] outline-none ring-0',
|
||||
)}
|
||||
type="checkbox"
|
||||
disabled={disabled}
|
||||
|
||||
@@ -62,7 +62,7 @@ export function Dialog({
|
||||
animate={{ top: 0, scale: 1 }}
|
||||
className={classNames(
|
||||
className,
|
||||
'h-full grid grid-rows-[auto_auto_minmax(0,1fr)]',
|
||||
'grid grid-rows-[auto_auto_minmax(0,1fr)]',
|
||||
'relative bg-gray-50 pointer-events-auto',
|
||||
'rounded-lg',
|
||||
'dark:border border-highlight shadow shadow-black/10',
|
||||
|
||||
@@ -55,7 +55,6 @@ export type DropdownItem = DropdownItemDefault | DropdownItemSeparator;
|
||||
export interface DropdownProps {
|
||||
children: ReactElement<HTMLAttributes<HTMLButtonElement>>;
|
||||
items: DropdownItem[];
|
||||
openOnHotKeyAction?: HotkeyAction;
|
||||
onOpen?: () => void;
|
||||
onClose?: () => void;
|
||||
}
|
||||
@@ -71,7 +70,7 @@ export interface DropdownRef {
|
||||
}
|
||||
|
||||
export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown(
|
||||
{ children, items, openOnHotKeyAction, onOpen, onClose }: DropdownProps,
|
||||
{ children, items, onOpen, onClose }: DropdownProps,
|
||||
ref,
|
||||
) {
|
||||
const [isOpen, _setIsOpen] = useState<boolean>(false);
|
||||
@@ -88,11 +87,6 @@ export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown
|
||||
[onClose, onOpen],
|
||||
);
|
||||
|
||||
useHotKey(openOnHotKeyAction ?? null, () => {
|
||||
setIsOpen(true);
|
||||
menuRef.current?.next?.();
|
||||
});
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
...menuRef.current,
|
||||
isOpen: isOpen,
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
}
|
||||
|
||||
.placeholder-widget {
|
||||
@apply text-xs text-violet-700 dark:text-violet-700 px-1 rounded cursor-default dark:shadow;
|
||||
@apply text-xs text-violet-700 dark:text-violet-700 px-1 mx-[0.5px] rounded cursor-default dark:shadow;
|
||||
|
||||
/* NOTE: Background and border are translucent so we can see text selection through it */
|
||||
@apply bg-violet-500/20 border border-violet-500/20 border-opacity-40;
|
||||
@@ -131,7 +131,8 @@
|
||||
}
|
||||
|
||||
.cm-editor .fold-gutter-icon {
|
||||
@apply pt-[0.25em] pl-[0.4em] px-[0.4em] h-4 cursor-pointer rounded;
|
||||
@apply pt-[0.25em] pl-[0.4em] px-[0.4em] h-4 rounded;
|
||||
@apply cursor-default !important;
|
||||
}
|
||||
|
||||
.cm-editor .fold-gutter-icon::after {
|
||||
@@ -152,8 +153,9 @@
|
||||
}
|
||||
|
||||
.cm-editor .cm-foldPlaceholder {
|
||||
@apply px-2 border border-gray-400/50 bg-gray-300/50 cursor-default;
|
||||
@apply px-2 border border-gray-400/50 bg-gray-300/50;
|
||||
@apply hover:text-gray-800 hover:border-gray-400;
|
||||
@apply cursor-default !important;
|
||||
}
|
||||
|
||||
.cm-editor .cm-activeLineGutter {
|
||||
|
||||
@@ -32,6 +32,7 @@ export type PairEditorProps = {
|
||||
allowFileValues?: boolean;
|
||||
nameValidate?: InputProps['validate'];
|
||||
valueValidate?: InputProps['validate'];
|
||||
noScroll?: boolean;
|
||||
};
|
||||
|
||||
export type Pair = {
|
||||
@@ -57,6 +58,7 @@ export const PairEditor = memo(function PairEditor({
|
||||
nameValidate,
|
||||
valueType,
|
||||
onChange,
|
||||
noScroll,
|
||||
pairs: originalPairs,
|
||||
valueAutocomplete,
|
||||
valueAutocompleteVariables,
|
||||
@@ -95,7 +97,7 @@ export const PairEditor = memo(function PairEditor({
|
||||
[onChange],
|
||||
);
|
||||
|
||||
const handleMove = useCallback<FormRowProps['onMove']>(
|
||||
const handleMove = useCallback<PairEditorRowProps['onMove']>(
|
||||
(id, side) => {
|
||||
const dragIndex = pairs.findIndex((r) => r.id === id);
|
||||
setHoveredIndex(side === 'above' ? dragIndex : dragIndex + 1);
|
||||
@@ -103,7 +105,7 @@ export const PairEditor = memo(function PairEditor({
|
||||
[pairs],
|
||||
);
|
||||
|
||||
const handleEnd = useCallback<FormRowProps['onEnd']>(
|
||||
const handleEnd = useCallback<PairEditorRowProps['onEnd']>(
|
||||
(id: string) => {
|
||||
if (hoveredIndex === null) return;
|
||||
setHoveredIndex(null);
|
||||
@@ -162,7 +164,8 @@ export const PairEditor = memo(function PairEditor({
|
||||
className={classNames(
|
||||
className,
|
||||
'@container',
|
||||
'pb-2 grid overflow-auto max-h-full',
|
||||
'pb-2 mb-auto',
|
||||
!noScroll && 'overflow-y-auto max-h-full',
|
||||
// Move over the width of the drag handle
|
||||
'-ml-3',
|
||||
// Pad to make room for the drag divider
|
||||
@@ -174,7 +177,7 @@ export const PairEditor = memo(function PairEditor({
|
||||
return (
|
||||
<Fragment key={p.id}>
|
||||
{hoveredIndex === i && <DropMarker />}
|
||||
<FormRow
|
||||
<PairEditorRow
|
||||
pairContainer={p}
|
||||
className="py-1"
|
||||
isLast={isLast}
|
||||
@@ -207,7 +210,7 @@ enum ItemTypes {
|
||||
ROW = 'pair-row',
|
||||
}
|
||||
|
||||
type FormRowProps = {
|
||||
type PairEditorRowProps = {
|
||||
className?: string;
|
||||
pairContainer: PairContainer;
|
||||
forceFocusPairId?: string | null;
|
||||
@@ -233,7 +236,7 @@ type FormRowProps = {
|
||||
| 'allowFileValues'
|
||||
>;
|
||||
|
||||
const FormRow = memo(function FormRow({
|
||||
function PairEditorRow({
|
||||
allowFileValues,
|
||||
className,
|
||||
forceFocusPairId,
|
||||
@@ -254,7 +257,7 @@ const FormRow = memo(function FormRow({
|
||||
valuePlaceholder,
|
||||
valueValidate,
|
||||
valueType,
|
||||
}: FormRowProps) {
|
||||
}: PairEditorRowProps) {
|
||||
const { id } = pairContainer;
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const prompt = usePrompt();
|
||||
@@ -480,7 +483,7 @@ const FormRow = memo(function FormRow({
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const newPairContainer = (initialPair?: Pair): PairContainer => {
|
||||
const id = initialPair?.id ?? uuid();
|
||||
|
||||
13
src-web/hooks/useFloatingSidebarHidden.ts
Normal file
13
src-web/hooks/useFloatingSidebarHidden.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
export function useFloatingSidebarHidden() {
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
const { set, value } = useKeyValue<boolean>({
|
||||
namespace: 'no_sync',
|
||||
key: ['floating_sidebar_hidden', activeWorkspaceId ?? 'n/a'],
|
||||
fallback: false,
|
||||
});
|
||||
|
||||
return [value, set] as const;
|
||||
}
|
||||
8
src-web/hooks/useShouldFloatSidebar.ts
Normal file
8
src-web/hooks/useShouldFloatSidebar.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { useWindowSize } from 'react-use';
|
||||
|
||||
const WINDOW_FLOATING_SIDEBAR_WIDTH = 600;
|
||||
|
||||
export function useShouldFloatSidebar() {
|
||||
const windowSize = useWindowSize();
|
||||
return windowSize.width <= WINDOW_FLOATING_SIDEBAR_WIDTH;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useKeyValue } from './useKeyValue';
|
||||
|
||||
@@ -10,12 +9,5 @@ export function useSidebarHidden() {
|
||||
fallback: false,
|
||||
});
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
show: () => set(false),
|
||||
hide: () => set(true),
|
||||
toggle: () => set((h) => !h),
|
||||
hidden: value,
|
||||
};
|
||||
}, [set, value]);
|
||||
return [value, set] as const;
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ module.exports = {
|
||||
selection: 'hsl(var(--color-violet-500) / 0.3)',
|
||||
focus: 'hsl(var(--color-blue-500) / 0.7)',
|
||||
invalid: 'hsl(var(--color-red-500))',
|
||||
highlight: 'hsl(var(--color-gray-300) / 0.35)',
|
||||
highlightSecondary: 'hsl(var(--color-gray-300) / 0.2)',
|
||||
highlight: 'hsl(var(--color-gray-500) / 0.3)',
|
||||
highlightSecondary: 'hsl(var(--color-gray-500) / 0.15)',
|
||||
transparent: 'transparent',
|
||||
white: 'hsl(0 100% 100% / <alpha-value>)',
|
||||
black: 'hsl(0 100% 0% / <alpha-value>)',
|
||||
|
||||
Reference in New Issue
Block a user