@duplicati/ngclient 0.0.1 → 0.0.6
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/chunk-22HCWJS5.js +1 -0
- package/chunk-24PLBY6C.js +1 -0
- package/chunk-3MM4GLBS.js +1 -0
- package/chunk-3MTW6FJP.js +1 -0
- package/chunk-4FK75Z4C.js +1 -0
- package/chunk-4MMHXTNF.js +1 -0
- package/chunk-57M4MADC.js +1 -0
- package/chunk-6XUWDRDE.js +1 -0
- package/chunk-77NTMJCT.js +1 -0
- package/chunk-7X6SBNMU.js +1 -0
- package/chunk-A66Z6362.js +1 -0
- package/chunk-AC6VDRLC.js +1 -0
- package/chunk-BNNZKRIC.js +1 -0
- package/chunk-CKPPU3GS.js +2 -0
- package/chunk-DYANEO5K.js +1 -0
- package/chunk-GJTW7UUU.js +1 -0
- package/chunk-GMANGOGH.js +1 -0
- package/chunk-I6QIKK6M.js +1 -0
- package/chunk-IOWSWUHM.js +1 -0
- package/chunk-IQSBPGVL.js +1 -0
- package/chunk-L47VTK2X.js +1 -0
- package/chunk-LVLU6MPQ.js +1 -0
- package/chunk-N5US3SKW.js +1 -0
- package/chunk-NIMPOFJV.js +1 -0
- package/chunk-ORDBF5MR.js +8 -0
- package/chunk-PH6AAOK4.js +1 -0
- package/chunk-PY5HJ5U2.js +1 -0
- package/chunk-QQDSFTZV.js +1 -0
- package/chunk-RANWFSNY.js +1 -0
- package/chunk-RLJJFBQ2.js +1 -0
- package/chunk-S76TN27U.js +1 -0
- package/chunk-UTPCUNNU.js +1 -0
- package/chunk-VPEVWKGB.js +1 -0
- package/chunk-VVUYO7E4.js +1 -0
- package/chunk-WLI4RZYL.js +1 -0
- package/chunk-X2NZ4CJ5.js +2 -0
- package/chunk-XU7PNEZO.js +1 -0
- package/chunk-XYJYUMYL.js +1 -0
- package/chunk-YRXI477O.js +1 -0
- package/chunk-ZD3JEKWI.js +1 -0
- package/index.html +15 -0
- package/main-5KJRELCN.js +1 -0
- package/package.json +3 -40
- package/sparkle-ui-assets/fonts/InterTight-VariableFont_wght.ttf +0 -0
- package/sparkle-ui-assets/fonts/InterTight-VariableFont_wght.woff2 +0 -0
- package/styles-6W7ZCKNM.css +1 -0
- package/.dockerignore +0 -13
- package/.github/workflows/npm-publish.yml +0 -59
- package/.prettierignore +0 -13
- package/.prettierrc +0 -12
- package/.vscode/extensions.json +0 -4
- package/.vscode/launch.json +0 -13
- package/.vscode/settings.json +0 -8
- package/.vscode/tasks.json +0 -24
- package/Dockerfile +0 -38
- package/LICENSE +0 -21
- package/README.md +0 -27
- package/angular.json +0 -98
- package/bun.lockb +0 -0
- package/openapi-ts.config.ts +0 -13
- package/scripts/generate-package-json.ts +0 -15
- package/src/app/about/about.component.html +0 -15
- package/src/app/about/about.component.scss +0 -19
- package/src/app/about/about.component.ts +0 -13
- package/src/app/about/changelog/changelog.component.html +0 -3
- package/src/app/about/changelog/changelog.component.scss +0 -7
- package/src/app/about/changelog/changelog.component.ts +0 -18
- package/src/app/about/general/general.component.html +0 -9
- package/src/app/about/general/general.component.scss +0 -23
- package/src/app/about/general/general.component.ts +0 -30
- package/src/app/about/libraries/libraries.component.html +0 -3
- package/src/app/about/libraries/libraries.component.scss +0 -7
- package/src/app/about/libraries/libraries.component.ts +0 -18
- package/src/app/about/logs/logs.component.html +0 -5
- package/src/app/about/logs/logs.component.scss +0 -7
- package/src/app/about/logs/logs.component.ts +0 -18
- package/src/app/about/system-info/system-info.component.html +0 -3
- package/src/app/about/system-info/system-info.component.scss +0 -7
- package/src/app/about/system-info/system-info.component.ts +0 -17
- package/src/app/add-backup/add-backup.component.html +0 -29
- package/src/app/add-backup/add-backup.component.scss +0 -38
- package/src/app/add-backup/add-backup.component.ts +0 -14
- package/src/app/app.component.ts +0 -35
- package/src/app/app.config.ts +0 -23
- package/src/app/app.routes.ts +0 -121
- package/src/app/core/components/file-tree/file-tree.component.html +0 -87
- package/src/app/core/components/file-tree/file-tree.component.scss +0 -80
- package/src/app/core/components/file-tree/file-tree.component.ts +0 -485
- package/src/app/core/components/logo/logo.component.html +0 -22
- package/src/app/core/components/logo/logo.component.scss +0 -12
- package/src/app/core/components/logo/logo.component.ts +0 -11
- package/src/app/core/components/status-bar/status-bar.component.html +0 -38
- package/src/app/core/components/status-bar/status-bar.component.scss +0 -27
- package/src/app/core/components/status-bar/status-bar.component.ts +0 -33
- package/src/app/core/components/status-bar/status-bar.state.ts +0 -182
- package/src/app/core/components/toggle-card/toggle-card.component.html +0 -11
- package/src/app/core/components/toggle-card/toggle-card.component.scss +0 -49
- package/src/app/core/components/toggle-card/toggle-card.component.ts +0 -28
- package/src/app/core/interceptors/http.interceptor.ts +0 -69
- package/src/app/core/interceptors/websocket.interceptor.ts +0 -66
- package/src/app/core/openapi/core/ApiError.ts +0 -21
- package/src/app/core/openapi/core/ApiRequestOptions.ts +0 -21
- package/src/app/core/openapi/core/ApiResult.ts +0 -7
- package/src/app/core/openapi/core/OpenAPI.ts +0 -55
- package/src/app/core/openapi/core/request.ts +0 -337
- package/src/app/core/openapi/index.ts +0 -6
- package/src/app/core/openapi/schemas.gen.ts +0 -3611
- package/src/app/core/openapi/services.gen.ts +0 -1460
- package/src/app/core/openapi/types.gen.ts +0 -1510
- package/src/app/core/pipes/duration.pipe.ts +0 -27
- package/src/app/core/pipes/relative-time.pipe.ts +0 -14
- package/src/app/core/providers/dayjs.ts +0 -16
- package/src/app/core/services/dict.en.ts +0 -0
- package/src/app/core/services/dictionary.service.ts +0 -12
- package/src/app/core/services/localstorage.token.ts +0 -82
- package/src/app/core/services/password-generator.service.ts +0 -39
- package/src/app/core/services/relay-websocket.service.ts +0 -268
- package/src/app/core/services/timespan-literals.service.ts +0 -25
- package/src/app/core/states/app-auth.state.ts +0 -87
- package/src/app/core/states/backups.state.ts +0 -71
- package/src/app/core/states/relayconfig.state.ts +0 -23
- package/src/app/core/states/sysinfo.state.ts +0 -31
- package/src/app/core/states/tasks.state.ts +0 -34
- package/src/app/core/types/subscribed.ts +0 -7
- package/src/app/core/validators/custom.validators.ts +0 -120
- package/src/app/create-edit-backup/create-edit-backup.component.html +0 -28
- package/src/app/create-edit-backup/create-edit-backup.component.scss +0 -15
- package/src/app/create-edit-backup/create-edit-backup.component.ts +0 -33
- package/src/app/create-edit-backup/create-edit-backup.state.ts +0 -582
- package/src/app/create-edit-backup/destination/destination.component.html +0 -367
- package/src/app/create-edit-backup/destination/destination.component.scss +0 -85
- package/src/app/create-edit-backup/destination/destination.component.ts +0 -249
- package/src/app/create-edit-backup/destination/destination.config.ts +0 -103
- package/src/app/create-edit-backup/destination/destination.mapper.ts +0 -177
- package/src/app/create-edit-backup/general/general.component.html +0 -108
- package/src/app/create-edit-backup/general/general.component.scss +0 -34
- package/src/app/create-edit-backup/general/general.component.ts +0 -136
- package/src/app/create-edit-backup/options/options.component.html +0 -95
- package/src/app/create-edit-backup/options/options.component.scss +0 -42
- package/src/app/create-edit-backup/options/options.component.ts +0 -113
- package/src/app/create-edit-backup/schedule/schedule.component.html +0 -102
- package/src/app/create-edit-backup/schedule/schedule.component.scss +0 -38
- package/src/app/create-edit-backup/schedule/schedule.component.ts +0 -137
- package/src/app/create-edit-backup/source-data/source-data.component.html +0 -93
- package/src/app/create-edit-backup/source-data/source-data.component.scss +0 -41
- package/src/app/create-edit-backup/source-data/source-data.component.ts +0 -114
- package/src/app/home/backup.const.ts +0 -167
- package/src/app/home/home.component.html +0 -98
- package/src/app/home/home.component.scss +0 -88
- package/src/app/home/home.component.ts +0 -54
- package/src/app/layout/layout.component.html +0 -64
- package/src/app/layout/layout.component.scss +0 -24
- package/src/app/layout/layout.component.ts +0 -51
- package/src/app/layout/layout.state.ts +0 -70
- package/src/app/login/login.component.html +0 -12
- package/src/app/login/login.component.scss +0 -25
- package/src/app/login/login.component.ts +0 -34
- package/src/app/logout/logout.component.html +0 -1
- package/src/app/logout/logout.component.scss +0 -3
- package/src/app/logout/logout.component.ts +0 -18
- package/src/app/restore/restore.component.html +0 -56
- package/src/app/restore/restore.component.scss +0 -37
- package/src/app/restore/restore.component.ts +0 -55
- package/src/app/restore-flow/options/options.component.html +0 -57
- package/src/app/restore-flow/options/options.component.scss +0 -16
- package/src/app/restore-flow/options/options.component.ts +0 -58
- package/src/app/restore-flow/restore-flow.component.html +0 -14
- package/src/app/restore-flow/restore-flow.component.scss +0 -15
- package/src/app/restore-flow/restore-flow.component.ts +0 -23
- package/src/app/restore-flow/restore-flow.state.ts +0 -120
- package/src/app/restore-flow/select-files/select-files.component.html +0 -42
- package/src/app/restore-flow/select-files/select-files.component.scss +0 -16
- package/src/app/restore-flow/select-files/select-files.component.ts +0 -129
- package/src/app/settings/settings.component.html +0 -256
- package/src/app/settings/settings.component.scss +0 -106
- package/src/app/settings/settings.component.ts +0 -475
- package/src/environments/environment-token.ts +0 -4
- package/src/environments/environment.prod.ts +0 -6
- package/src/environments/environment.ts +0 -6
- package/src/index.html +0 -15
- package/src/main.ts +0 -6
- package/src/proxy.conf.mjs +0 -6
- package/src/styles.scss +0 -41
- package/tsconfig.app.json +0 -15
- package/tsconfig.json +0 -30
- /package/{src/assets → assets}/duplicati-logo.png +0 -0
- /package/{src/assets → assets}/duplicati-logo.svg +0 -0
- /package/{src/assets → assets}/favicon.ico +0 -0
- /package/{src/assets → assets}/images/backup.png +0 -0
- /package/{src/assets → assets}/images/dark-theme.png +0 -0
- /package/{src/assets → assets}/images/folder.png +0 -0
- /package/{src/assets → assets}/images/light-theme.png +0 -0
- /package/{src/assets → assets}/images/new-backup.png +0 -0
- /package/{src/assets → assets}/images/restore.png +0 -0
- /package/{src/assets → assets}/images/system-theme.png +0 -0
- /package/{src/assets → assets}/spk.css +0 -0
- /package/{src/assets → assets}/spk.woff2 +0 -0
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
|
2
|
-
import { AppAuthState } from '../core/states/app-auth.state';
|
|
3
|
-
|
|
4
|
-
@Component({
|
|
5
|
-
selector: 'app-logout',
|
|
6
|
-
standalone: true,
|
|
7
|
-
imports: [],
|
|
8
|
-
templateUrl: './logout.component.html',
|
|
9
|
-
styleUrl: './logout.component.scss',
|
|
10
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
11
|
-
})
|
|
12
|
-
export default class LogoutComponent {
|
|
13
|
-
#auth = inject(AppAuthState);
|
|
14
|
-
|
|
15
|
-
ngOnInit() {
|
|
16
|
-
this.#auth.logout();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
<app-status-bar />
|
|
2
|
-
|
|
3
|
-
<section>
|
|
4
|
-
<h2>Where do you want to restore from?</h2>
|
|
5
|
-
|
|
6
|
-
<!-- <spk-card class="type-a">
|
|
7
|
-
<img src="/assets/images/backup.png" alt="" width="48px" />
|
|
8
|
-
<div class="text">
|
|
9
|
-
<h3>Direct restore from backup files</h3>
|
|
10
|
-
<p>Point to your backup files and restore from there.</p>
|
|
11
|
-
</div>
|
|
12
|
-
<button spk-button [routerLink]="['/restore-flow']">
|
|
13
|
-
Start
|
|
14
|
-
<spk-icon>play-circle</spk-icon>
|
|
15
|
-
</button>
|
|
16
|
-
</spk-card> -->
|
|
17
|
-
|
|
18
|
-
<!-- <spk-card class="type-a">
|
|
19
|
-
<img src="/assets/images/restore.png" alt="" width="48px" />
|
|
20
|
-
<div class="text">
|
|
21
|
-
<h3>Restore from configuration</h3>
|
|
22
|
-
<p>Load destination from an exported job or a storage provider</p>
|
|
23
|
-
</div>
|
|
24
|
-
<button spk-button>
|
|
25
|
-
Start
|
|
26
|
-
<spk-icon>play-circle</spk-icon>
|
|
27
|
-
</button>
|
|
28
|
-
</spk-card>
|
|
29
|
-
|
|
30
|
-
<spk-divider>Or existing</spk-divider> -->
|
|
31
|
-
|
|
32
|
-
@if (backupsLoading()) {
|
|
33
|
-
<spk-progress-bar class="indeterminate primary"></spk-progress-bar>
|
|
34
|
-
} @else if (backups().length) {
|
|
35
|
-
@for (backup of backups(); track $index) {
|
|
36
|
-
<spk-card class="type-a">
|
|
37
|
-
<img src="/assets/images/folder.png" alt="" width="48px" />
|
|
38
|
-
|
|
39
|
-
<div class="text">
|
|
40
|
-
<h3>Restore {{ backup.Backup?.Name ?? 'Backup name missing' }}</h3>
|
|
41
|
-
<p>
|
|
42
|
-
{{ backup.Backup?.Metadata?.['SourceSizeString'] ?? '-' }} /
|
|
43
|
-
{{ backup.Backup?.Metadata?.['BackupListCount'] ?? '-' }}
|
|
44
|
-
</p>
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
<button spk-button [routerLink]="['/restore-flow', backup.Backup?.ID]">
|
|
48
|
-
Restore
|
|
49
|
-
<spk-icon>arrow-right</spk-icon>
|
|
50
|
-
</button>
|
|
51
|
-
</spk-card>
|
|
52
|
-
}
|
|
53
|
-
} @else {
|
|
54
|
-
No backups found
|
|
55
|
-
}
|
|
56
|
-
</section>
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
@use '@sparkle-ui/core/styles/helpers' as *;
|
|
2
|
-
|
|
3
|
-
:host {
|
|
4
|
-
display: block;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
h2 {
|
|
8
|
-
font: var(--title-30);
|
|
9
|
-
text-align: center;
|
|
10
|
-
padding: p2r(32);
|
|
11
|
-
}
|
|
12
|
-
section {
|
|
13
|
-
max-width: p2r(700);
|
|
14
|
-
margin: 0 auto;
|
|
15
|
-
padding: p2r(32 0);
|
|
16
|
-
display: flex;
|
|
17
|
-
flex-direction: column;
|
|
18
|
-
gap: p2r(16);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
spk-divider {
|
|
22
|
-
color: var(--base-level-60);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
spk-card {
|
|
26
|
-
display: flex;
|
|
27
|
-
align-items: center;
|
|
28
|
-
gap: p2r(16);
|
|
29
|
-
--card-padding: #{p2r(32)};
|
|
30
|
-
|
|
31
|
-
.text {
|
|
32
|
-
flex: 1 0;
|
|
33
|
-
display: flex;
|
|
34
|
-
flex-direction: column;
|
|
35
|
-
gap: p2r(4);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
|
2
|
-
import { RouterLink } from '@angular/router';
|
|
3
|
-
import {
|
|
4
|
-
SparkleButtonComponent,
|
|
5
|
-
SparkleCardComponent,
|
|
6
|
-
SparkleDividerComponent,
|
|
7
|
-
SparkleIconComponent,
|
|
8
|
-
SparkleProgressBarComponent,
|
|
9
|
-
} from '@sparkle-ui/core';
|
|
10
|
-
import StatusBarComponent from '../core/components/status-bar/status-bar.component';
|
|
11
|
-
import { BackupAndScheduleOutputDto, DuplicatiServerService } from '../core/openapi';
|
|
12
|
-
import { BackupsState } from '../core/states/backups.state';
|
|
13
|
-
|
|
14
|
-
@Component({
|
|
15
|
-
selector: 'app-restore',
|
|
16
|
-
standalone: true,
|
|
17
|
-
imports: [
|
|
18
|
-
StatusBarComponent,
|
|
19
|
-
SparkleCardComponent,
|
|
20
|
-
SparkleButtonComponent,
|
|
21
|
-
SparkleDividerComponent,
|
|
22
|
-
SparkleIconComponent,
|
|
23
|
-
SparkleProgressBarComponent,
|
|
24
|
-
RouterLink,
|
|
25
|
-
],
|
|
26
|
-
templateUrl: './restore.component.html',
|
|
27
|
-
styleUrl: './restore.component.scss',
|
|
28
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
29
|
-
})
|
|
30
|
-
export default class RestoreComponent {
|
|
31
|
-
#backupsState = inject(BackupsState);
|
|
32
|
-
#dupServer = inject(DuplicatiServerService);
|
|
33
|
-
|
|
34
|
-
backups = this.#backupsState.backups;
|
|
35
|
-
backupsLoading = this.#backupsState.backupsLoading;
|
|
36
|
-
|
|
37
|
-
ngOnInit() {
|
|
38
|
-
this.#backupsState.getBackups();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
restoreNow(backup: BackupAndScheduleOutputDto) {
|
|
42
|
-
this.#dupServer.postApiV1BackupByIdRestore({
|
|
43
|
-
id: backup.Backup?.ID!,
|
|
44
|
-
requestBody: {
|
|
45
|
-
// paths?: Array<(string)> | null;
|
|
46
|
-
// passphrase?: (string) | null;
|
|
47
|
-
// time?: (string) | null;
|
|
48
|
-
// restore_path?: (string) | null;
|
|
49
|
-
// overwrite?: (boolean) | null;
|
|
50
|
-
// permissions?: (boolean) | null;
|
|
51
|
-
// skip_metadata?: (boolean) | null;
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
<form [formGroup]="optionsForm" #formRef (submit)="submit()">
|
|
2
|
-
<h3 class="title-30">Restore options</h3>
|
|
3
|
-
|
|
4
|
-
<app-toggle-card [disallowToggle]="true">
|
|
5
|
-
<ng-container title>Where do you want to restore files from?</ng-container>
|
|
6
|
-
|
|
7
|
-
<spk-radio class="raised primary">
|
|
8
|
-
Original location
|
|
9
|
-
<input type="radio" name="restoreFrom" value="orignal" formControlName="restoreFrom" />
|
|
10
|
-
</spk-radio>
|
|
11
|
-
|
|
12
|
-
<spk-radio class="raised primary">
|
|
13
|
-
Pick location
|
|
14
|
-
<input type="radio" name="restoreFrom" value="pickLocation" formControlName="restoreFrom" />
|
|
15
|
-
</spk-radio>
|
|
16
|
-
|
|
17
|
-
<app-file-tree [disabled]="optionsFormSignal()?.restoreFrom !== 'pickLocation'">
|
|
18
|
-
<label for="path">Path</label>
|
|
19
|
-
<input type="text" id="path" formControlName="restoreFromPath" />
|
|
20
|
-
</app-file-tree>
|
|
21
|
-
</app-toggle-card>
|
|
22
|
-
|
|
23
|
-
<app-toggle-card [disallowToggle]="true">
|
|
24
|
-
<ng-container title>How do you want to handle existing files?</ng-container>
|
|
25
|
-
|
|
26
|
-
<spk-radio class="raised primary">
|
|
27
|
-
Overwrite
|
|
28
|
-
<input type="radio" name="handleExisting" value="overwrite" formControlName="handleExisting" />
|
|
29
|
-
</spk-radio>
|
|
30
|
-
|
|
31
|
-
<spk-radio class="raised primary">
|
|
32
|
-
Save different versions with timestamp in file name
|
|
33
|
-
<input type="radio" name="handleExisting" value="saveTimestamp" formControlName="handleExisting" />
|
|
34
|
-
</spk-radio>
|
|
35
|
-
</app-toggle-card>
|
|
36
|
-
|
|
37
|
-
<app-toggle-card>
|
|
38
|
-
<ng-container title>Permissions</ng-container>
|
|
39
|
-
|
|
40
|
-
<spk-toggle class="primary raised">
|
|
41
|
-
Restore read/write permissions
|
|
42
|
-
<input type="checkbox" formControlName="permissions" />
|
|
43
|
-
</spk-toggle>
|
|
44
|
-
</app-toggle-card>
|
|
45
|
-
|
|
46
|
-
<div class="form-actions">
|
|
47
|
-
<button spk-button type="button" (click)="goBack()">
|
|
48
|
-
<spk-icon>arrow-left</spk-icon>
|
|
49
|
-
Go back
|
|
50
|
-
</button>
|
|
51
|
-
|
|
52
|
-
<button spk-button class="raised primary" type="submit">
|
|
53
|
-
<spk-icon>arrow-right</spk-icon>
|
|
54
|
-
Submit
|
|
55
|
-
</button>
|
|
56
|
-
</div>
|
|
57
|
-
</form>
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
|
2
|
-
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
|
3
|
-
import { ActivatedRoute, Router } from '@angular/router';
|
|
4
|
-
import {
|
|
5
|
-
SparkleButtonComponent,
|
|
6
|
-
SparkleIconComponent,
|
|
7
|
-
SparkleRadioComponent,
|
|
8
|
-
SparkleToggleComponent,
|
|
9
|
-
} from '@sparkle-ui/core';
|
|
10
|
-
import FileTreeComponent from '../../core/components/file-tree/file-tree.component';
|
|
11
|
-
import ToggleCardComponent from '../../core/components/toggle-card/toggle-card.component';
|
|
12
|
-
import { RestoreFlowState } from '../restore-flow.state';
|
|
13
|
-
|
|
14
|
-
const fb = new FormBuilder();
|
|
15
|
-
|
|
16
|
-
export const createRestoreOptionsForm = () => {
|
|
17
|
-
return fb.group({
|
|
18
|
-
restoreFrom: fb.control<'orignal' | 'pickLocation'>('orignal'),
|
|
19
|
-
restoreFromPath: fb.control<string>(''),
|
|
20
|
-
handleExisting: fb.control<'overwrite' | 'saveTimestamp'>('overwrite'),
|
|
21
|
-
permissions: fb.control<boolean>(false),
|
|
22
|
-
});
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
@Component({
|
|
26
|
-
selector: 'app-options',
|
|
27
|
-
standalone: true,
|
|
28
|
-
imports: [
|
|
29
|
-
ReactiveFormsModule,
|
|
30
|
-
|
|
31
|
-
ToggleCardComponent,
|
|
32
|
-
FileTreeComponent,
|
|
33
|
-
|
|
34
|
-
SparkleToggleComponent,
|
|
35
|
-
SparkleRadioComponent,
|
|
36
|
-
SparkleButtonComponent,
|
|
37
|
-
SparkleIconComponent,
|
|
38
|
-
],
|
|
39
|
-
templateUrl: './options.component.html',
|
|
40
|
-
styleUrl: './options.component.scss',
|
|
41
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
42
|
-
})
|
|
43
|
-
export default class OptionsComponent {
|
|
44
|
-
#restoreFlowState = inject(RestoreFlowState);
|
|
45
|
-
#router = inject(Router);
|
|
46
|
-
#route = inject(ActivatedRoute);
|
|
47
|
-
|
|
48
|
-
optionsForm = this.#restoreFlowState.optionsForm;
|
|
49
|
-
optionsFormSignal = this.#restoreFlowState.optionsFormSignal;
|
|
50
|
-
|
|
51
|
-
goBack() {
|
|
52
|
-
this.#router.navigate(['select-files'], { relativeTo: this.#route.parent });
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
submit() {
|
|
56
|
-
this.#restoreFlowState.submit();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<spk-stepper>
|
|
2
|
-
<div spk-step routerLinkActive="active" [routerLink]="['/restore-flow', backupId(), 'select-files']">
|
|
3
|
-
<spk-radio />
|
|
4
|
-
Select files
|
|
5
|
-
</div>
|
|
6
|
-
<div spk-step routerLinkActive="active" [routerLink]="['/restore-flow', backupId(), 'options']">
|
|
7
|
-
<spk-radio />
|
|
8
|
-
Options
|
|
9
|
-
</div>
|
|
10
|
-
</spk-stepper>
|
|
11
|
-
|
|
12
|
-
<section>
|
|
13
|
-
<router-outlet />
|
|
14
|
-
</section>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
|
2
|
-
import { ActivatedRoute, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
|
|
3
|
-
import { SparkleRadioComponent, SparkleStepperComponent } from '@sparkle-ui/core';
|
|
4
|
-
import { RestoreFlowState } from './restore-flow.state';
|
|
5
|
-
|
|
6
|
-
@Component({
|
|
7
|
-
selector: 'app-restore-flow',
|
|
8
|
-
standalone: true,
|
|
9
|
-
imports: [SparkleStepperComponent, SparkleRadioComponent, RouterOutlet, RouterLink, RouterLinkActive],
|
|
10
|
-
templateUrl: './restore-flow.component.html',
|
|
11
|
-
styleUrl: './restore-flow.component.scss',
|
|
12
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
13
|
-
})
|
|
14
|
-
export default class RestoreFlowComponent {
|
|
15
|
-
#route = inject(ActivatedRoute);
|
|
16
|
-
#restoreFlowState = inject(RestoreFlowState);
|
|
17
|
-
|
|
18
|
-
backupId = this.#restoreFlowState.backupId;
|
|
19
|
-
|
|
20
|
-
ngOnInit() {
|
|
21
|
-
this.#restoreFlowState.init(this.#route.snapshot.params['id']);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { inject, Injectable, signal } from '@angular/core';
|
|
2
|
-
import { toSignal } from '@angular/core/rxjs-interop';
|
|
3
|
-
import { Router } from '@angular/router';
|
|
4
|
-
import { finalize, forkJoin, take } from 'rxjs';
|
|
5
|
-
import { DuplicatiServerService, GetBackupResultDto, IListResultFileset } from '../core/openapi';
|
|
6
|
-
import { createRestoreOptionsForm } from './options/options.component';
|
|
7
|
-
import { createRestoreSelectFilesForm } from './select-files/select-files.component';
|
|
8
|
-
|
|
9
|
-
@Injectable({
|
|
10
|
-
providedIn: 'root',
|
|
11
|
-
})
|
|
12
|
-
export class RestoreFlowState {
|
|
13
|
-
#router = inject(Router);
|
|
14
|
-
#dupServer = inject(DuplicatiServerService);
|
|
15
|
-
|
|
16
|
-
backupId = signal<'string' | null>(null);
|
|
17
|
-
backup = signal<GetBackupResultDto | null>(null);
|
|
18
|
-
selectFilesForm = createRestoreSelectFilesForm();
|
|
19
|
-
optionsForm = createRestoreOptionsForm();
|
|
20
|
-
optionsFormSignal = toSignal(this.optionsForm.valueChanges);
|
|
21
|
-
selectFilesFormSignal = toSignal(this.selectFilesForm.valueChanges);
|
|
22
|
-
versionOptionsLoading = signal(false);
|
|
23
|
-
versionOptions = signal<IListResultFileset[]>([]);
|
|
24
|
-
isSubmitting = signal(false);
|
|
25
|
-
|
|
26
|
-
init(id: 'string') {
|
|
27
|
-
this.backupId.set(id);
|
|
28
|
-
this.#getBackupData(id, true);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// restoreFrom: fb.control<'orignal' | 'pickLocation'>('orignal'),
|
|
32
|
-
// restoreFromPath: fb.control<string>(''),
|
|
33
|
-
// handleExisting: fb.control<'overwrite' | 'saveTimestamp'>('overwrite'),
|
|
34
|
-
// permissions: fb.control<boolean>(false),
|
|
35
|
-
// {
|
|
36
|
-
// "paths": [
|
|
37
|
-
// "string"
|
|
38
|
-
// ],
|
|
39
|
-
// "passphrase": "string",
|
|
40
|
-
// "time": "string",
|
|
41
|
-
// "restore_path": "string",
|
|
42
|
-
// "overwrite": true,
|
|
43
|
-
// "permissions": true,
|
|
44
|
-
// "skip_metadata": true
|
|
45
|
-
// }
|
|
46
|
-
submit() {
|
|
47
|
-
this.isSubmitting.set(true);
|
|
48
|
-
|
|
49
|
-
const id = this.backupId();
|
|
50
|
-
const optionsValue = this.optionsForm.value;
|
|
51
|
-
const selectFilesFormValue = this.selectFilesForm.value;
|
|
52
|
-
const selectedOption = this.versionOptions()?.find((x) => x.Version === selectFilesFormValue.selectedOption);
|
|
53
|
-
|
|
54
|
-
this.#dupServer
|
|
55
|
-
.postApiV1BackupByIdRestore({
|
|
56
|
-
id: id ?? '',
|
|
57
|
-
requestBody: {
|
|
58
|
-
paths: selectFilesFormValue.filesToRestore?.split('\0').map((x) => `${x}*`) ?? [],
|
|
59
|
-
passphrase: selectFilesFormValue.passphrase ?? null,
|
|
60
|
-
time: selectedOption?.Time,
|
|
61
|
-
restore_path: optionsValue.restoreFromPath,
|
|
62
|
-
overwrite: optionsValue.handleExisting === 'overwrite',
|
|
63
|
-
permissions: optionsValue.permissions,
|
|
64
|
-
skip_metadata: true,
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
.pipe(finalize(() => this.isSubmitting.set(false)))
|
|
68
|
-
.subscribe({
|
|
69
|
-
next: () => {
|
|
70
|
-
this.exit();
|
|
71
|
-
},
|
|
72
|
-
error: (err) => {
|
|
73
|
-
console.error('restore error', err);
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
exit() {
|
|
79
|
-
// TODOS
|
|
80
|
-
// - Are you sure dialog
|
|
81
|
-
this.#resetAllForms();
|
|
82
|
-
this.#router.navigate(['/']);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
getVersionOptions() {
|
|
86
|
-
this.versionOptions();
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
#getBackupData(id: string, setFirstToForm = false) {
|
|
90
|
-
this.versionOptionsLoading.set(true);
|
|
91
|
-
|
|
92
|
-
forkJoin([
|
|
93
|
-
this.#dupServer.getApiV1BackupById({
|
|
94
|
-
id,
|
|
95
|
-
}),
|
|
96
|
-
this.#dupServer.getApiV1BackupByIdFilesets({
|
|
97
|
-
id,
|
|
98
|
-
}),
|
|
99
|
-
])
|
|
100
|
-
.pipe(
|
|
101
|
-
take(1),
|
|
102
|
-
finalize(() => this.versionOptionsLoading.set(false))
|
|
103
|
-
)
|
|
104
|
-
.subscribe({
|
|
105
|
-
next: ([backup, filesets]) => {
|
|
106
|
-
this.versionOptions.set(filesets);
|
|
107
|
-
this.backup.set(backup);
|
|
108
|
-
|
|
109
|
-
if (setFirstToForm) {
|
|
110
|
-
this.selectFilesForm.controls.selectedOption.setValue(filesets[0].Version as number);
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
#resetAllForms() {
|
|
117
|
-
this.selectFilesForm.reset();
|
|
118
|
-
this.optionsForm.reset();
|
|
119
|
-
}
|
|
120
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
<form [formGroup]="selectFilesForm" #formRef (submit)="next()">
|
|
2
|
-
<h3 class="title-30">Select files</h3>
|
|
3
|
-
|
|
4
|
-
@if (versionOptionsLoading()) {
|
|
5
|
-
<spk-progress-bar class="indeterminate primary"></spk-progress-bar>
|
|
6
|
-
} @else {
|
|
7
|
-
<spk-select [displayFn]="displayFn()">
|
|
8
|
-
<input type="number" placeholder="Select an option..." formControlName="selectedOption" />
|
|
9
|
-
|
|
10
|
-
<ng-container options>
|
|
11
|
-
@for (option of versionOptions(); track $index) {
|
|
12
|
-
<option [value]="option.Version">{{ option.Version }}: {{ option.Time | date: 'd MMM y, h:mm' }}</option>
|
|
13
|
-
}
|
|
14
|
-
</ng-container>
|
|
15
|
-
</spk-select>
|
|
16
|
-
|
|
17
|
-
@if (rootPathLoaded()) {
|
|
18
|
-
<app-file-tree
|
|
19
|
-
[rootPath]="rootPath()"
|
|
20
|
-
[backupSettings]="backupSettings()"
|
|
21
|
-
[multiSelect]="true"
|
|
22
|
-
[showFiles]="true">
|
|
23
|
-
<label for="path">Path</label>
|
|
24
|
-
<input type="text" id="path" formControlName="filesToRestore" />
|
|
25
|
-
</app-file-tree>
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
<!-- <pre>{{ selectFilesFormSignal() | json }}</pre> -->
|
|
30
|
-
|
|
31
|
-
<div class="form-actions">
|
|
32
|
-
<button spk-button type="button" (click)="exit()">
|
|
33
|
-
<spk-icon>arrow-left</spk-icon>
|
|
34
|
-
Exit
|
|
35
|
-
</button>
|
|
36
|
-
|
|
37
|
-
<button spk-button class="raised primary" type="submit">
|
|
38
|
-
<spk-icon>arrow-right</spk-icon>
|
|
39
|
-
Continue
|
|
40
|
-
</button>
|
|
41
|
-
</div>
|
|
42
|
-
</form>
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { DatePipe, JsonPipe } from '@angular/common';
|
|
2
|
-
import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';
|
|
3
|
-
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
|
4
|
-
import { ActivatedRoute, Router } from '@angular/router';
|
|
5
|
-
import {
|
|
6
|
-
SparkleButtonComponent,
|
|
7
|
-
SparkleIconComponent,
|
|
8
|
-
SparkleProgressBarComponent,
|
|
9
|
-
SparkleSelectComponent,
|
|
10
|
-
} from '@sparkle-ui/core';
|
|
11
|
-
import { derivedFrom } from 'ngxtension/derived-from';
|
|
12
|
-
import { map, of, pipe, startWith, switchMap } from 'rxjs';
|
|
13
|
-
import FileTreeComponent from '../../core/components/file-tree/file-tree.component';
|
|
14
|
-
import { DuplicatiServerService } from '../../core/openapi';
|
|
15
|
-
import { RestoreFlowState } from '../restore-flow.state';
|
|
16
|
-
|
|
17
|
-
const fb = new FormBuilder();
|
|
18
|
-
|
|
19
|
-
export const createRestoreSelectFilesForm = () => {
|
|
20
|
-
return fb.group({
|
|
21
|
-
filesToRestore: fb.control<string>(''),
|
|
22
|
-
selectedOption: fb.control<number | null>(null),
|
|
23
|
-
passphrase: fb.control<string | null>(null),
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
@Component({
|
|
28
|
-
selector: 'app-select-files',
|
|
29
|
-
standalone: true,
|
|
30
|
-
imports: [
|
|
31
|
-
ReactiveFormsModule,
|
|
32
|
-
DatePipe,
|
|
33
|
-
JsonPipe,
|
|
34
|
-
|
|
35
|
-
FileTreeComponent,
|
|
36
|
-
|
|
37
|
-
SparkleButtonComponent,
|
|
38
|
-
SparkleIconComponent,
|
|
39
|
-
SparkleSelectComponent,
|
|
40
|
-
SparkleProgressBarComponent,
|
|
41
|
-
],
|
|
42
|
-
templateUrl: './select-files.component.html',
|
|
43
|
-
styleUrl: './select-files.component.scss',
|
|
44
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
45
|
-
providers: [DatePipe],
|
|
46
|
-
})
|
|
47
|
-
export default class SelectFilesComponent {
|
|
48
|
-
#dupServer = inject(DuplicatiServerService);
|
|
49
|
-
#restoreFlowState = inject(RestoreFlowState);
|
|
50
|
-
#router = inject(Router);
|
|
51
|
-
#route = inject(ActivatedRoute);
|
|
52
|
-
#datePipe = inject(DatePipe);
|
|
53
|
-
|
|
54
|
-
selectFilesForm = this.#restoreFlowState.selectFilesForm;
|
|
55
|
-
selectFilesFormSignal = this.#restoreFlowState.selectFilesFormSignal;
|
|
56
|
-
backupId = this.#restoreFlowState.backupId;
|
|
57
|
-
versionOptionsLoading = this.#restoreFlowState.versionOptionsLoading;
|
|
58
|
-
versionOptions = this.#restoreFlowState.versionOptions;
|
|
59
|
-
backupSettings = computed(() => {
|
|
60
|
-
const id = this.backupId();
|
|
61
|
-
const selectedOption = this.selectFilesFormSignal()?.selectedOption;
|
|
62
|
-
|
|
63
|
-
if (!(typeof selectedOption === 'number') || !id) return null;
|
|
64
|
-
|
|
65
|
-
const option = this.versionOptions()?.find((x) => x.Version === selectedOption);
|
|
66
|
-
const time = option?.Time ?? null;
|
|
67
|
-
|
|
68
|
-
if (!time) return null;
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
id,
|
|
72
|
-
time,
|
|
73
|
-
};
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
rootPathLoaded = signal(false);
|
|
77
|
-
rootPath = derivedFrom(
|
|
78
|
-
[this.selectFilesFormSignal, this.backupId],
|
|
79
|
-
pipe(
|
|
80
|
-
startWith([null, null]),
|
|
81
|
-
switchMap(([selectFilesFormSignal, backupId]) => {
|
|
82
|
-
const selectedOption = selectFilesFormSignal?.selectedOption;
|
|
83
|
-
const id = backupId;
|
|
84
|
-
|
|
85
|
-
if (!(typeof selectedOption === 'number') || !id) return of('/');
|
|
86
|
-
|
|
87
|
-
const option = this.versionOptions()?.find((x) => x.Version === selectedOption);
|
|
88
|
-
|
|
89
|
-
return this.#dupServer
|
|
90
|
-
.getApiV1BackupByIdFiles({
|
|
91
|
-
id,
|
|
92
|
-
time: option?.Time ?? '',
|
|
93
|
-
prefixOnly: false,
|
|
94
|
-
folderContents: true,
|
|
95
|
-
})
|
|
96
|
-
.pipe(
|
|
97
|
-
map((x) => {
|
|
98
|
-
this.rootPathLoaded.set(true);
|
|
99
|
-
|
|
100
|
-
return (x['Files'] as any)[0].Path;
|
|
101
|
-
})
|
|
102
|
-
);
|
|
103
|
-
})
|
|
104
|
-
)
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
displayFn() {
|
|
108
|
-
const options = this.versionOptions();
|
|
109
|
-
|
|
110
|
-
return (val: string) => {
|
|
111
|
-
if (!val) return '';
|
|
112
|
-
|
|
113
|
-
const item = options?.find((x) => x.Version?.toString() === val);
|
|
114
|
-
|
|
115
|
-
if (!item) {
|
|
116
|
-
return '';
|
|
117
|
-
}
|
|
118
|
-
return `${item.Version}: ${this.#datePipe.transform(item.Time, 'd MMM y, h:mm')}`;
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
next() {
|
|
123
|
-
this.#router.navigate(['options'], { relativeTo: this.#route.parent });
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
exit() {
|
|
127
|
-
this.#restoreFlowState.exit();
|
|
128
|
-
}
|
|
129
|
-
}
|