@remit/ui 0.0.58 → 0.0.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/filter-rule.ts +43 -20
- package/src/components/selection-wizard.render.test.ts +725 -0
- package/src/components/selection-wizard.tsx +1078 -0
- package/src/index.ts +56 -0
- package/src/lib/rule-name.test.ts +28 -0
- package/src/lib/rule-name.ts +27 -0
- package/src/lib/sender-derivation.test.ts +53 -0
- package/src/lib/sender-derivation.ts +35 -0
- package/src/lib/wizard-steps.test.ts +673 -0
- package/src/lib/wizard-steps.ts +478 -0
package/package.json
CHANGED
|
@@ -241,15 +241,47 @@ export function commitLabel(scope: RuleScope): string {
|
|
|
241
241
|
return "Save until then";
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Why a rule cannot be committed yet, one message per unmet condition. Any
|
|
246
|
+
* surface that asks for a rule — the editor in one pass, the wizard one step at
|
|
247
|
+
* a time — says the same thing about the same gap, because there is one string
|
|
248
|
+
* for it.
|
|
249
|
+
*/
|
|
250
|
+
export const ruleBlockedCopy = {
|
|
251
|
+
noMatch: "Add a clause so the rule has something to match.",
|
|
252
|
+
// A one-time apply runs the vector-free matcher, which cannot read message
|
|
253
|
+
// bodies. Saved as a rule the same clause works, so say that rather than
|
|
254
|
+
// refusing the clause outright.
|
|
255
|
+
bodyTextOnce:
|
|
256
|
+
"Applying once can't read message bodies. Save this as a rule instead, or drop the “has the words” clause.",
|
|
257
|
+
noAction: "Pick a folder to move into, or a label to apply.",
|
|
258
|
+
unnamed: "Name this rule so you can find it later.",
|
|
259
|
+
noUntilDate: "Pick the date this rule should stop on.",
|
|
260
|
+
counting: "Counting matches — save once the count settles.",
|
|
261
|
+
recounting: "Recounting matches — save once the count settles.",
|
|
262
|
+
} as const;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Why the count on screen is not yet the count that will be applied, or
|
|
266
|
+
* `undefined` once it has settled. This is what makes RFC 038's
|
|
267
|
+
* previewed-set-equals-applied-set contract structural rather than a promise:
|
|
268
|
+
* no surface can commit a rule whose match count is still moving.
|
|
269
|
+
*/
|
|
270
|
+
export function previewSettledReason(
|
|
271
|
+
preview: PreviewCount,
|
|
272
|
+
): string | undefined {
|
|
273
|
+
if (preview.status === "loading") return ruleBlockedCopy.counting;
|
|
274
|
+
if (preview.status === "ready" && preview.stale)
|
|
275
|
+
return ruleBlockedCopy.recounting;
|
|
276
|
+
return undefined;
|
|
277
|
+
}
|
|
278
|
+
|
|
244
279
|
/**
|
|
245
280
|
* Why the rule cannot be saved yet, or `undefined` when it is ready. A rule
|
|
246
281
|
* needs at least one live way to match, at least one action — move and/or
|
|
247
282
|
* label, either satisfies this (issue #26) — and, for the two persisted
|
|
248
|
-
* scopes, a name and, for `until`, a date. It also needs a settled preview
|
|
249
|
-
*
|
|
250
|
-
* will be applied. That makes RFC 038's previewed-set-equals-applied-set
|
|
251
|
-
* contract structural — a consumer cannot save a rule whose match count is
|
|
252
|
-
* still moving. Never disable a control without saying why (ux.md).
|
|
283
|
+
* scopes, a name and, for `until`, a date. It also needs a settled preview.
|
|
284
|
+
* Never disable a control without saying why (ux.md).
|
|
253
285
|
*/
|
|
254
286
|
export function commitBlockedReason(
|
|
255
287
|
rule: FilterRule,
|
|
@@ -258,26 +290,17 @@ export function commitBlockedReason(
|
|
|
258
290
|
const hasMatch =
|
|
259
291
|
rule.clauses.length > 0 ||
|
|
260
292
|
(rule.widen !== undefined && !rule.widen.inactive);
|
|
261
|
-
if (!hasMatch) return
|
|
262
|
-
// A one-time apply runs the vector-free matcher, which cannot read message
|
|
263
|
-
// bodies. Saved as a rule the same clause works, so say that rather than
|
|
264
|
-
// refusing the clause outright.
|
|
293
|
+
if (!hasMatch) return ruleBlockedCopy.noMatch;
|
|
265
294
|
if (rule.scope === "once" && unreadableBodyClauses(rule).length > 0)
|
|
266
|
-
return
|
|
267
|
-
if (!rule.moveMailboxId && !rule.labelId)
|
|
268
|
-
return "Pick a folder to move into, or a label to apply.";
|
|
295
|
+
return ruleBlockedCopy.bodyTextOnce;
|
|
296
|
+
if (!rule.moveMailboxId && !rule.labelId) return ruleBlockedCopy.noAction;
|
|
269
297
|
if (
|
|
270
298
|
(rule.scope === "standing" || rule.scope === "until") &&
|
|
271
299
|
(rule.name ?? "").trim() === ""
|
|
272
300
|
)
|
|
273
|
-
return
|
|
274
|
-
if (rule.scope === "until" && !rule.until)
|
|
275
|
-
|
|
276
|
-
if (preview.status === "loading")
|
|
277
|
-
return "Counting matches — save once the count settles.";
|
|
278
|
-
if (preview.status === "ready" && preview.stale)
|
|
279
|
-
return "Recounting matches — save once the count settles.";
|
|
280
|
-
return undefined;
|
|
301
|
+
return ruleBlockedCopy.unnamed;
|
|
302
|
+
if (rule.scope === "until" && !rule.until) return ruleBlockedCopy.noUntilDate;
|
|
303
|
+
return previewSettledReason(preview);
|
|
281
304
|
}
|
|
282
305
|
|
|
283
306
|
export const demoFolders: FolderOption[] = [
|