Compare commits

..

No commits in common. "cce6889d3538adfe798601d1fa0fc176f0463642" and "63ff45149a60ae3ebcc90dec5f7b41d519d0870f" have entirely different histories.

39 changed files with 237 additions and 713 deletions

View file

@ -1,361 +0,0 @@
name: email
# Phase 0.3 of the nigig-email remediation plan.
#
# Before this file existed, nigig-email had NO CI of any kind. That is
# how a binary with unbalanced braces reached main and stayed there:
# `cargo check -p nigig-email` failed on main while `--lib` passed, so
# the library was fine and the BINARY had never compiled once. Nobody
# had ever run the crate standalone.
#
# It is also how four unused dependencies survived, one of them
# robius-location -- the exact dependency SMS Phase B removed from three
# other crates because it pulls polkit/gio/glib and two RUSTSEC
# advisories in for code that is never called.
#
# Scope note: this crate is a UI shell over nigig-core::email_account,
# email_store and email_worker. The domain logic lives in nigig-core and
# is host-testable; the SMTP transport is not testable here at all
# (no live server in CI), so the tests that matter are the pure ones and
# this workflow gates those plus compilation of both targets.
on:
push:
paths:
- 'crates/apps/nigig-email/**'
- 'crates/nigig-core/src/email_account.rs'
- 'crates/nigig-core/src/email_store.rs'
- 'crates/nigig-core/src/email_worker.rs'
- 'Cargo.lock'
- 'Cargo.toml'
- 'rust-toolchain.toml'
- '.forgejo/workflows/email.yml'
pull_request:
paths:
- 'crates/apps/nigig-email/**'
- 'crates/nigig-core/src/email_account.rs'
- 'crates/nigig-core/src/email_store.rs'
- 'crates/nigig-core/src/email_worker.rs'
- 'Cargo.lock'
- 'Cargo.toml'
- 'rust-toolchain.toml'
- '.forgejo/workflows/email.yml'
jobs:
# ---------------------------------------------------------------------
# Source-scanning gates. No toolchain needed, so they run first and
# fail fast.
# ---------------------------------------------------------------------
gates:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
# S2 of the assessment. SmtpConfig carries a plaintext password and
# derives Serialize, so anything that reuses it for storage leaks
# the credential. EmailAccount is the persistable half and must
# never grow a password field.
#
# There is a unit test asserting the serialised account contains
# neither the secret nor a field named "password"; this is the
# cheaper structural check that catches the field being added even
# if someone deletes the test.
- name: The persistable account type must not carry a password
run: |
set -euo pipefail
# Look only at the EmailAccount struct body.
body=$(sed -n '/^pub struct EmailAccount {/,/^}/p' \
crates/nigig-core/src/email_account.rs)
if echo "$body" | grep -nE '^[[:space:]]*pub[[:space:]]+password'; then
echo
echo "ERROR: EmailAccount declares a password field."
echo "That type is written to disk. The secret is returned"
echo "separately by AccountDraft::validate and held in memory"
echo "for the session only. Persisting it needs the platform"
echo "keystore first (plan item A1 / C1f)."
exit 1
fi
echo "OK"
# B3. `port.parse().unwrap_or(587)` silently rewrote a typo'd port,
# and because the port selects the transport (465 implicit TLS vs
# 587 STARTTLS) that silently changed the security posture too.
# AccountDraft::validate now rejects a malformed port instead.
- name: A malformed port must not silently become a default
run: |
set -euo pipefail
# Exclude comment lines: email_account.rs documents the old
# behaviour by quoting it, and a gate that trips on its own
# rationale is a gate nobody keeps.
if grep -rnE 'parse\(\)[[:space:]]*\.unwrap_or\(587\)' \
crates/apps/nigig-email/src \
crates/nigig-core/src/email_account.rs \
crates/nigig-core/src/email_store.rs \
| grep -vE '^[^:]*:[0-9]*:[[:space:]]*(//|/\*|\*|///)'; then
echo
echo "ERROR: a port is being parsed with unwrap_or(587)."
echo "That turns '465x' into 587 and switches the transport"
echo "from implicit TLS to STARTTLS without telling the user."
echo "Return AccountError::PortInvalid instead."
exit 1
fi
echo "OK"
# A3, the byte-offset slicing class of bug. `&s[..n]` panics when n
# is not a UTF-8 boundary; one inbound message containing emoji or
# non-Latin text took down the whole SMS conversation list on every
# frame until it was deleted. Email bodies are equally untrusted --
# more so, they arrive with arbitrary MIME -- and email_store's
# preview_line runs per visible row inside draw_walk.
#
# The SMS crates carry the same gate. This one is a hard zero
# because the email code has never had such a slice.
- name: No byte-offset string slicing in the email text helpers
run: |
set -euo pipefail
PATTERN='[A-Za-z_][A-Za-z0-9_]*\[(\.\.=?[A-Za-z0-9_]+|[A-Za-z0-9_]+\.\.)[A-Za-z0-9_]*\]'
# flat[..idx] in preview_line is proven safe -- idx comes from
# char_indices() -- and carries a comment saying so. Exclude it
# by line content rather than by muting the whole file.
hits=$(grep -rnE --include='*.rs' "$PATTERN" \
crates/apps/nigig-email/src \
crates/nigig-core/src/email_store.rs \
crates/nigig-core/src/email_account.rs \
| grep -vE '^[^:]*:[0-9]*:[[:space:]]*(//|/\*|\*)' \
| grep -v 'flat\[\.\.idx\]' || true)
if [ -n "$hits" ]; then
echo "$hits"
echo
echo "ERROR: byte-offset slice(s) above. These panic when the"
echo "offset is not a char boundary, which any email body"
echo "containing emoji or non-Latin text will produce. Use"
echo "char_indices() to find a real boundary first."
exit 1
fi
echo "OK"
# The inbox list is populated from email_store::sample_thread()
# because no receive path exists yet (finding A1, plan C1). That is
# acceptable as scaffolding and unacceptable as a shipped state, so
# keep it visible: the name must stay `sample_`-prefixed and must
# not spread beyond the one call site.
- name: Development sample data must stay obvious and contained
run: |
set -euo pipefail
# Count CALL sites, not the import line.
count=$(grep -rn 'sample_thread()' --include='*.rs' \
crates/apps/nigig-email/src | wc -l)
if [ "$count" -gt 1 ]; then
grep -rn 'sample_thread' --include='*.rs' crates/apps/nigig-email/src
echo
echo "ERROR: sample_thread() is referenced $count times in the"
echo "UI. It is placeholder data for one call site until a real"
echo "fetch lands (plan C1/C4b). Spreading it makes the"
echo "placeholder load-bearing."
exit 1
fi
echo "OK"
# ---------------------------------------------------------------------
# The email domain logic. Pure, host-testable, no display and no
# network -- this is the job that can actually prove something.
# ---------------------------------------------------------------------
email-domain:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
# nigig-core pulls sqlite and the matrix client.
- name: Install native dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq \
pkg-config libssl-dev libsqlite3-dev
# NOT actions/setup-rust@v1 -- that action does not exist on this
# instance's registry and fails the job in "Set up job" before any
# step runs. See .forgejo/RUNNER.md.
- name: Install the declared toolchain
run: |
set -e
version="$(sed -n 's/^[[:space:]]*channel[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' \
rust-toolchain.toml | head -n 1)"
curl --fail --location --proto '=https' --tlsv1.2 https://sh.rustup.rs -o /tmp/rustup-init
chmod 700 /tmp/rustup-init
/tmp/rustup-init -y --profile minimal --default-toolchain "$version" \
--component rustfmt --component clippy --no-modify-path
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Email domain tests
run: cargo test --locked -p nigig-core --lib email_
# A floor, not a ratchet: these tests are cheap, pure, and the
# number should only go up. 38 today.
- name: The email domain test suite must not shrink
run: |
set -euo pipefail
FLOOR=38
out="$(cargo test --locked -p nigig-core --lib email_ 2>&1)"
echo "$out" | grep -E '^test result:' || true
n=$(echo "$out" | grep -E '^test result:' \
| sed -n 's/.* \([0-9]\+\) passed.*/\1/p' \
| awk '{s+=$1} END {print s+0}')
echo "email domain tests: $n (floor $FLOOR)"
if [ "$n" -lt "$FLOOR" ]; then
echo "ERROR: $n < $FLOOR. Tests were deleted or stopped running."
exit 1
fi
echo "OK"
# ---------------------------------------------------------------------
# The UI crate. Pulls the whole Makepad stack, so it is the slow job
# and needs the GUI system libraries.
# ---------------------------------------------------------------------
nigig-email:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- name: Install native dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq \
pkg-config libwayland-dev libxcursor-dev libxrandr-dev \
libxi-dev libx11-dev libgl1-mesa-dev libasound2-dev \
libglib2.0-dev libssl-dev libsqlite3-dev libudev-dev \
libpulse-dev libxkbcommon-dev
- name: Install the declared toolchain
run: |
set -e
version="$(sed -n 's/^[[:space:]]*channel[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' \
rust-toolchain.toml | head -n 1)"
curl --fail --location --proto '=https' --tlsv1.2 https://sh.rustup.rs -o /tmp/rustup-init
chmod 700 /tmp/rustup-init
/tmp/rustup-init -y --profile minimal --default-toolchain "$version" \
--component rustfmt --component clippy --no-modify-path
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# --all-targets on purpose. `--lib` alone passed for the entire
# time main.rs was syntactically invalid, which is precisely the
# failure this job exists to prevent.
- name: Check (lib AND bin)
run: cargo check --locked -p nigig-email --all-targets
- name: Test
run: cargo test --locked -p nigig-email
# Phase 0.6. A hard gate, not report-only: this crate is 1,100
# lines and already formats clean, so there is no pre-existing
# drift to grandfather in. Contrast sms.yml and nigig-map.yml,
# which are report-only because they inherited hundreds of diffs.
- name: Formatting
run: |
cargo fmt -p nigig-email -- --check \
|| { echo "run: cargo fmt -p nigig-email"; exit 1; }
# Ratchet at the measured baseline, which is ZERO.
#
# I first set this to 2, having seen two `unexpected_cfgs` warnings
# for `native_activity` emitted by the app_main! macro. Measuring
# properly with the same dedupe this script uses gives 0 -- those
# two are attributed to the bin target and filtered out by the
# package_id check. A baseline above the real count is not a
# harmless margin: this script fails when n < BASELINE precisely so
# that slack cannot hide a regression.
- name: Clippy ratchet (nigig-email-owned diagnostics only)
run: |
set -euo pipefail
BASELINE=0
cargo clippy --locked -p nigig-email --all-targets \
--message-format=json > /tmp/clippy-email.json 2>/tmp/clippy-email.err || true
cat /tmp/clippy-email.err || true
BASELINE="$BASELINE" python3 - <<'PY'
import json, os, sys
baseline = int(os.environ['BASELINE'])
owned, seen = [], set()
with open('/tmp/clippy-email.json') as fh:
for line in fh:
try:
m = json.loads(line)
except ValueError:
continue
if m.get('reason') != 'compiler-message':
continue
if 'nigig-email' not in m.get('package_id', ''):
continue
msg = m['message']
if msg.get('level') not in ('warning', 'error'):
continue
# --all-targets compiles lib and lib-test, duplicating
# every diagnostic; dedupe on rendered text.
key = msg.get('rendered', '')
if key in seen:
continue
seen.add(key)
owned.append(msg)
n = len(owned)
print("found %d nigig-email diagnostics, baseline %d" % (n, baseline))
if n > baseline:
for msg in owned:
sys.stdout.write(msg.get('rendered', ''))
print()
print("ERROR: %d diagnostics, up from %d." % (n, baseline))
sys.exit(1)
if n < baseline:
print()
print("Good: down to %d. Lower BASELINE in this file to %d "
"so the progress cannot be undone." % (n, n))
sys.exit(1)
print("OK")
PY
# ---------------------------------------------------------------------
# Supply chain.
# ---------------------------------------------------------------------
supply-chain:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
# Phase 0.5. Four dependencies were declared and never referenced,
# one of them robius-location, which drags polkit/gio/glib and two
# RUSTSEC advisories in for code that is never called.
- name: nigig-email must not declare dependencies it never uses
run: |
set -euo pipefail
bad=0
# chrono is used by inbox.rs::format_thread_time. Everything
# else in the manifest must appear in src/ under its
# underscored crate name.
for dep in serde serde_json robius-location robius-sms lettre; do
declared=$(grep -cE "^[[:space:]]*${dep}[[:space:]]*=" \
crates/apps/nigig-email/Cargo.toml || true)
[ "$declared" -eq 0 ] && continue
underscored="${dep//-/_}"
used=$(grep -rl "$underscored" crates/apps/nigig-email/src 2>/dev/null | wc -l)
if [ "$used" -eq 0 ]; then
echo "ERROR: nigig-email declares $dep but never uses it."
bad=1
fi
done
if [ "$bad" -ne 0 ]; then
echo
echo "Unused dependencies enlarge the attack surface and the"
echo "licence obligations for no benefit. Remove them."
exit 1
fi
echo "OK"
- name: Lockfile must be committed and current
run: |
set -euo pipefail
test -f Cargo.lock || { echo "ERROR: Cargo.lock is not committed."; exit 1; }
git diff --exit-code -- Cargo.lock
- name: Reject whitespace errors
run: git diff --check "$(git rev-list --max-parents=0 HEAD | tail -1)"..HEAD || git diff --check

View file

@ -101,7 +101,6 @@ jobs:
bad=0 bad=0
for manifest in \ for manifest in \
crates/apps/nigig-build/Cargo.toml \ crates/apps/nigig-build/Cargo.toml \
crates/apps/nigig-email/Cargo.toml \
crates/nigig-core/Cargo.toml \ crates/nigig-core/Cargo.toml \
crates/nigig-uikit/Cargo.toml; do crates/nigig-uikit/Cargo.toml; do
crate_dir="$(dirname "$manifest")" crate_dir="$(dirname "$manifest")"

315
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -524,14 +524,6 @@ snapshot. Commits are on `main`.
| `5a5b817` | **Phase C2 (early)**`email_account.rs` + `email_store.rs`: session state, account validation, sender-thread grouping, char-safe previews. 38 host tests. | | `5a5b817` | **Phase C2 (early)**`email_account.rs` + `email_store.rs`: session state, account validation, sender-thread grouping, char-safe previews. 38 host tests. |
| `b91f97b` | **Phase 0.1 DONE**`main.rs` braces fixed; the binary compiles for the first time. | | `b91f97b` | **Phase 0.1 DONE**`main.rs` braces fixed; the binary compiles for the first time. |
| `18bbb7b` | **Feature: account-gated inbox** — sender list + thread reader reusing `nigig_uikit::shared::conversation`; setup form moved off the Bulk tab; `drafts.rs` deleted (0.4). | | `18bbb7b` | **Feature: account-gated inbox** — sender list + thread reader reusing `nigig_uikit::shared::conversation`; setup form moved off the Bulk tab; `drafts.rs` deleted (0.4). |
| `cc8a727` | **Phase 0.2 DONE** — 42 abbreviated git revs across 34 crates rewritten to full 40-char SHAs. Label-only change, verified against `Cargo.lock`. |
| `4ae50cb` | **Phase 0.5 DONE**`serde`, `serde_json`, `robius-location` removed; platform-dep gate extended to `nigig-email`. |
| `244c4f2` | **Phase 0.3 + 0.6 DONE**`email.yml` (4 jobs, 11 gates). Writing the gates caught **B2 and B3 still live in `bulk.rs`**; both fixed here. |
**Phase 0 is complete.** All seven items done; 0.7 was fixed upstream.
Every gate in `email.yml` was negative-tested — reverted the fix,
confirmed the gate fails, restored it — rather than merely observed
green.
Verified: `cargo check -p nigig-email --all-targets` → 0 errors; Verified: `cargo check -p nigig-email --all-targets` → 0 errors;
41 tests pass (38 core + 3 UI helpers); `nigig-email` clippy down to 2 41 tests pass (38 core + 3 UI helpers); `nigig-email` clippy down to 2
@ -617,12 +609,12 @@ Nothing else can be trusted until the crate builds and something runs it.
| ID | Task | | ID | Task |
|---|---| |---|---|
| ~~0.1~~ | ~~**Fix `main.rs` braces.**~~ **DONE** (`b91f97b`) — was missing the `StandaloneFeatureBody` wrapper; `--lib` had always passed, so only the binary was broken. | | ~~0.1~~ | ~~**Fix `main.rs` braces.**~~ **DONE** (`b91f97b`) — was missing the `StandaloneFeatureBody` wrapper; `--lib` had always passed, so only the binary was broken. |
| ~~0.2~~ | ~~**Repair the 40-char rev gate repo-wide.**~~ **DONE** (`f5d003f`) — 42 declarations across 34 crates rewritten to full SHAs (`ecf5a572ab62…`, `5efe6e24c9f7…`). Verified label-only: `Cargo.lock` holds one makepad commit id and zero refs to the old. | | 0.2 | **Repair the 40-char rev gate repo-wide.** Resolve `5efe6e24c` → full SHA, rewrite all 42 declarations. This is mechanical and must land in its own commit. |
| ~~0.3~~ | ~~**Create `.forgejo/workflows/email.yml`**~~ **DONE** — 4 jobs: `gates` (4 source scans), `email-domain` (38 tests + floor), `nigig-email` (check `--all-targets`, test, fmt, clippy ratchet), `supply-chain` (unused deps, lockfile, whitespace). | | 0.3 | **Create `.forgejo/workflows/email.yml`**: `gates` (source scans), `nigig-email` (check + clippy + test), `supply-chain` (`cargo deny`, lockfile, unused deps). |
| ~~0.4~~ | ~~**Delete or wire `drafts.rs`.**~~ **DONE** (`18bbb7b`) — deleted. 157 lines never declared in `pages/mod.rs`, so never compiled. | | ~~0.4~~ | ~~**Delete or wire `drafts.rs`.**~~ **DONE** (`18bbb7b`) — deleted. 157 lines never declared in `pages/mod.rs`, so never compiled. |
| ~~0.5~~ | ~~**Drop unused deps.**~~ **DONE** (`e958386`) — removed `serde`, `serde_json`, `robius-location` (all 0 references in `src/`). `chrono` kept: it *is* used by `format_thread_time`, correcting the assessment. Extended the existing platform-dep gate to cover `nigig-email`; negative-tested. | | 0.5 | **Drop unused deps**: `serde_json`, `robius-location`. *Revised:* `chrono` is now used (`format_thread_time`) and `serde` is used by `email_account`/`email_store`, so only two remain. Extend the "removed platform deps must not come back" gate to cover `nigig-email`. |
| ~~0.7~~ | ~~**Unblock `origin/main`.**~~ **DONE upstream** (`005bed1`, not mine) — corrected `i_tree` to `0.19.0`, exactly the fix predicted here. Verified: the workspace resolves and `cargo check -p nigig-email --all-targets` passes on current `main`. | | **0.7** | **NEW, HIGHEST PRIORITY — unblock `origin/main`.** The workspace does not resolve at HEAD, so no crate can be CI-verified. Two causes in sequence: `86c9595` dropped the `maps` feature `pageflipnav` needs; `ce0eaae` fixed that but added `i_tree = "1.0.0"` to `crates/apps/map`, a version crates.io does not have (max published: `0.19.0`). Fix is almost certainly `i_tree = "0.19"`, but that is the map crate's call, not this plan's. Blocks 0.2, 0.3 and every ratchet in Phase E. |
| ~~0.6~~ | ~~**Add `nigig-email` to a fmt gate.**~~ **DONE** — a HARD gate, not report-only: the crate already formats clean, so there is no pre-existing drift to grandfather in. Contrast `sms.yml`/`nigig-map.yml`, which inherited hundreds of diffs and had to report only. | | 0.6 | **Add `nigig-email` to a fmt gate**, or record explicitly why not (SMS chose report-only; email is small enough to just format). |
Exit: `cargo check`/`clippy`/`test -p nigig-email` green on a real runner. Exit: `cargo check`/`clippy`/`test -p nigig-email` green on a real runner.
@ -673,10 +665,7 @@ send-only form. **It needs a product decision before any code.**
| C6 | **Bulk pacing.** Email providers rate-limit harder than carriers. Port `SendPacing` from `robius-sms` — already generic arithmetic. | | C6 | **Bulk pacing.** Email providers rate-limit harder than carriers. Port `SendPacing` from `robius-sms` — already generic arithmetic. |
| C7 | **NEW — pull-to-refresh + background fetch** once C1 lands. The SMS crate's D1/D2 pattern (worker thread → results queue → `SignalToUI` → drained on the UI thread) applies directly; do not fetch from `draw_walk`. | | C7 | **NEW — pull-to-refresh + background fetch** once C1 lands. The SMS crate's D1/D2 pattern (worker thread → results queue → `SignalToUI` → drained on the UI thread) applies directly; do not fetch from `draw_walk`. |
#### C1 — DECIDED: support both, user-selectable #### C1 — the decision I need from you
**Decision (2026-08-16): implement both backends and let the user pick,
with a setup form appropriate to each.**
| | IMAP on device | Server-side proxy | | | IMAP on device | Server-side proxy |
|---|---|---| |---|---|---|
@ -686,70 +675,12 @@ with a setup form appropriate to each.**
| wasm | IMAP over raw TCP is impossible in a browser — needs a proxy *anyway* | Same code path on every platform | | wasm | IMAP over raw TCP is impossible in a browser — needs a proxy *anyway* | Same code path on every platform |
| Resolves S2? | No — you still hold the password | **Largely yes** | | Resolves S2? | No — you still hold the password | **Largely yes** |
This is the right call and it is *cheaper than it sounds*, because wasm My read: **the proxy wins on merit**, mostly because the wasm target
already forces a proxy to exist: supporting only IMAP was never actually already forces one and because it retires the password-storage problem
an option for the browser target. So the second backend is not new scope, rather than mitigating it. But it is infrastructure you may not want to
it is scope that was already implied. run, and IMAP-on-device is the only option that works with no backend at
all. This is a product call, not a technical one, which is why I have not
##### What "both" requires architecturally made it.
The thing that makes this tractable is a **trait boundary**, not two
parallel UIs. One `MailBackend` abstraction with two implementations, and
a `BackendKind` discriminant on the account:
```rust
pub enum BackendKind { ImapSmtp, ProxyApi }
pub trait MailBackend {
async fn verify(&self) -> Result<(), String>;
async fn list_inbox(&self) -> Result<Vec<EmailMessage>, String>;
async fn send(&self, req: &EmailSendRequest) -> Result<(), String>;
}
```
`email_store`'s grouping, `preview_line`, the inbox list, the thread
reader and the unread handling all sit **above** this line and are already
written — they consume `Vec<EmailMessage>` and do not care where it came
from. That was deliberate (see C2) and it is what makes two backends a
contained change rather than a rewrite.
##### Two forms, and the fields genuinely differ
Not one form with a toggle that hides rows — the fields are different
enough that pretending otherwise produces a confusing screen:
| IMAP + SMTP | Proxy API |
|---|---|
| Email address | Email address |
| IMAP server + port | API base URL (**must be HTTPS** — S5) |
| SMTP server + port | API token / credential |
| Username | — |
| Password / app password | — |
| — | Optional account label |
So: a backend chooser first, then the matching form. `AccountDraft` gains
a `BackendKind` and validation branches on it — `validate()` already
returns `Vec<AccountError>` and reports every problem at once, so this
extends cleanly.
##### Sequencing
| ID | Task |
|---|---|
| C1a | `BackendKind` + `MailBackend` trait in `nigig-core`. Host-testable with a fake backend; no network. |
| C1b | Extend `AccountDraft`/`EmailAccount` with `BackendKind`; branch validation. Tests for both shapes, including HTTPS-only enforcement on the proxy URL. |
| C1c | Backend chooser + two forms in `EmailAccountSetup`. |
| C1d | `ProxyApiBackend` — thin HTTP client. Do this **first** of the two: it is smaller, it is the only option on wasm, and it exercises the trait boundary end to end. |
| C1e | `ImapSmtpBackend``async-imap`, native only. Gate behind a feature so wasm builds never pull it in. |
| C1f | Keystore-backed credential storage (A1). Required for IMAP to be usable across restarts; optional for the proxy, which can hold a revocable token instead. |
##### One thing I will not pretend
Offering both **doubles the security surface**, and the IMAP path is the
one that keeps a reusable password on the device. A revocable proxy token
is strictly safer than a password that also unlocks the user's password
resets. So the setup UI should say which is which, plainly, rather than
presenting them as equivalent choices.
--- ---

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -5,7 +5,7 @@ edition = "2021"
description = "Map tile renderer with viewport, caching, scheduling, and MVT decoding" description = "Map tile renderer with viewport, caching, scheduling, and MVT decoding"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc" } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572" }
# Polygon operations (used by makepad_map for advanced geometry) # Polygon operations (used by makepad_map for advanced geometry)
i_overlay = { version = "7.0.3", default-features = false } i_overlay = { version = "7.0.3", default-features = false }
@ -14,7 +14,7 @@ i_shape = "1.0.0"
i_tree = "0.19.0" i_tree = "0.19.0"
[dev-dependencies] [dev-dependencies]
makepad-test = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc" } makepad-test = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572" }
[features] [features]
default = ["map_style"] default = ["map_style"]

View file

@ -6,9 +6,9 @@ description = "Visual regression test application for nigig-map widget"
[dependencies] [dependencies]
<<<<<<< HEAD <<<<<<< HEAD
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "5efe6e24c9f732e9f11b783757f196f4f1c402b2", features = ["maps"] } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "5efe6e24c", features = ["maps"] }
======= =======
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", features = ["maps"] } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", features = ["maps"] }
>>>>>>> 71b5460 (chore: update makepad fork to latest upstream/dev (abd70f4)) >>>>>>> 71b5460 (chore: update makepad fork to latest upstream/dev (abd70f4))
nigig-map = { path = "../.." } nigig-map = { path = "../.." }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,11 +4,11 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", features = ["test", "csg", "gltf"] } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", features = ["test", "csg", "gltf"] }
makepad-code-editor = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-code-editor = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
makepad-xr = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-xr = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
makepad-ai = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-ai = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
makepad-base64 = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-base64 = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
# makepad-gltf: read-side GLB parser. Used for round-trip validation # makepad-gltf: read-side GLB parser. Used for round-trip validation
# of arch_gltf.rs output (write GLB → load with makepad_gltf → verify). # of arch_gltf.rs output (write GLB → load with makepad_gltf → verify).
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,8 +4,10 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
# Used by inbox.rs::format_thread_time for list-row timestamps. serde = { version = "1", features = ["derive"] }
serde_json = "1"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
robius-location = { git = "https://github.com/project-robius/robius", rev = "b766e62b0600f5d2ee21cc6995648346fc277bd8" }

View file

@ -1,5 +1,4 @@
use makepad_widgets::*; use makepad_widgets::*;
use nigig_core::email_account::AccountDraft;
use nigig_core::email_worker::{spawn_send_email, spawn_smtp_test, EmailWorkerAction, SmtpConfig}; use nigig_core::email_worker::{spawn_send_email, spawn_smtp_test, EmailWorkerAction, SmtpConfig};
script_mod! { script_mod! {
@ -88,45 +87,29 @@ impl Widget for EmailBulkPage {
self.view.handle_event(cx, event, scope); self.view.handle_event(cx, event, scope);
if let Event::Actions(actions) = event { if let Event::Actions(actions) = event {
// B2: this block used to read five TextInputs and build an let server = self.text_input(cx, ids!(server_input)).text();
// SmtpConfig on EVERY action event -- ten heap allocations let port_t = self.text_input(cx, ids!(port_input)).text();
// per keystroke, per scroll, per timer tick from any widget let username = self.text_input(cx, ids!(username_input)).text();
// in the app, for a struct only read when a button is let password = self.text_input(cx, ids!(password_input)).text();
// clicked. Worse, it captured whatever the fields happened let from = self.text_input(cx, ids!(from_input)).text();
// to hold when an unrelated action fired. Read on click
// instead.
let test_clicked = self.button(cx, ids!(test_btn)).clicked(actions);
let send_clicked = self.button(cx, ids!(send_btn)).clicked(actions);
if test_clicked || send_clicked { let port: u16 = port_t.parse().unwrap_or(587);
match self.read_config(cx) { self.smtp_config = SmtpConfig {
Err(msg) => { server: server.clone(),
// B3: the port used to be parsed with port,
// `unwrap_or(587)`, so "465x" silently became 587 username: username.clone(),
// -- and because the port selects the transport password: password.clone(),
// (465 implicit TLS vs 587 STARTTLS) that from: from.clone(),
// silently changed the security posture too. Say };
// so instead.
let id = if test_clicked { if self.button(cx, ids!(test_btn)).clicked(actions) {
ids!(status_label) let config = self.smtp_config.clone();
} else { self.label(cx, ids!(status_label))
ids!(send_status) .set_text(cx, "Testing...");
}; spawn_smtp_test(config);
self.label(cx, id).set_text(cx, &msg);
self.view.redraw(cx);
}
Ok(config) => {
self.smtp_config = config.clone();
if test_clicked {
self.label(cx, ids!(status_label))
.set_text(cx, "Testing...");
spawn_smtp_test(config);
}
}
}
} }
if send_clicked && !self.smtp_config.server.is_empty() { if self.button(cx, ids!(send_btn)).clicked(actions) {
let to = self.text_input(cx, ids!(to_input)).text(); let to = self.text_input(cx, ids!(to_input)).text();
let subject = self.text_input(cx, ids!(subject_input)).text(); let subject = self.text_input(cx, ids!(subject_input)).text();
let message = self.text_input(cx, ids!(message_input)).text(); let message = self.text_input(cx, ids!(message_input)).text();
@ -158,36 +141,3 @@ impl Widget for EmailBulkPage {
self.view.draw_walk(cx, scope, walk) self.view.draw_walk(cx, scope, walk)
} }
} }
impl EmailBulkPage {
/// Read the SMTP form and validate it.
///
/// Routes through `AccountDraft::validate`, which is unit tested in
/// nigig-core, rather than re-implementing parsing here. That is the
/// only reason this page now rejects a malformed port instead of
/// silently rewriting it to 587 (B3).
fn read_config(&mut self, cx: &mut Cx) -> Result<SmtpConfig, String> {
let draft = AccountDraft {
address: self.text_input(cx, ids!(from_input)).text(),
smtp_server: self.text_input(cx, ids!(server_input)).text(),
smtp_port: self.text_input(cx, ids!(port_input)).text(),
username: self.text_input(cx, ids!(username_input)).text(),
password: self.text_input(cx, ids!(password_input)).text(),
display_name: String::new(),
};
match draft.validate() {
Ok((account, password)) => Ok(SmtpConfig {
server: account.smtp_server,
port: account.smtp_port,
username: account.username,
password,
from: account.address,
}),
Err(errors) => Err(errors
.iter()
.map(|e| e.message())
.collect::<Vec<_>>()
.join(" ")),
}
}
}

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -38,7 +38,7 @@ default = ["demo"]
demo = ["nigig-pay-ui/demo"] demo = ["nigig-pay-ui/demo"]
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", features = ["test"] } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", features = ["test"] }
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -34,7 +34,7 @@ default = []
demo = [] demo = []
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-pay-domain = { path = "../../nigig-pay-domain" } nigig-pay-domain = { path = "../../nigig-pay-domain" }
# Session correlation (review items 2.7 / 5.3). The registry that refuses an # Session correlation (review items 2.7 / 5.3). The registry that refuses an

View file

@ -38,7 +38,7 @@ default = ["demo"]
demo = ["nigig-pay-ui/demo"] demo = ["nigig-pay-ui/demo"]
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", features = ["test"] } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", features = ["test"] }
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
robius-ussd = { path = "../../robius-ussd", features = ["serde"] } robius-ussd = { path = "../../robius-ussd", features = ["serde"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -10,7 +10,7 @@ edition = "2021"
# The example app in makepad-example-map uses the same flag. # The example app in makepad-example-map uses the same flag.
# `map_style` belongs to the Nigig map crate; the Robrix Makepad fork exposes # `map_style` belongs to the Nigig map crate; the Robrix Makepad fork exposes
# its built-in map widget through the `maps` feature only. # its built-in map widget through the `maps` feature only.
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", features = ["maps"] } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", features = ["maps"] }
nigig-map = { path = "../map" } nigig-map = { path = "../map" }
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -11,14 +11,14 @@ nigig-pdf-document = { path = "../pdf-document" }
nigig-pdf-graphics = { path = "../pdf-graphics" } nigig-pdf-graphics = { path = "../pdf-graphics" }
# The `test` feature gates makepad-widgets' re-export of makepad-test, # The `test` feature gates makepad-widgets' re-export of makepad-test,
# which tests/ui.rs imports as makepad_widgets::makepad_test. # which tests/ui.rs imports as makepad_widgets::makepad_test.
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", features = ["test"] } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", features = ["test"] }
[dev-dependencies] [dev-dependencies]
# Both are required, and neither is redundant: `ui.rs` imports the symbols # Both are required, and neither is redundant: `ui.rs` imports the symbols
# through the re-export above, but the `#[makepad_test]` attribute expands # through the re-export above, but the `#[makepad_test]` attribute expands
# to an absolute `::makepad_test::` path, which only resolves if the crate # to an absolute `::makepad_test::` path, which only resolves if the crate
# is also a direct dependency. Dropping either breaks the UI tests. # is also a direct dependency. Dropping either breaks the UI tests.
makepad-test = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", package = "makepad-test" } makepad-test = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", package = "makepad-test" }
# A binary host so makepad_test can drive the widget through real event # A binary host so makepad_test can drive the widget through real event
# delivery; the crate itself remains a library. # delivery; the crate itself remains a library.

View file

@ -16,8 +16,8 @@ description = "Makepad widget wrappers for the spreadsheet engine."
# #
# For now, using a relative path from this crate's location: # For now, using a relative path from this crate's location:
# crates/apps/spreadsheet/spreadsheet-ui/ → ../../../../makepad/widgets # crates/apps/spreadsheet/spreadsheet-ui/ → ../../../../makepad/widgets
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
spreadsheet-engine = { path = "../spreadsheet-engine" } spreadsheet-engine = { path = "../spreadsheet-engine" }
[dev-dependencies] [dev-dependencies]
makepad-test = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", package = "makepad-test" } makepad-test = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", package = "makepad-test" }

View file

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../../nigig-core" } nigig-core = { path = "../../nigig-core" }
nigig-uikit = { path = "../../nigig-uikit" } nigig-uikit = { path = "../../nigig-uikit" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }

View file

@ -21,7 +21,7 @@ nigig-core = { path = "../../nigig-core" }
# matches. If nigig-core uses a path dep, match it here. If it uses git, # matches. If nigig-core uses a path dep, match it here. If it uses git,
# match that. # match that.
# makepad-widgets = { git = "https://github.com/makepad/makepad.git", branch = "dev" } # makepad-widgets = { git = "https://github.com/makepad/makepad.git", branch = "dev" }
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
# ── Robius integration ─────────────────────────────────────────────────── # ── Robius integration ───────────────────────────────────────────────────
# robius-use-makepad sets up the right Makepad feature flags for # robius-use-makepad sets up the right Makepad feature flags for

View file

@ -12,7 +12,7 @@ async-rt = []
[dependencies] [dependencies]
matrix_client = { path = "../matrix_client", default-features = false } matrix_client = { path = "../matrix_client", default-features = false }
nigig-system-prefs = { path = "../nigig-system-prefs" } nigig-system-prefs = { path = "../nigig-system-prefs" }
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }

View file

@ -5,7 +5,7 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc"} makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572"}
nigig-core = { path = "../nigig-core" } nigig-core = { path = "../nigig-core" }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"

View file

@ -48,7 +48,7 @@ panic = 'abort'
strip = true strip = true
[dependencies] [dependencies]
makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572ab62a1c1598909971f602f99083671cc", default-features = false, features = ["test", "serde", "maps"] } makepad-widgets = { git = "https://gitdab.com/andodeki/makepad", rev = "ecf5a572", default-features = false, features = ["test", "serde", "maps"] }
robius-use-makepad = "0.1.1" robius-use-makepad = "0.1.1"
robius-open = { git = "https://github.com/project-robius/robius", rev = "b766e62b0600f5d2ee21cc6995648346fc277bd8" } robius-open = { git = "https://github.com/project-robius/robius", rev = "b766e62b0600f5d2ee21cc6995648346fc277bd8" }
robius-directories = { git = "https://github.com/project-robius/robius", rev = "b766e62b0600f5d2ee21cc6995648346fc277bd8" } robius-directories = { git = "https://github.com/project-robius/robius", rev = "b766e62b0600f5d2ee21cc6995648346fc277bd8" }