selfstore 1.8.5 → 1.8.7
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/dist/advanced.d.ts +1 -1
- package/dist/advanced.js +1 -1
- package/dist/advanced.js.map +1 -1
- package/dist/{chunk-PNX7AJYO.js → chunk-LKIRWVXM.js} +27 -4
- package/dist/chunk-LKIRWVXM.js.map +1 -0
- package/dist/{chunk-ELDSPUTS.js → chunk-TXAMWBG5.js} +45 -5
- package/dist/chunk-TXAMWBG5.js.map +1 -0
- package/dist/{flows-1EntUZ91.d.ts → flows-vX9zy9bI.d.ts} +42 -1
- package/dist/flows.d.ts +1 -1
- package/dist/flows.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/{local-C52j3DeH.d.ts → local-VLHtF3vT.d.ts} +45 -10
- package/dist/widgets.d.ts +19 -1
- package/dist/widgets.js +92 -29
- package/dist/widgets.js.map +1 -1
- package/llms.txt +10 -2
- package/package.json +1 -1
- package/dist/chunk-ELDSPUTS.js.map +0 -1
- package/dist/chunk-PNX7AJYO.js.map +0 -1
|
@@ -47,7 +47,44 @@ interface FlowHost {
|
|
|
47
47
|
type StoreLike = FlowHost | {
|
|
48
48
|
flowHost: FlowHost;
|
|
49
49
|
};
|
|
50
|
+
/**
|
|
51
|
+
* A destination this device has already used, offered as one gesture back to
|
|
52
|
+
* it rather than as the question it answered the first time.
|
|
53
|
+
*
|
|
54
|
+
* The screen that asks "where should we save your data?" is right exactly
|
|
55
|
+
* once. Every time after that - a device whose destination was detached, a
|
|
56
|
+
* browser whose storage was cleared - the app usually still knows the answer,
|
|
57
|
+
* and asking again makes the returning user re-derive a decision they already
|
|
58
|
+
* made. This offer carries that memory: it goes first, above a separator, and
|
|
59
|
+
* says WHICH backup it will reopen.
|
|
60
|
+
*
|
|
61
|
+
* The host supplies the connector, because only the host knows how to reach
|
|
62
|
+
* the remembered destination (adopting a known file id, not searching by
|
|
63
|
+
* name). The flow supplies what follows: no conflict step, and no chooser.
|
|
64
|
+
*/
|
|
65
|
+
interface ResumeOffer {
|
|
66
|
+
/** Which destination it is. Picks the icon and the wording, nothing else. */
|
|
67
|
+
kind: ConnectKind;
|
|
68
|
+
/**
|
|
69
|
+
* What exactly is being reopened - the account, the file name. Rendered as
|
|
70
|
+
* the card's second line: "resume my backup" only answers the user's
|
|
71
|
+
* question when it can name the backup.
|
|
72
|
+
*/
|
|
73
|
+
detail?: string;
|
|
74
|
+
/** Reopen it. Same contract as any connector: null when the user cancels. */
|
|
75
|
+
connect: Connector;
|
|
76
|
+
}
|
|
50
77
|
interface ConnectFlowOptions {
|
|
78
|
+
/**
|
|
79
|
+
* The destination this device already used, offered ahead of the others.
|
|
80
|
+
* Absent (the default) means every visit is a first visit.
|
|
81
|
+
*
|
|
82
|
+
* Taking this offer never raises the conflict step, whatever
|
|
83
|
+
* `hasLocalData` says: reopening one's own backup is not a merge question,
|
|
84
|
+
* it IS the answer to it. The question still stands for a destination the
|
|
85
|
+
* user newly points at.
|
|
86
|
+
*/
|
|
87
|
+
resume?: ResumeOffer;
|
|
51
88
|
/** Declare when this device holds data worth a question: only then does an
|
|
52
89
|
* existing backup raise the 'conflict' step with the destructive choices.
|
|
53
90
|
* Default: never - the flow applies defaultResolution. */
|
|
@@ -126,6 +163,10 @@ interface ConnectFlow extends FlowStore<ConnectSnapshot> {
|
|
|
126
163
|
* with the object form, `variant` picks the gesture: 'create' (default,
|
|
127
164
|
* save picker) or 'open' (adopt an existing backup file). */
|
|
128
165
|
choose(kind: ConnectKind, variant?: 'create' | 'open'): void;
|
|
166
|
+
/** Reopen the remembered destination (`options.resume`). Same gesture rule
|
|
167
|
+
* as choose - call it inside the click. No-op when nothing is remembered.
|
|
168
|
+
* Never raises the conflict step: this backup is already this device's. */
|
|
169
|
+
resume(): void;
|
|
129
170
|
/** 'form' step (webdav: true): submit the server config. */
|
|
130
171
|
submitWebdav(config: WebdavConfig): void;
|
|
131
172
|
/** 'form' step (s3: true): submit the bucket config. */
|
|
@@ -323,4 +364,4 @@ declare function joinFlow(link: string, engine: JoinEngine, options?: {
|
|
|
323
364
|
deadlineMs?: number;
|
|
324
365
|
}): JoinFlow;
|
|
325
366
|
|
|
326
|
-
export {
|
|
367
|
+
export { joinFlow as A, replicaFlow as B, type ConnectTargets as C, shareFlow as D, type FlowHost as F, type JoinEngine as J, type ReplicaFlow as R, type StoreLike as S, type ConnectFlowOptions as a, type ConnectKind as b, type ConnectFlow as c, type ShareEngine as d, type ShareLevel as e, type ShareFlow as f, type JoinFlow as g, type ConnectFlowOutcome as h, type ConnectResolution as i, type ConnectSnapshot as j, type ConnectStep as k, type Connector as l, type JoinOutcome as m, type JoinPreview as n, type JoinSnapshot as o, type JoinStep as p, REPLICA_ID as q, type ReplicaFlowOptions as r, type ReplicaSnapshot as s, type ReplicaStep as t, type ResumeOffer as u, type ShareBusy as v, type ShareLinkInfo as w, type ShareMemberInfo as x, type ShareSnapshot as y, connectFlow as z };
|
package/dist/flows.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { c as ConnectFlow, a as ConnectFlowOptions, h as ConnectFlowOutcome, b as ConnectKind, i as ConnectResolution, j as ConnectSnapshot, k as ConnectStep, C as ConnectTargets, l as Connector, F as FlowHost, J as JoinEngine, g as JoinFlow, m as JoinOutcome, n as JoinPreview, o as JoinSnapshot, p as JoinStep, q as REPLICA_ID, R as ReplicaFlow, r as ReplicaFlowOptions, s as ReplicaSnapshot, t as ReplicaStep, u as ShareBusy, d as ShareEngine, f as ShareFlow, e as ShareLevel,
|
|
1
|
+
export { c as ConnectFlow, a as ConnectFlowOptions, h as ConnectFlowOutcome, b as ConnectKind, i as ConnectResolution, j as ConnectSnapshot, k as ConnectStep, C as ConnectTargets, l as Connector, F as FlowHost, J as JoinEngine, g as JoinFlow, m as JoinOutcome, n as JoinPreview, o as JoinSnapshot, p as JoinStep, q as REPLICA_ID, R as ReplicaFlow, r as ReplicaFlowOptions, s as ReplicaSnapshot, t as ReplicaStep, u as ResumeOffer, v as ShareBusy, d as ShareEngine, f as ShareFlow, e as ShareLevel, w as ShareLinkInfo, x as ShareMemberInfo, y as ShareSnapshot, z as connectFlow, A as joinFlow, B as replicaFlow, D as shareFlow } from './flows-vX9zy9bI.js';
|
|
2
2
|
export { F as FlowStore, w as withDeadline } from './machine-ALMkT3mk.js';
|
|
3
3
|
import './store-BiQ-BuVl.js';
|
|
4
4
|
import './cache-ilsK3Tki.js';
|
package/dist/flows.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { connectFlow, joinFlow, shareFlow } from './chunk-
|
|
1
|
+
export { connectFlow, joinFlow, shareFlow } from './chunk-LKIRWVXM.js';
|
|
2
2
|
import { connect as connect$1, connect3, connect2, fromSession as fromSession$1, fromSession2, fromSession3 } from './chunk-TKWU52LK.js';
|
|
3
3
|
import { makeMachine, toStoreError } from './chunk-W22V5CRM.js';
|
|
4
4
|
export { withDeadline } from './chunk-W22V5CRM.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { L as LocalCache, K as KV } from './cache-ilsK3Tki.js';
|
|
|
4
4
|
import { SyncConfig } from './sync.js';
|
|
5
5
|
import { i as DriveAuth } from './drive-CTYvGg_7.js';
|
|
6
6
|
import { W as WebdavConfig, S as S3Config } from './s3-DvsnA-FK.js';
|
|
7
|
-
export {
|
|
7
|
+
export { f as changePassword, g as gisDriveAuth, p as pickFromDisk, s as saveToDisk } from './local-VLHtF3vT.js';
|
|
8
8
|
|
|
9
9
|
declare const BACKUP_EXTENSION = ".zip";
|
|
10
10
|
declare const BACKUP_MIME = "application/zip";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { indexedDbCache, memoryCache, isLockableCache, createLocalStore } from './chunk-
|
|
2
|
-
export { gisDriveAuth } from './chunk-
|
|
1
|
+
import { indexedDbCache, memoryCache, isLockableCache, createLocalStore } from './chunk-TXAMWBG5.js';
|
|
2
|
+
export { gisDriveAuth } from './chunk-TXAMWBG5.js';
|
|
3
3
|
import './chunk-SKWHKM25.js';
|
|
4
4
|
import { saveToDisk } from './chunk-DCEXWSM6.js';
|
|
5
5
|
export { pickFromDisk, saveToDisk } from './chunk-DCEXWSM6.js';
|
|
@@ -21,19 +21,54 @@ declare function changePassword(input: Blob | Uint8Array, opts: {
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* A client-only DriveAuth: the Google Identity Services token flow, no backend.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
24
|
+
*
|
|
25
|
+
* What this flow can and cannot do, because it decides how often a user is
|
|
26
|
+
* interrupted. Google's browser token flow issues an access token that lives
|
|
27
|
+
* about an hour and NO refresh token - a refresh token requires a client secret,
|
|
28
|
+
* which requires a server. And `requestAccessToken` always opens a popup, even
|
|
29
|
+
* with `prompt: ''`: the popup closes by itself when the grant is still on file,
|
|
30
|
+
* but opening it at all needs a user gesture. So a purely client-side app cannot
|
|
31
|
+
* silently re-acquire a token on page load. What it CAN do:
|
|
32
|
+
*
|
|
33
|
+
* - reuse a token it already has (`persist: 'session'`), so a reload inside the
|
|
34
|
+
* hour asks for nothing at all;
|
|
35
|
+
* - name the account (`hint`), so the popup does not ask which one;
|
|
36
|
+
* - re-grant without the consent screen (`prompt: ''` before `'consent'`) -
|
|
37
|
+
* which is also what stops Google mailing "you granted access" every time.
|
|
38
|
+
*
|
|
39
|
+
* For a connection that never re-prompts, back the Drive target with a server
|
|
40
|
+
* that holds a refresh token instead (a broker implementing this same DriveAuth).
|
|
30
41
|
*/
|
|
31
42
|
|
|
32
|
-
/**
|
|
33
|
-
|
|
43
|
+
/** Where the access token survives between requests. */
|
|
44
|
+
type GisTokenPersistence = 'memory' | 'session';
|
|
45
|
+
interface GisDriveAuthOptions {
|
|
34
46
|
clientId: string;
|
|
35
47
|
scope?: string;
|
|
36
|
-
|
|
48
|
+
/**
|
|
49
|
+
* The account to re-grant for, so the popup does not ask which one. Pass the
|
|
50
|
+
* address the app remembers (`driveTarget.account()` answers it once
|
|
51
|
+
* connected); a function is read at every request, for a host that only
|
|
52
|
+
* learns it after the first connect.
|
|
53
|
+
*/
|
|
54
|
+
hint?: string | (() => string | null | undefined);
|
|
55
|
+
/**
|
|
56
|
+
* Where the access token lives between requests.
|
|
57
|
+
*
|
|
58
|
+
* `'memory'` (the default) keeps it in a closure and nowhere else: a reload
|
|
59
|
+
* has to re-acquire it, which needs a click, but no Drive-scoped credential is
|
|
60
|
+
* ever written to web storage.
|
|
61
|
+
*
|
|
62
|
+
* `'session'` also keeps it in `sessionStorage`, so a reload reuses the token
|
|
63
|
+
* it already has and asks for nothing. That token is a bearer credential for
|
|
64
|
+
* the `drive.file` scope, readable by any script on the origin; it dies with
|
|
65
|
+
* the tab and within the hour. Opt in for an app whose users reload often;
|
|
66
|
+
* leave it alone where an XSS on the origin must find nothing to lift.
|
|
67
|
+
*/
|
|
68
|
+
persist?: GisTokenPersistence;
|
|
69
|
+
}
|
|
70
|
+
/** Build a client-only DriveAuth for the given OAuth client id (no backend). */
|
|
71
|
+
declare function gisDriveAuth(opts: GisDriveAuthOptions): DriveAuth;
|
|
37
72
|
|
|
38
73
|
/**
|
|
39
74
|
* Save a backup blob to disk via the File System Access API, else a download.
|
|
@@ -62,4 +97,4 @@ declare function datedName(filename: string, when?: Date): string;
|
|
|
62
97
|
/** Prompt the user to pick a backup file from disk. Resolves null if cancelled. */
|
|
63
98
|
declare function pickFromDisk(): Promise<File | null>;
|
|
64
99
|
|
|
65
|
-
export {
|
|
100
|
+
export { type GisDriveAuthOptions as G, type GisTokenPersistence as a, inspect as b, isEncrypted as c, datedName as d, exportSnapshot as e, changePassword as f, gisDriveAuth as g, importSnapshot as i, pickFromDisk as p, saveToDisk as s };
|
package/dist/widgets.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { F as FlowHost, S as StoreLike, C as ConnectTargets, a as ConnectFlowOptions, b as ConnectKind, c as ConnectFlow, d as ShareEngine, e as ShareLevel, f as ShareFlow, J as JoinEngine, g as JoinFlow, R as ReplicaFlow } from './flows-
|
|
1
|
+
import { F as FlowHost, S as StoreLike, C as ConnectTargets, a as ConnectFlowOptions, b as ConnectKind, c as ConnectFlow, d as ShareEngine, e as ShareLevel, f as ShareFlow, J as JoinEngine, g as JoinFlow, R as ReplicaFlow } from './flows-vX9zy9bI.js';
|
|
2
2
|
import { f as BackupsManager } from './manager-DZ1c_aSS.js';
|
|
3
3
|
import './store-BiQ-BuVl.js';
|
|
4
4
|
import './cache-ilsK3Tki.js';
|
|
@@ -127,6 +127,15 @@ declare class SelfstoreConnectElement extends FlowWidget {
|
|
|
127
127
|
attributeChangedCallback(name: string, _old: string | null, value: string | null): void;
|
|
128
128
|
connectedCallback(): void;
|
|
129
129
|
private wire;
|
|
130
|
+
/**
|
|
131
|
+
* The destination choice: the way back first, then a rule, then the ways
|
|
132
|
+
* forward.
|
|
133
|
+
*
|
|
134
|
+
* Its own method because `view` covers every step of the journey and was at
|
|
135
|
+
* the complexity cap; this is the step that keeps growing, since it is the
|
|
136
|
+
* one the host shapes.
|
|
137
|
+
*/
|
|
138
|
+
private viewChoose;
|
|
130
139
|
protected view(into: HTMLElement): void;
|
|
131
140
|
/**
|
|
132
141
|
* A form field that keeps its name once you start typing.
|
|
@@ -137,6 +146,15 @@ declare class SelfstoreConnectElement extends FlowWidget {
|
|
|
137
146
|
* never a label.
|
|
138
147
|
*/
|
|
139
148
|
private labelled;
|
|
149
|
+
/**
|
|
150
|
+
* The destination this device already used, first and on its own.
|
|
151
|
+
*
|
|
152
|
+
* It carries the same shape as an ordinary card so nothing new has to be
|
|
153
|
+
* styled, and the host's icon for that kind, so it reads as the same place
|
|
154
|
+
* rather than a fourth option. Its second line names WHICH backup - without
|
|
155
|
+
* that, "resume my backup" is one more thing to wonder about.
|
|
156
|
+
*/
|
|
157
|
+
private resumeCard;
|
|
140
158
|
private destCard;
|
|
141
159
|
/** The grouped "your own server" card shown when both WebDAV and S3 are
|
|
142
160
|
* offered: one entry into the tabbed form, opening on the first server kind. */
|
package/dist/widgets.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { saveToDisk, datedName } from './chunk-DCEXWSM6.js';
|
|
2
|
-
import { connectFlow, shareFlow, joinFlow } from './chunk-
|
|
2
|
+
import { connectFlow, shareFlow, joinFlow } from './chunk-LKIRWVXM.js';
|
|
3
3
|
import { isOpenSupported } from './chunk-TKWU52LK.js';
|
|
4
4
|
import './chunk-W22V5CRM.js';
|
|
5
5
|
import './chunk-J5MFXJU6.js';
|
|
@@ -81,6 +81,24 @@ button[part~='dot-button'] {
|
|
|
81
81
|
}
|
|
82
82
|
button[part~='card'] { cursor: pointer; font: inherit; color: inherit; }
|
|
83
83
|
button[part~='card']:hover { border-color: var(--_accent); }
|
|
84
|
+
/* The rule between "go back to what you had" and "start something new". A word
|
|
85
|
+
sits in the gap rather than beside it, so the two groups read as two even
|
|
86
|
+
before either is read. */
|
|
87
|
+
[part~='separator'] {
|
|
88
|
+
display: flex;
|
|
89
|
+
align-items: center;
|
|
90
|
+
gap: 0.7rem;
|
|
91
|
+
margin: 0.15rem 0;
|
|
92
|
+
color: var(--_ink-dim);
|
|
93
|
+
font-size: 0.85em;
|
|
94
|
+
}
|
|
95
|
+
[part~='separator']::before,
|
|
96
|
+
[part~='separator']::after {
|
|
97
|
+
content: '';
|
|
98
|
+
flex: 1;
|
|
99
|
+
height: 1px;
|
|
100
|
+
background: var(--_border);
|
|
101
|
+
}
|
|
84
102
|
img[part~='icon'] {
|
|
85
103
|
width: var(--selfstore-icon-size, 2.1em);
|
|
86
104
|
height: var(--selfstore-icon-size, 2.1em);
|
|
@@ -487,6 +505,10 @@ var FlowWidget = class extends HTMLElement {
|
|
|
487
505
|
var EN = {
|
|
488
506
|
"connect.title": "Where should we save your data?",
|
|
489
507
|
"connect.recommended": "Recommended",
|
|
508
|
+
// The way back, and the rule under it. A host that can name the destination
|
|
509
|
+
// overrides this with something less abstract ("Resume my Google Drive").
|
|
510
|
+
"connect.resume": "Resume my backup",
|
|
511
|
+
"connect.or": "or",
|
|
490
512
|
"connect.drive": "Google Drive",
|
|
491
513
|
"connect.drive.sub": "Available on all your devices",
|
|
492
514
|
"connect.file": "A file on this device",
|
|
@@ -548,6 +570,8 @@ var EN = {
|
|
|
548
570
|
var FR = {
|
|
549
571
|
"connect.title": "O\xF9 enregistrer vos donn\xE9es ?",
|
|
550
572
|
"connect.recommended": "Recommand\xE9",
|
|
573
|
+
"connect.resume": "Reprendre ma sauvegarde",
|
|
574
|
+
"connect.or": "ou",
|
|
551
575
|
"connect.drive": "Google Drive",
|
|
552
576
|
"connect.drive.sub": "Disponible sur tous vos appareils",
|
|
553
577
|
"connect.file": "Un fichier sur cet appareil",
|
|
@@ -755,39 +779,54 @@ var SelfstoreConnectElement = class extends FlowWidget {
|
|
|
755
779
|
this.rerender();
|
|
756
780
|
});
|
|
757
781
|
}
|
|
782
|
+
/**
|
|
783
|
+
* The destination choice: the way back first, then a rule, then the ways
|
|
784
|
+
* forward.
|
|
785
|
+
*
|
|
786
|
+
* Its own method because `view` covers every step of the journey and was at
|
|
787
|
+
* the complexity cap; this is the step that keeps growing, since it is the
|
|
788
|
+
* one the host shapes.
|
|
789
|
+
*/
|
|
790
|
+
viewChoose(into, s) {
|
|
791
|
+
put(into, this.heading("title", "connect.title"));
|
|
792
|
+
const offer = this.#options.resume;
|
|
793
|
+
if (offer) {
|
|
794
|
+
into.append(this.resumeCard(offer));
|
|
795
|
+
into.append(h("div", { part: "separator" }, h("span", {}, this.t("connect.or"))));
|
|
796
|
+
}
|
|
797
|
+
const serverKinds = ["webdav", "s3"].filter(
|
|
798
|
+
(k) => s.kinds.includes(k) && !this.#advanced.includes(k)
|
|
799
|
+
);
|
|
800
|
+
const groupServer = serverKinds.length >= 2;
|
|
801
|
+
for (const kind of s.kinds) {
|
|
802
|
+
if (this.#advanced.includes(kind)) continue;
|
|
803
|
+
if (groupServer && (kind === "webdav" || kind === "s3")) {
|
|
804
|
+
if (kind === serverKinds[0]) into.append(this.serverCard(serverKinds[0]));
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
into.append(this.destCard(kind));
|
|
808
|
+
}
|
|
809
|
+
for (const kind of s.kinds) {
|
|
810
|
+
if (!this.#advanced.includes(kind)) continue;
|
|
811
|
+
into.append(
|
|
812
|
+
h(
|
|
813
|
+
"button",
|
|
814
|
+
{
|
|
815
|
+
part: "link advanced-link",
|
|
816
|
+
"data-kind": kind,
|
|
817
|
+
onclick: () => this.#flow?.choose(kind)
|
|
818
|
+
},
|
|
819
|
+
this.t(`connect.${kind}`)
|
|
820
|
+
)
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
758
824
|
view(into) {
|
|
759
825
|
const flow = this.#flow;
|
|
760
826
|
if (!flow) return;
|
|
761
827
|
const s = flow.snapshot;
|
|
762
828
|
if (s.step === "choose") {
|
|
763
|
-
|
|
764
|
-
const serverKinds = ["webdav", "s3"].filter(
|
|
765
|
-
(k) => s.kinds.includes(k) && !this.#advanced.includes(k)
|
|
766
|
-
);
|
|
767
|
-
const groupServer = serverKinds.length >= 2;
|
|
768
|
-
for (const kind of s.kinds) {
|
|
769
|
-
if (this.#advanced.includes(kind)) continue;
|
|
770
|
-
if (groupServer && (kind === "webdav" || kind === "s3")) {
|
|
771
|
-
if (kind === serverKinds[0]) into.append(this.serverCard(serverKinds[0]));
|
|
772
|
-
continue;
|
|
773
|
-
}
|
|
774
|
-
into.append(this.destCard(kind));
|
|
775
|
-
}
|
|
776
|
-
for (const kind of s.kinds) {
|
|
777
|
-
if (this.#advanced.includes(kind)) {
|
|
778
|
-
into.append(
|
|
779
|
-
h(
|
|
780
|
-
"button",
|
|
781
|
-
{
|
|
782
|
-
part: "link advanced-link",
|
|
783
|
-
"data-kind": kind,
|
|
784
|
-
onclick: () => this.#flow?.choose(kind)
|
|
785
|
-
},
|
|
786
|
-
this.t(`connect.${kind}`)
|
|
787
|
-
)
|
|
788
|
-
);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
829
|
+
this.viewChoose(into, s);
|
|
791
830
|
return;
|
|
792
831
|
}
|
|
793
832
|
if (s.step === "form") {
|
|
@@ -962,6 +1001,30 @@ var SelfstoreConnectElement = class extends FlowWidget {
|
|
|
962
1001
|
labelled(labelKey, input) {
|
|
963
1002
|
return h("label", { part: "labelled" }, h("span", { part: "label" }, this.t(labelKey)), input);
|
|
964
1003
|
}
|
|
1004
|
+
/**
|
|
1005
|
+
* The destination this device already used, first and on its own.
|
|
1006
|
+
*
|
|
1007
|
+
* It carries the same shape as an ordinary card so nothing new has to be
|
|
1008
|
+
* styled, and the host's icon for that kind, so it reads as the same place
|
|
1009
|
+
* rather than a fourth option. Its second line names WHICH backup - without
|
|
1010
|
+
* that, "resume my backup" is one more thing to wonder about.
|
|
1011
|
+
*/
|
|
1012
|
+
resumeCard(offer) {
|
|
1013
|
+
const icon = this.#icons[offer.kind] ?? defaultIcons[offer.kind];
|
|
1014
|
+
const head = icon ? h("img", { part: "icon", src: icon, alt: "" }) : null;
|
|
1015
|
+
const title = h("div", { part: "title" }, this.t("connect.resume"));
|
|
1016
|
+
const sub = offer.detail ? h("div", { part: "sub" }, offer.detail) : null;
|
|
1017
|
+
return h(
|
|
1018
|
+
"button",
|
|
1019
|
+
{
|
|
1020
|
+
part: "card resume-card",
|
|
1021
|
+
"data-kind": offer.kind,
|
|
1022
|
+
onclick: () => this.#flow?.resume()
|
|
1023
|
+
},
|
|
1024
|
+
head,
|
|
1025
|
+
h("div", {}, title, sub)
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
965
1028
|
destCard(kind) {
|
|
966
1029
|
const icon = this.#icons[kind] ?? defaultIcons[kind];
|
|
967
1030
|
const head = icon ? h("img", { part: "icon", src: icon, alt: "" }) : null;
|