@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.
Files changed (197) hide show
  1. package/chunk-22HCWJS5.js +1 -0
  2. package/chunk-24PLBY6C.js +1 -0
  3. package/chunk-3MM4GLBS.js +1 -0
  4. package/chunk-3MTW6FJP.js +1 -0
  5. package/chunk-4FK75Z4C.js +1 -0
  6. package/chunk-4MMHXTNF.js +1 -0
  7. package/chunk-57M4MADC.js +1 -0
  8. package/chunk-6XUWDRDE.js +1 -0
  9. package/chunk-77NTMJCT.js +1 -0
  10. package/chunk-7X6SBNMU.js +1 -0
  11. package/chunk-A66Z6362.js +1 -0
  12. package/chunk-AC6VDRLC.js +1 -0
  13. package/chunk-BNNZKRIC.js +1 -0
  14. package/chunk-CKPPU3GS.js +2 -0
  15. package/chunk-DYANEO5K.js +1 -0
  16. package/chunk-GJTW7UUU.js +1 -0
  17. package/chunk-GMANGOGH.js +1 -0
  18. package/chunk-I6QIKK6M.js +1 -0
  19. package/chunk-IOWSWUHM.js +1 -0
  20. package/chunk-IQSBPGVL.js +1 -0
  21. package/chunk-L47VTK2X.js +1 -0
  22. package/chunk-LVLU6MPQ.js +1 -0
  23. package/chunk-N5US3SKW.js +1 -0
  24. package/chunk-NIMPOFJV.js +1 -0
  25. package/chunk-ORDBF5MR.js +8 -0
  26. package/chunk-PH6AAOK4.js +1 -0
  27. package/chunk-PY5HJ5U2.js +1 -0
  28. package/chunk-QQDSFTZV.js +1 -0
  29. package/chunk-RANWFSNY.js +1 -0
  30. package/chunk-RLJJFBQ2.js +1 -0
  31. package/chunk-S76TN27U.js +1 -0
  32. package/chunk-UTPCUNNU.js +1 -0
  33. package/chunk-VPEVWKGB.js +1 -0
  34. package/chunk-VVUYO7E4.js +1 -0
  35. package/chunk-WLI4RZYL.js +1 -0
  36. package/chunk-X2NZ4CJ5.js +2 -0
  37. package/chunk-XU7PNEZO.js +1 -0
  38. package/chunk-XYJYUMYL.js +1 -0
  39. package/chunk-YRXI477O.js +1 -0
  40. package/chunk-ZD3JEKWI.js +1 -0
  41. package/index.html +15 -0
  42. package/main-5KJRELCN.js +1 -0
  43. package/package.json +3 -40
  44. package/sparkle-ui-assets/fonts/InterTight-VariableFont_wght.ttf +0 -0
  45. package/sparkle-ui-assets/fonts/InterTight-VariableFont_wght.woff2 +0 -0
  46. package/styles-6W7ZCKNM.css +1 -0
  47. package/.dockerignore +0 -13
  48. package/.github/workflows/npm-publish.yml +0 -59
  49. package/.prettierignore +0 -13
  50. package/.prettierrc +0 -12
  51. package/.vscode/extensions.json +0 -4
  52. package/.vscode/launch.json +0 -13
  53. package/.vscode/settings.json +0 -8
  54. package/.vscode/tasks.json +0 -24
  55. package/Dockerfile +0 -38
  56. package/LICENSE +0 -21
  57. package/README.md +0 -27
  58. package/angular.json +0 -98
  59. package/bun.lockb +0 -0
  60. package/openapi-ts.config.ts +0 -13
  61. package/scripts/generate-package-json.ts +0 -15
  62. package/src/app/about/about.component.html +0 -15
  63. package/src/app/about/about.component.scss +0 -19
  64. package/src/app/about/about.component.ts +0 -13
  65. package/src/app/about/changelog/changelog.component.html +0 -3
  66. package/src/app/about/changelog/changelog.component.scss +0 -7
  67. package/src/app/about/changelog/changelog.component.ts +0 -18
  68. package/src/app/about/general/general.component.html +0 -9
  69. package/src/app/about/general/general.component.scss +0 -23
  70. package/src/app/about/general/general.component.ts +0 -30
  71. package/src/app/about/libraries/libraries.component.html +0 -3
  72. package/src/app/about/libraries/libraries.component.scss +0 -7
  73. package/src/app/about/libraries/libraries.component.ts +0 -18
  74. package/src/app/about/logs/logs.component.html +0 -5
  75. package/src/app/about/logs/logs.component.scss +0 -7
  76. package/src/app/about/logs/logs.component.ts +0 -18
  77. package/src/app/about/system-info/system-info.component.html +0 -3
  78. package/src/app/about/system-info/system-info.component.scss +0 -7
  79. package/src/app/about/system-info/system-info.component.ts +0 -17
  80. package/src/app/add-backup/add-backup.component.html +0 -29
  81. package/src/app/add-backup/add-backup.component.scss +0 -38
  82. package/src/app/add-backup/add-backup.component.ts +0 -14
  83. package/src/app/app.component.ts +0 -35
  84. package/src/app/app.config.ts +0 -23
  85. package/src/app/app.routes.ts +0 -121
  86. package/src/app/core/components/file-tree/file-tree.component.html +0 -87
  87. package/src/app/core/components/file-tree/file-tree.component.scss +0 -80
  88. package/src/app/core/components/file-tree/file-tree.component.ts +0 -485
  89. package/src/app/core/components/logo/logo.component.html +0 -22
  90. package/src/app/core/components/logo/logo.component.scss +0 -12
  91. package/src/app/core/components/logo/logo.component.ts +0 -11
  92. package/src/app/core/components/status-bar/status-bar.component.html +0 -38
  93. package/src/app/core/components/status-bar/status-bar.component.scss +0 -27
  94. package/src/app/core/components/status-bar/status-bar.component.ts +0 -33
  95. package/src/app/core/components/status-bar/status-bar.state.ts +0 -182
  96. package/src/app/core/components/toggle-card/toggle-card.component.html +0 -11
  97. package/src/app/core/components/toggle-card/toggle-card.component.scss +0 -49
  98. package/src/app/core/components/toggle-card/toggle-card.component.ts +0 -28
  99. package/src/app/core/interceptors/http.interceptor.ts +0 -69
  100. package/src/app/core/interceptors/websocket.interceptor.ts +0 -66
  101. package/src/app/core/openapi/core/ApiError.ts +0 -21
  102. package/src/app/core/openapi/core/ApiRequestOptions.ts +0 -21
  103. package/src/app/core/openapi/core/ApiResult.ts +0 -7
  104. package/src/app/core/openapi/core/OpenAPI.ts +0 -55
  105. package/src/app/core/openapi/core/request.ts +0 -337
  106. package/src/app/core/openapi/index.ts +0 -6
  107. package/src/app/core/openapi/schemas.gen.ts +0 -3611
  108. package/src/app/core/openapi/services.gen.ts +0 -1460
  109. package/src/app/core/openapi/types.gen.ts +0 -1510
  110. package/src/app/core/pipes/duration.pipe.ts +0 -27
  111. package/src/app/core/pipes/relative-time.pipe.ts +0 -14
  112. package/src/app/core/providers/dayjs.ts +0 -16
  113. package/src/app/core/services/dict.en.ts +0 -0
  114. package/src/app/core/services/dictionary.service.ts +0 -12
  115. package/src/app/core/services/localstorage.token.ts +0 -82
  116. package/src/app/core/services/password-generator.service.ts +0 -39
  117. package/src/app/core/services/relay-websocket.service.ts +0 -268
  118. package/src/app/core/services/timespan-literals.service.ts +0 -25
  119. package/src/app/core/states/app-auth.state.ts +0 -87
  120. package/src/app/core/states/backups.state.ts +0 -71
  121. package/src/app/core/states/relayconfig.state.ts +0 -23
  122. package/src/app/core/states/sysinfo.state.ts +0 -31
  123. package/src/app/core/states/tasks.state.ts +0 -34
  124. package/src/app/core/types/subscribed.ts +0 -7
  125. package/src/app/core/validators/custom.validators.ts +0 -120
  126. package/src/app/create-edit-backup/create-edit-backup.component.html +0 -28
  127. package/src/app/create-edit-backup/create-edit-backup.component.scss +0 -15
  128. package/src/app/create-edit-backup/create-edit-backup.component.ts +0 -33
  129. package/src/app/create-edit-backup/create-edit-backup.state.ts +0 -582
  130. package/src/app/create-edit-backup/destination/destination.component.html +0 -367
  131. package/src/app/create-edit-backup/destination/destination.component.scss +0 -85
  132. package/src/app/create-edit-backup/destination/destination.component.ts +0 -249
  133. package/src/app/create-edit-backup/destination/destination.config.ts +0 -103
  134. package/src/app/create-edit-backup/destination/destination.mapper.ts +0 -177
  135. package/src/app/create-edit-backup/general/general.component.html +0 -108
  136. package/src/app/create-edit-backup/general/general.component.scss +0 -34
  137. package/src/app/create-edit-backup/general/general.component.ts +0 -136
  138. package/src/app/create-edit-backup/options/options.component.html +0 -95
  139. package/src/app/create-edit-backup/options/options.component.scss +0 -42
  140. package/src/app/create-edit-backup/options/options.component.ts +0 -113
  141. package/src/app/create-edit-backup/schedule/schedule.component.html +0 -102
  142. package/src/app/create-edit-backup/schedule/schedule.component.scss +0 -38
  143. package/src/app/create-edit-backup/schedule/schedule.component.ts +0 -137
  144. package/src/app/create-edit-backup/source-data/source-data.component.html +0 -93
  145. package/src/app/create-edit-backup/source-data/source-data.component.scss +0 -41
  146. package/src/app/create-edit-backup/source-data/source-data.component.ts +0 -114
  147. package/src/app/home/backup.const.ts +0 -167
  148. package/src/app/home/home.component.html +0 -98
  149. package/src/app/home/home.component.scss +0 -88
  150. package/src/app/home/home.component.ts +0 -54
  151. package/src/app/layout/layout.component.html +0 -64
  152. package/src/app/layout/layout.component.scss +0 -24
  153. package/src/app/layout/layout.component.ts +0 -51
  154. package/src/app/layout/layout.state.ts +0 -70
  155. package/src/app/login/login.component.html +0 -12
  156. package/src/app/login/login.component.scss +0 -25
  157. package/src/app/login/login.component.ts +0 -34
  158. package/src/app/logout/logout.component.html +0 -1
  159. package/src/app/logout/logout.component.scss +0 -3
  160. package/src/app/logout/logout.component.ts +0 -18
  161. package/src/app/restore/restore.component.html +0 -56
  162. package/src/app/restore/restore.component.scss +0 -37
  163. package/src/app/restore/restore.component.ts +0 -55
  164. package/src/app/restore-flow/options/options.component.html +0 -57
  165. package/src/app/restore-flow/options/options.component.scss +0 -16
  166. package/src/app/restore-flow/options/options.component.ts +0 -58
  167. package/src/app/restore-flow/restore-flow.component.html +0 -14
  168. package/src/app/restore-flow/restore-flow.component.scss +0 -15
  169. package/src/app/restore-flow/restore-flow.component.ts +0 -23
  170. package/src/app/restore-flow/restore-flow.state.ts +0 -120
  171. package/src/app/restore-flow/select-files/select-files.component.html +0 -42
  172. package/src/app/restore-flow/select-files/select-files.component.scss +0 -16
  173. package/src/app/restore-flow/select-files/select-files.component.ts +0 -129
  174. package/src/app/settings/settings.component.html +0 -256
  175. package/src/app/settings/settings.component.scss +0 -106
  176. package/src/app/settings/settings.component.ts +0 -475
  177. package/src/environments/environment-token.ts +0 -4
  178. package/src/environments/environment.prod.ts +0 -6
  179. package/src/environments/environment.ts +0 -6
  180. package/src/index.html +0 -15
  181. package/src/main.ts +0 -6
  182. package/src/proxy.conf.mjs +0 -6
  183. package/src/styles.scss +0 -41
  184. package/tsconfig.app.json +0 -15
  185. package/tsconfig.json +0 -30
  186. /package/{src/assets → assets}/duplicati-logo.png +0 -0
  187. /package/{src/assets → assets}/duplicati-logo.svg +0 -0
  188. /package/{src/assets → assets}/favicon.ico +0 -0
  189. /package/{src/assets → assets}/images/backup.png +0 -0
  190. /package/{src/assets → assets}/images/dark-theme.png +0 -0
  191. /package/{src/assets → assets}/images/folder.png +0 -0
  192. /package/{src/assets → assets}/images/light-theme.png +0 -0
  193. /package/{src/assets → assets}/images/new-backup.png +0 -0
  194. /package/{src/assets → assets}/images/restore.png +0 -0
  195. /package/{src/assets → assets}/images/system-theme.png +0 -0
  196. /package/{src/assets → assets}/spk.css +0 -0
  197. /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,16 +0,0 @@
1
- @use '@sparkle-ui/core/styles/helpers' as *;
2
-
3
- :host {
4
- display: block;
5
- }
6
-
7
- form {
8
- display: flex;
9
- flex-direction: column;
10
- gap: p2r(24);
11
- }
12
-
13
- .form-actions {
14
- display: flex;
15
- justify-content: space-between;
16
- }
@@ -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,15 +0,0 @@
1
- @use '@sparkle-ui/core/styles/helpers' as *;
2
-
3
- :host {
4
- display: block;
5
- }
6
-
7
- spk-stepper {
8
- max-width: p2r(500);
9
- margin: p2r(40) auto;
10
- }
11
-
12
- section {
13
- max-width: p2r(500);
14
- margin: 0 auto p2r(40);
15
- }
@@ -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,16 +0,0 @@
1
- @use '@sparkle-ui/core/styles/helpers' as *;
2
-
3
- :host {
4
- display: block;
5
- }
6
-
7
- form {
8
- display: flex;
9
- flex-direction: column;
10
- gap: p2r(24);
11
- }
12
-
13
- .form-actions {
14
- display: flex;
15
- justify-content: space-between;
16
- }
@@ -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
- }