geonetwork-ui 2.3.0-dev.3d65a13b → 2.3.0-dev.c3722986

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 (72) hide show
  1. package/esm2022/libs/data-access/gn4/src/openapi/api/records.api.service.mjs +35 -7
  2. package/esm2022/libs/data-access/gn4/src/openapi/model/models.mjs +1 -2
  3. package/esm2022/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.mjs +3 -3
  4. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +3 -3
  5. package/esm2022/libs/ui/elements/src/lib/thumbnail/thumbnail.component.mjs +4 -3
  6. package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +6 -5
  7. package/esm2022/libs/ui/inputs/src/lib/button/button.component.mjs +2 -1
  8. package/esm2022/libs/ui/inputs/src/lib/files-drop/files-drop.directive.mjs +59 -0
  9. package/esm2022/libs/ui/inputs/src/lib/image-input/image-input.component.mjs +183 -0
  10. package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +10 -4
  11. package/esm2022/libs/util/shared/src/lib/utils/bytes-convert.mjs +4 -0
  12. package/esm2022/libs/util/shared/src/lib/utils/image-resize.mjs +60 -0
  13. package/esm2022/libs/util/shared/src/lib/utils/index.mjs +8 -6
  14. package/esm2022/translations/de.json +10 -0
  15. package/esm2022/translations/en.json +10 -0
  16. package/esm2022/translations/es.json +10 -0
  17. package/esm2022/translations/fr.json +10 -0
  18. package/esm2022/translations/it.json +10 -0
  19. package/esm2022/translations/nl.json +10 -0
  20. package/esm2022/translations/pt.json +10 -0
  21. package/fesm2022/geonetwork-ui.mjs +494 -114
  22. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  23. package/libs/data-access/gn4/src/openapi/api/records.api.service.d.ts +9 -5
  24. package/libs/data-access/gn4/src/openapi/api/records.api.service.d.ts.map +1 -1
  25. package/libs/data-access/gn4/src/openapi/model/models.d.ts +0 -1
  26. package/libs/data-access/gn4/src/openapi/model/models.d.ts.map +1 -1
  27. package/libs/ui/elements/src/lib/thumbnail/thumbnail.component.d.ts +1 -1
  28. package/libs/ui/elements/src/lib/thumbnail/thumbnail.component.d.ts.map +1 -1
  29. package/libs/ui/elements/src/lib/ui-elements.module.d.ts +20 -20
  30. package/libs/ui/inputs/src/lib/button/button.component.d.ts.map +1 -1
  31. package/libs/ui/inputs/src/lib/files-drop/files-drop.directive.d.ts +14 -0
  32. package/libs/ui/inputs/src/lib/files-drop/files-drop.directive.d.ts.map +1 -0
  33. package/libs/ui/inputs/src/lib/image-input/image-input.component.d.ts +44 -0
  34. package/libs/ui/inputs/src/lib/image-input/image-input.component.d.ts.map +1 -0
  35. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +2 -1
  36. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts.map +1 -1
  37. package/libs/util/shared/src/lib/utils/bytes-convert.d.ts +2 -0
  38. package/libs/util/shared/src/lib/utils/bytes-convert.d.ts.map +1 -0
  39. package/libs/util/shared/src/lib/utils/image-resize.d.ts +3 -0
  40. package/libs/util/shared/src/lib/utils/image-resize.d.ts.map +1 -0
  41. package/libs/util/shared/src/lib/utils/index.d.ts +7 -5
  42. package/libs/util/shared/src/lib/utils/index.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/src/libs/data-access/gn4/src/openapi/api/records.api.service.ts +43 -12
  45. package/src/libs/data-access/gn4/src/openapi/model/models.ts +0 -1
  46. package/src/libs/data-access/gn4/src/spec.yaml +1 -1
  47. package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.css +0 -0
  48. package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.html +8 -0
  49. package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.ts +70 -0
  50. package/src/libs/ui/elements/src/lib/thumbnail/thumbnail.component.ts +5 -3
  51. package/src/libs/ui/elements/src/lib/ui-elements.module.ts +1 -1
  52. package/src/libs/ui/inputs/src/lib/button/button.component.ts +1 -1
  53. package/src/libs/ui/inputs/src/lib/files-drop/files-drop.directive.ts +45 -0
  54. package/src/libs/ui/inputs/src/lib/image-input/image-input.component.css +0 -0
  55. package/src/libs/ui/inputs/src/lib/image-input/image-input.component.html +146 -0
  56. package/src/libs/ui/inputs/src/lib/image-input/image-input.component.ts +193 -0
  57. package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +3 -0
  58. package/src/libs/util/shared/src/lib/utils/bytes-convert.ts +3 -0
  59. package/src/libs/util/shared/src/lib/utils/image-resize.ts +72 -0
  60. package/src/libs/util/shared/src/lib/utils/index.ts +7 -5
  61. package/translations/de.json +10 -0
  62. package/translations/en.json +10 -0
  63. package/translations/es.json +10 -0
  64. package/translations/fr.json +10 -0
  65. package/translations/it.json +10 -0
  66. package/translations/nl.json +10 -0
  67. package/translations/pt.json +10 -0
  68. package/translations/sk.json +10 -0
  69. package/esm2022/libs/data-access/gn4/src/openapi/model/inlineObject3.api.model.mjs +0 -13
  70. package/libs/data-access/gn4/src/openapi/model/inlineObject3.api.model.d.ts +0 -18
  71. package/libs/data-access/gn4/src/openapi/model/inlineObject3.api.model.d.ts.map +0 -1
  72. package/src/libs/data-access/gn4/src/openapi/model/inlineObject3.api.model.ts +0 -18
@@ -0,0 +1,44 @@
1
+ import { HttpClient } from '@angular/common/http';
2
+ import { ChangeDetectorRef, EventEmitter } from '@angular/core';
3
+ import * as i0 from "@angular/core";
4
+ export declare class ImageInputComponent {
5
+ private http;
6
+ private cd;
7
+ maxSizeMB: number;
8
+ previewUrl?: string;
9
+ altText?: string;
10
+ uploadProgress?: number;
11
+ uploadError?: boolean;
12
+ fileChange: EventEmitter<File>;
13
+ urlChange: EventEmitter<string>;
14
+ uploadCancel: EventEmitter<void>;
15
+ delete: EventEmitter<void>;
16
+ altTextChange: EventEmitter<string>;
17
+ dragFilesOver: boolean;
18
+ showUrlInput: boolean;
19
+ downloadError: boolean;
20
+ showAltTextInput: boolean;
21
+ urlInputValue?: string;
22
+ lastUploadType?: 'file' | 'url';
23
+ lastUploadContent?: string | File;
24
+ constructor(http: HttpClient, cd: ChangeDetectorRef);
25
+ getPrimaryText(): "input.image.uploadErrorLabel" | "input.image.uploadProgressLabel" | "input.image.selectFileLabel";
26
+ getSecondaryText(): "input.image.uploadErrorRetry" | "input.image.uploadProgressCancel" | "input.image.dropFileLabel";
27
+ handleDragFilesOver(dragFilesOver: boolean): void;
28
+ handleDropFiles(files: File[]): void;
29
+ handleFileInput(event: Event): void;
30
+ displayUrlInput(): void;
31
+ handleUrlChange(event: Event): void;
32
+ downloadUrl(): Promise<void>;
33
+ handleSecondaryTextClick(): void;
34
+ handleCancel(): void;
35
+ handleRetry(): void;
36
+ handleDelete(): void;
37
+ toggleAltTextInput(): void;
38
+ handleAltTextChange(event: Event): void;
39
+ private filterTypeImage;
40
+ private resizeAndEmit;
41
+ static ɵfac: i0.ɵɵFactoryDeclaration<ImageInputComponent, never>;
42
+ static ɵcmp: i0.ɵɵComponentDeclaration<ImageInputComponent, "gn-ui-image-input", never, { "maxSizeMB": { "alias": "maxSizeMB"; "required": false; }; "previewUrl": { "alias": "previewUrl"; "required": false; }; "altText": { "alias": "altText"; "required": false; }; "uploadProgress": { "alias": "uploadProgress"; "required": false; }; "uploadError": { "alias": "uploadError"; "required": false; }; }, { "fileChange": "fileChange"; "urlChange": "urlChange"; "uploadCancel": "uploadCancel"; "delete": "delete"; "altTextChange": "altTextChange"; }, never, never, true, never>;
43
+ }
44
+ //# sourceMappingURL=image-input.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-input.component.d.ts","sourceRoot":"","sources":["../../../../../../src/libs/ui/inputs/src/lib/image-input/image-input.component.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAEL,iBAAiB,EAEjB,YAAY,EAGb,MAAM,eAAe,CAAA;;AAUtB,qBAea,mBAAmB;IAqBlB,OAAO,CAAC,IAAI;IAAc,OAAO,CAAC,EAAE;IApBvC,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,WAAW,CAAC,EAAE,OAAO,CAAA;IACpB,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,CAAqB;IACnD,SAAS,EAAE,YAAY,CAAC,MAAM,CAAC,CAAqB;IACpD,YAAY,EAAE,YAAY,CAAC,IAAI,CAAC,CAAqB;IACrD,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,CAAqB;IAC/C,aAAa,EAAE,YAAY,CAAC,MAAM,CAAC,CAAqB;IAElE,aAAa,UAAQ;IACrB,YAAY,UAAQ;IACpB,aAAa,UAAQ;IACrB,gBAAgB,UAAQ;IAExB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;gBAEb,IAAI,EAAE,UAAU,EAAU,EAAE,EAAE,iBAAiB;IAEnE,cAAc;IAUd,gBAAgB;IAUhB,mBAAmB,CAAC,aAAa,EAAE,OAAO;IAO1C,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE;IAS7B,eAAe,CAAC,KAAK,EAAE,KAAK;IAQ5B,eAAe;IAKf,eAAe,CAAC,KAAK,EAAE,KAAK;IAKtB,WAAW;IAgCjB,wBAAwB;IAQxB,YAAY;IAIZ,WAAW;IAWX,YAAY;IAIZ,kBAAkB;IAIlB,mBAAmB,CAAC,KAAK,EAAE,KAAK;IAKhC,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,aAAa;yCAvJV,mBAAmB;2CAAnB,mBAAmB;CA8J/B"}
@@ -40,9 +40,10 @@ import * as i38 from "@angular/material/core";
40
40
  import * as i39 from "./editable-label/editable-label.directive";
41
41
  import * as i40 from "./text-area/text-area.component";
42
42
  import * as i41 from "./button/button.component";
43
+ import * as i42 from "./image-input/image-input.component";
43
44
  export declare class UiInputsModule {
44
45
  static ɵfac: i0.ɵɵFactoryDeclaration<UiInputsModule, never>;
45
- static ɵmod: i0.ɵɵNgModuleDeclaration<UiInputsModule, [typeof i1.DropdownSelectorComponent, typeof i2.AutocompleteComponent, typeof i3.TextInputComponent, typeof i4.DragAndDropFileInputComponent, typeof i5.ChipsInputComponent, typeof i6.NavigationButtonComponent, typeof i7.StarToggleComponent, typeof i8.DropdownMultiselectComponent, typeof i9.ViewportIntersectorComponent, typeof i10.FormFieldComponent, typeof i11.FormFieldSimpleComponent, typeof i12.FormFieldArrayComponent, typeof i13.FormFieldObjectComponent, typeof i14.FormFieldRichComponent, typeof i15.FormFieldFileComponent, typeof i16.FormFieldSpatialExtentComponent, typeof i17.FormFieldTemporalExtentComponent, typeof i18.CheckToggleComponent, typeof i19.CopyTextButtonComponent, typeof i20.CheckboxComponent, typeof i21.SearchInputComponent, typeof i22.DateRangePickerComponent], [typeof i23.CommonModule, typeof i24.TranslateModule, typeof i25.NgxDropzoneModule, typeof i26.FormsModule, typeof i26.ReactiveFormsModule, typeof i27.TagInputModule, typeof i28.UtilSharedModule, typeof i29.MatAutocompleteModule, typeof i30.MatIconModule, typeof i31.UiWidgetsModule, typeof i32.OverlayModule, typeof i33.MatCheckboxModule, typeof i34.MatTooltipModule, typeof i35.MatFormFieldModule, typeof i36.MatInputModule, typeof i37.MatDatepickerModule, typeof i38.MatNativeDateModule, typeof i39.EditableLabelDirective, typeof i40.TextAreaComponent, typeof i41.ButtonComponent], [typeof i1.DropdownSelectorComponent, typeof i2.AutocompleteComponent, typeof i41.ButtonComponent, typeof i3.TextInputComponent, typeof i4.DragAndDropFileInputComponent, typeof i40.TextAreaComponent, typeof i5.ChipsInputComponent, typeof i6.NavigationButtonComponent, typeof i7.StarToggleComponent, typeof i8.DropdownMultiselectComponent, typeof i9.ViewportIntersectorComponent, typeof i10.FormFieldComponent, typeof i18.CheckToggleComponent, typeof i19.CopyTextButtonComponent, typeof i20.CheckboxComponent, typeof i21.SearchInputComponent, typeof i22.DateRangePickerComponent, typeof i39.EditableLabelDirective]>;
46
+ static ɵmod: i0.ɵɵNgModuleDeclaration<UiInputsModule, [typeof i1.DropdownSelectorComponent, typeof i2.AutocompleteComponent, typeof i3.TextInputComponent, typeof i4.DragAndDropFileInputComponent, typeof i5.ChipsInputComponent, typeof i6.NavigationButtonComponent, typeof i7.StarToggleComponent, typeof i8.DropdownMultiselectComponent, typeof i9.ViewportIntersectorComponent, typeof i10.FormFieldComponent, typeof i11.FormFieldSimpleComponent, typeof i12.FormFieldArrayComponent, typeof i13.FormFieldObjectComponent, typeof i14.FormFieldRichComponent, typeof i15.FormFieldFileComponent, typeof i16.FormFieldSpatialExtentComponent, typeof i17.FormFieldTemporalExtentComponent, typeof i18.CheckToggleComponent, typeof i19.CopyTextButtonComponent, typeof i20.CheckboxComponent, typeof i21.SearchInputComponent, typeof i22.DateRangePickerComponent], [typeof i23.CommonModule, typeof i24.TranslateModule, typeof i25.NgxDropzoneModule, typeof i26.FormsModule, typeof i26.ReactiveFormsModule, typeof i27.TagInputModule, typeof i28.UtilSharedModule, typeof i29.MatAutocompleteModule, typeof i30.MatIconModule, typeof i31.UiWidgetsModule, typeof i32.OverlayModule, typeof i33.MatCheckboxModule, typeof i34.MatTooltipModule, typeof i35.MatFormFieldModule, typeof i36.MatInputModule, typeof i37.MatDatepickerModule, typeof i38.MatNativeDateModule, typeof i39.EditableLabelDirective, typeof i40.TextAreaComponent, typeof i41.ButtonComponent, typeof i42.ImageInputComponent], [typeof i1.DropdownSelectorComponent, typeof i2.AutocompleteComponent, typeof i41.ButtonComponent, typeof i3.TextInputComponent, typeof i4.DragAndDropFileInputComponent, typeof i40.TextAreaComponent, typeof i5.ChipsInputComponent, typeof i6.NavigationButtonComponent, typeof i7.StarToggleComponent, typeof i8.DropdownMultiselectComponent, typeof i9.ViewportIntersectorComponent, typeof i10.FormFieldComponent, typeof i18.CheckToggleComponent, typeof i19.CopyTextButtonComponent, typeof i20.CheckboxComponent, typeof i21.SearchInputComponent, typeof i22.DateRangePickerComponent, typeof i39.EditableLabelDirective, typeof i42.ImageInputComponent]>;
46
47
  static ɵinj: i0.ɵɵInjectorDeclaration<UiInputsModule>;
47
48
  }
48
49
  //# sourceMappingURL=ui-inputs.module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui-inputs.module.d.ts","sourceRoot":"","sources":["../../../../../src/libs/ui/inputs/src/lib/ui-inputs.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,qBAoEa,cAAc;yCAAd,cAAc;0CAAd,cAAc;0CAAd,cAAc;CAAG"}
1
+ {"version":3,"file":"ui-inputs.module.d.ts","sourceRoot":"","sources":["../../../../../src/libs/ui/inputs/src/lib/ui-inputs.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,qBAsEa,cAAc;yCAAd,cAAc;0CAAd,cAAc;0CAAd,cAAc;CAAG"}
@@ -0,0 +1,2 @@
1
+ export declare function megabytesToBytes(megabytes: any): number;
2
+ //# sourceMappingURL=bytes-convert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bytes-convert.d.ts","sourceRoot":"","sources":["../../../../../../src/libs/util/shared/src/lib/utils/bytes-convert.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,SAAS,KAAA,UAEzC"}
@@ -0,0 +1,3 @@
1
+ export declare function downsizeImage(blob: Blob, maxWidth: number, maxHeight: number): Promise<Blob>;
2
+ export declare function downgradeImage(blob: Blob, maxSizeBytes: number): Promise<Blob>;
3
+ //# sourceMappingURL=image-resize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-resize.d.ts","sourceRoot":"","sources":["../../../../../../src/libs/util/shared/src/lib/utils/image-resize.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAC3B,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAiCf"}
@@ -1,10 +1,12 @@
1
+ export * from './bytes-convert';
2
+ export * from './event';
3
+ export * from './fuzzy-filter';
4
+ export * from './geojson';
5
+ export * from './image-resize';
1
6
  export * from './parse';
2
- export * from './strip-html';
3
7
  export * from './remove-whitespace';
4
- export * from './geojson';
5
8
  export * from './sort-by';
6
- export * from './url';
7
- export * from './event';
8
- export * from './fuzzy-filter';
9
+ export * from './strip-html';
9
10
  export * from './temporal-extent-union';
11
+ export * from './url';
10
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/libs/util/shared/src/lib/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,cAAc,qBAAqB,CAAA;AACnC,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,OAAO,CAAA;AACrB,cAAc,SAAS,CAAA;AACvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,yBAAyB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/libs/util/shared/src/lib/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,SAAS,CAAA;AACvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA;AACvB,cAAc,qBAAqB,CAAA;AACnC,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,yBAAyB,CAAA;AACvC,cAAc,OAAO,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geonetwork-ui",
3
- "version": "2.3.0-dev.3d65a13b",
3
+ "version": "2.3.0-dev.c3722986",
4
4
  "engines": {
5
5
  "node": ">=14.17.0"
6
6
  },
@@ -30,7 +30,6 @@ import {
30
30
  import { ExtentDtoApiModel } from '../model/models'
31
31
  import { FeatureResponseApiModel } from '../model/models'
32
32
  import { IProcessingReportApiModel } from '../model/models'
33
- import { InlineObject3ApiModel } from '../model/models'
34
33
  import { MetadataBatchApproveParameterApiModel } from '../model/models'
35
34
  import { MetadataBatchSubmitParameterApiModel } from '../model/models'
36
35
  import { MetadataCategoryApiModel } from '../model/models'
@@ -75,6 +74,20 @@ export class RecordsApiService {
75
74
  this.encoder = this.configuration.encoder || new CustomHttpParameterCodec()
76
75
  }
77
76
 
77
+ /**
78
+ * @param consumes string[] mime-types
79
+ * @return true: consumes contains 'multipart/form-data', false: otherwise
80
+ */
81
+ private canConsumeForm(consumes: string[]): boolean {
82
+ const form = 'multipart/form-data'
83
+ for (const consume of consumes) {
84
+ if (form === consume) {
85
+ return true
86
+ }
87
+ }
88
+ return false
89
+ }
90
+
78
91
  private addToHttpParams(
79
92
  httpParams: HttpParams,
80
93
  value: any,
@@ -8290,44 +8303,44 @@ export class RecordsApiService {
8290
8303
  /**
8291
8304
  * Create a new resource for a given metadata
8292
8305
  * @param metadataUuid The metadata UUID
8306
+ * @param file The file to upload
8293
8307
  * @param visibility The sharing policy
8294
8308
  * @param approved Use approved version or not
8295
- * @param inlineObject3ApiModel
8296
8309
  * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
8297
8310
  * @param reportProgress flag to report request and response progress.
8298
8311
  */
8299
8312
  public putResource(
8300
8313
  metadataUuid: string,
8314
+ file: Blob,
8301
8315
  visibility?: 'public' | 'private',
8302
8316
  approved?: boolean,
8303
- inlineObject3ApiModel?: InlineObject3ApiModel,
8304
8317
  observe?: 'body',
8305
8318
  reportProgress?: boolean,
8306
8319
  options?: { httpHeaderAccept?: 'application/json' }
8307
8320
  ): Observable<MetadataResourceApiModel>
8308
8321
  public putResource(
8309
8322
  metadataUuid: string,
8323
+ file: Blob,
8310
8324
  visibility?: 'public' | 'private',
8311
8325
  approved?: boolean,
8312
- inlineObject3ApiModel?: InlineObject3ApiModel,
8313
8326
  observe?: 'response',
8314
8327
  reportProgress?: boolean,
8315
8328
  options?: { httpHeaderAccept?: 'application/json' }
8316
8329
  ): Observable<HttpResponse<MetadataResourceApiModel>>
8317
8330
  public putResource(
8318
8331
  metadataUuid: string,
8332
+ file: Blob,
8319
8333
  visibility?: 'public' | 'private',
8320
8334
  approved?: boolean,
8321
- inlineObject3ApiModel?: InlineObject3ApiModel,
8322
8335
  observe?: 'events',
8323
8336
  reportProgress?: boolean,
8324
8337
  options?: { httpHeaderAccept?: 'application/json' }
8325
8338
  ): Observable<HttpEvent<MetadataResourceApiModel>>
8326
8339
  public putResource(
8327
8340
  metadataUuid: string,
8341
+ file: Blob,
8328
8342
  visibility?: 'public' | 'private',
8329
8343
  approved?: boolean,
8330
- inlineObject3ApiModel?: InlineObject3ApiModel,
8331
8344
  observe: any = 'body',
8332
8345
  reportProgress: boolean = false,
8333
8346
  options?: { httpHeaderAccept?: 'application/json' }
@@ -8337,6 +8350,11 @@ export class RecordsApiService {
8337
8350
  'Required parameter metadataUuid was null or undefined when calling putResource.'
8338
8351
  )
8339
8352
  }
8353
+ if (file === null || file === undefined) {
8354
+ throw new Error(
8355
+ 'Required parameter file was null or undefined when calling putResource.'
8356
+ )
8357
+ }
8340
8358
 
8341
8359
  let queryParameters = new HttpParams({ encoder: this.encoder })
8342
8360
  if (visibility !== undefined && visibility !== null) {
@@ -8369,11 +8387,24 @@ export class RecordsApiService {
8369
8387
  }
8370
8388
 
8371
8389
  // to determine the Content-Type header
8372
- const consumes: string[] = ['application/json']
8373
- const httpContentTypeSelected: string | undefined =
8374
- this.configuration.selectHeaderContentType(consumes)
8375
- if (httpContentTypeSelected !== undefined) {
8376
- headers = headers.set('Content-Type', httpContentTypeSelected)
8390
+ const consumes: string[] = ['multipart/form-data']
8391
+
8392
+ const canConsumeForm = this.canConsumeForm(consumes)
8393
+
8394
+ let formParams: { append(param: string, value: any): any }
8395
+ let useForm = false
8396
+ let convertFormParamsToString = false
8397
+ // use FormData to transmit files using content-type "multipart/form-data"
8398
+ // see https://stackoverflow.com/questions/4007969/application-x-www-form-urlencoded-or-multipart-form-data
8399
+ useForm = canConsumeForm
8400
+ if (useForm) {
8401
+ formParams = new FormData()
8402
+ } else {
8403
+ formParams = new HttpParams({ encoder: this.encoder })
8404
+ }
8405
+
8406
+ if (file !== undefined) {
8407
+ formParams = (formParams.append('file', <any>file) as any) || formParams
8377
8408
  }
8378
8409
 
8379
8410
  let responseType_: 'text' | 'json' = 'json'
@@ -8388,7 +8419,7 @@ export class RecordsApiService {
8388
8419
  `${this.configuration.basePath}/records/${encodeURIComponent(
8389
8420
  String(metadataUuid)
8390
8421
  )}/attachments`,
8391
- inlineObject3ApiModel,
8422
+ convertFormParamsToString ? formParams.toString() : formParams,
8392
8423
  {
8393
8424
  params: queryParameters,
8394
8425
  responseType: <any>responseType_,
@@ -33,7 +33,6 @@ export * from './iProcessingReport.api.model'
33
33
  export * from './iSODate.api.model'
34
34
  export * from './infoReport.api.model'
35
35
  export * from './inlineObject1.api.model'
36
- export * from './inlineObject3.api.model'
37
36
  export * from './inlineObject4.api.model'
38
37
  export * from './isoLanguage.api.model'
39
38
  export * from './jSONObject.api.model'
@@ -7390,7 +7390,7 @@ paths:
7390
7390
  example: true
7391
7391
  requestBody:
7392
7392
  content:
7393
- application/json:
7393
+ multipart/form-data:
7394
7394
  schema:
7395
7395
  required:
7396
7396
  - file
@@ -0,0 +1,8 @@
1
+ <gn-ui-image-input
2
+ [maxSizeMB]="5"
3
+ [previewUrl]="resourceUrl"
4
+ [altText]="resourceFileName"
5
+ (fileChange)="handleFileChange($event)"
6
+ (urlChange)="handleUrlChange($event)"
7
+ (delete)="handleDelete()"
8
+ ></gn-ui-image-input>
@@ -0,0 +1,70 @@
1
+ import {
2
+ ChangeDetectionStrategy,
3
+ ChangeDetectorRef,
4
+ Component,
5
+ Input,
6
+ OnInit,
7
+ } from '@angular/core'
8
+ import { CommonModule } from '@angular/common'
9
+ import { RecordsApiService } from '../../../../../../../libs/data-access/gn4/src'
10
+ import { UiInputsModule } from '../../../../../../../libs/ui/inputs/src'
11
+
12
+ @Component({
13
+ selector: 'gn-ui-overview-upload',
14
+ standalone: true,
15
+ imports: [CommonModule, UiInputsModule],
16
+ templateUrl: './overview-upload.component.html',
17
+ styleUrls: ['./overview-upload.component.css'],
18
+ changeDetection: ChangeDetectionStrategy.OnPush,
19
+ })
20
+ export class OverviewUploadComponent implements OnInit {
21
+ @Input() metadataUuid: string
22
+
23
+ resourceFileName: string
24
+ resourceUrl: string
25
+
26
+ constructor(
27
+ private recordsApiService: RecordsApiService,
28
+ private cd: ChangeDetectorRef
29
+ ) {}
30
+
31
+ ngOnInit(): void {
32
+ this.recordsApiService
33
+ .getAllResources(this.metadataUuid)
34
+ .subscribe((resources) => {
35
+ this.resourceFileName = resources[0]?.filename
36
+ this.resourceUrl = resources[0]?.url
37
+ this.cd.markForCheck()
38
+ })
39
+ }
40
+
41
+ handleFileChange(file: File) {
42
+ this.recordsApiService
43
+ .putResource(this.metadataUuid, file, 'public')
44
+ .subscribe((resource) => {
45
+ this.resourceFileName = resource.filename
46
+ this.resourceUrl = resource.url
47
+ this.cd.markForCheck()
48
+ })
49
+ }
50
+
51
+ handleUrlChange(url: string) {
52
+ this.recordsApiService
53
+ .putResourceFromURL(this.metadataUuid, url, 'public')
54
+ .subscribe((resource) => {
55
+ this.resourceFileName = resource.filename
56
+ this.resourceUrl = resource.url
57
+ this.cd.markForCheck()
58
+ })
59
+ }
60
+
61
+ handleDelete() {
62
+ this.recordsApiService
63
+ .delResource(this.metadataUuid, this.resourceFileName)
64
+ .subscribe(() => {
65
+ this.resourceFileName = null
66
+ this.resourceUrl = null
67
+ this.cd.markForCheck()
68
+ })
69
+ }
70
+ }
@@ -1,3 +1,4 @@
1
+ import { CommonModule } from '@angular/common'
1
2
  import {
2
3
  ChangeDetectionStrategy,
3
4
  Component,
@@ -18,20 +19,21 @@ export const THUMBNAIL_PLACEHOLDER = new InjectionToken<string>(
18
19
  'thumbnail-placeholder'
19
20
  )
20
21
 
22
+ type FitOptions = 'cover' | 'contain' | 'scale-down'
21
23
  type ThumbnailImageObject = {
22
24
  url: string
23
- fit?: 'cover' | 'contain' | 'scale-down'
25
+ fit?: FitOptions
24
26
  }
25
27
 
26
28
  const DEFAULT_PLACEHOLDER =
27
29
  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA3XAAAN1wFCKJt4AAAAB3RJTUUH5gkNDCUFYjA1nwAAA1pJREFUeNrtnW2TmjAURh8CLlTdrmun///3tZ22+zLuYlehH7jsMGogwRiiec4MM44K6D3x3hAwAIQQQgghhJDYSM5cPwNQAMgBpACUg22GTg2gArAD8A9AKY+9CsgALAF8YRsGALwDeAWw9yGgALCKoKWP+WU8iwxjUsudLBj83sZciIiPSwhoWz7pJ5dUZFQXlEXOZ/DNeTBt3JnhBpc9aacGsOn0BuoIUk3b+5trGnEC4B7Ak4sUlInRU+wB/JbgVxG18KrTBc01EmYmcTFJQUVPy/9zTh/4BthLDOqeenB2DdBtZBN58LsSNpcUoEtTJWM/GIvMhQDde9j6h2OhXAjo6/2Q/lgkLgSQC0IBFEABZEKyiaQv5AAv7fSlS+lPVxRwOXTnEtoTPAs04yfRHGMoz8F/HOiaJfKeggLc78dmOHsVS33y9SUXsDuLlsg6FOAw/fhYhwI0pJ7WoQASpoC9p3UoQEPpaR0K0LCB3fB1e6KfAhxRweAKgQ5PsQxJ+CzCJYC/A7+EWt4TzVCE77GgEsBPHA/G7QBswcE4b+noVRZ2QxkCCqAAQgEUQCiAAggFUAChAAogFEABhAJcfT9FAdOxQuB/ML9lAfdo/qWYy2MK8EiO5mrrliUCvdIudAEzWWzQzWuxwjRnAK9WwAzAWhZTCe3l7cryNQrQBL/txZhKGGrlwc36ogIPfvdzfhuQsDDM80EVZXUFwe+mEJ2EOwBfLfYTTFFWVxL8Qwl3nedSye1jjhEyCjAPflfCWiScU1iDKMrqyoJ/KOFxRDf1sCg/xCxgTPC7EnIHn6GYsiirKw2+ayYryorBn7YoKwb/qCgntywg1OBPdqSsGPyTRXnp07gvPgD8AAl6KIICCAVQAAlLwOg5MSNi9NyqJgKqAHpQoZNZxs5KgG7SDN7AZzgWOxcCtprn5/wVfLb+uWXsrASUPXlvHbmETGKQjBVgMitVJTuaaQS2t/GoEMeE3onEor2jlK4RvwN4G1u9T4n6zp6PMTWAXzCYdCq12OCOhdeYZzT3mIErAW1Fr+HmNOAt82KSesYIAJoRzR2aIVumo+Ms8WwT/HOOZlM0Y+Zzxv2zp/gCTzfzPOyGtdfgp7LEcDvbvSxbWXg/HUIIIYQQQogx/wHLoX7NoCMFPwAAAABJRU5ErkJggg=='
28
30
 
29
- type FitOptions = 'cover' | 'contain' | 'scale-down'
30
-
31
31
  @Component({
32
32
  selector: 'gn-ui-thumbnail',
33
33
  templateUrl: './thumbnail.component.html',
34
34
  changeDetection: ChangeDetectionStrategy.OnPush,
35
+ standalone: true,
36
+ imports: [CommonModule],
35
37
  })
36
38
  export class ThumbnailComponent implements OnInit, OnChanges {
37
39
  @Input() thumbnailUrl: string | string[]
@@ -46,6 +46,7 @@ import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-over
46
46
  FormsModule,
47
47
  NgOptimizedImage,
48
48
  MarkdownParserComponent,
49
+ ThumbnailComponent,
49
50
  ],
50
51
  declarations: [
51
52
  MetadataInfoComponent,
@@ -61,7 +62,6 @@ import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-over
61
62
  MetadataQualityItemComponent,
62
63
  SearchResultsErrorComponent,
63
64
  PaginationComponent,
64
- ThumbnailComponent,
65
65
  AvatarComponent,
66
66
  UserPreviewComponent,
67
67
  GnUiLinkifyDirective,
@@ -15,7 +15,7 @@ import { propagateToDocumentOnly } from '../../../../../../libs/util/shared/src'
15
15
  standalone: true,
16
16
  })
17
17
  export class ButtonComponent {
18
- private btnClass: string
18
+ private btnClass = 'gn-ui-btn-default'
19
19
 
20
20
  @Input() set type(
21
21
  value: 'primary' | 'secondary' | 'default' | 'outline' | 'light'
@@ -0,0 +1,45 @@
1
+ import { Directive, HostListener, Output, EventEmitter } from '@angular/core'
2
+
3
+ @Directive({
4
+ selector: '[gnUiFilesDrop]',
5
+ standalone: true,
6
+ })
7
+ export class FilesDropDirective {
8
+ @Output() dragFilesOver: EventEmitter<boolean> = new EventEmitter()
9
+ @Output() dropFiles: EventEmitter<File[]> = new EventEmitter()
10
+
11
+ dragEnterCounter = 0
12
+
13
+ @HostListener('dragenter', ['$event'])
14
+ _onDragEnter(event: DragEvent) {
15
+ event.preventDefault()
16
+ this.dragEnterCounter++
17
+ this.dragFilesOver.emit(true)
18
+ }
19
+
20
+ @HostListener('dragover', ['$event'])
21
+ _onDragOver(event: DragEvent) {
22
+ event.preventDefault()
23
+ }
24
+
25
+ @HostListener('dragleave', ['$event'])
26
+ _onDragLeave(event: DragEvent) {
27
+ event.preventDefault()
28
+ this.dragEnterCounter = Math.max(0, this.dragEnterCounter - 1)
29
+ if (this.dragEnterCounter === 0) {
30
+ this.dragFilesOver.emit(false)
31
+ }
32
+ }
33
+
34
+ @HostListener('drop', ['$event'])
35
+ _onDrop(event: DragEvent) {
36
+ event.preventDefault()
37
+ this.dragEnterCounter = 0
38
+ this.dragFilesOver.emit(false)
39
+
40
+ const files = Array.from(event.dataTransfer.files)
41
+ if (files.length > 0) {
42
+ this.dropFiles.emit(files)
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,146 @@
1
+ <ng-container *ngIf="previewUrl; then withImage; else withoutImage">
2
+ </ng-container>
3
+
4
+ <ng-template #withImage>
5
+ <div class="w-full h-full flex flex-col gap-2">
6
+ <div class="flex-1 group relative">
7
+ <img
8
+ class="w-full h-full object-cover border-2 border-gray-300 rounded-lg"
9
+ [alt]="altText"
10
+ loading="lazy"
11
+ [src]="previewUrl"
12
+ />
13
+ <gn-ui-button
14
+ [extraClass]="
15
+ 'bg-gray-200 absolute right-2 bottom-2 invisible group-hover:visible'
16
+ "
17
+ (buttonClick)="handleDelete()"
18
+ >
19
+ <mat-icon class="material-symbols-outlined">delete</mat-icon>
20
+ </gn-ui-button>
21
+ </div>
22
+ <input
23
+ *ngIf="showAltTextInput"
24
+ type="text"
25
+ class="py-3 px-2 border-2 border-gray-300 rounded-lg text-sm font-medium"
26
+ [placeholder]="'input.image.altTextPlaceholder' | translate"
27
+ [value]="altText"
28
+ (change)="handleAltTextChange($event)"
29
+ />
30
+ <div class="flex flex-row gap-2">
31
+ <gn-ui-button
32
+ [extraClass]="'bg-gray-200 font-bold'"
33
+ (buttonClick)="handleDelete()"
34
+ >
35
+ <mat-icon class="material-symbols-outlined me-1">delete</mat-icon>
36
+ {{ 'input.image.delete' | translate }}
37
+ </gn-ui-button>
38
+ <gn-ui-button
39
+ *ngIf="!showAltTextInput"
40
+ [extraClass]="'bg-gray-200 font-bold'"
41
+ (buttonClick)="toggleAltTextInput()"
42
+ >
43
+ <mat-icon class="material-symbols-outlined me-1">add</mat-icon>
44
+ {{ 'input.image.displayAltTextInput' | translate }}
45
+ </gn-ui-button>
46
+ </div>
47
+ </div>
48
+ </ng-template>
49
+
50
+ <ng-template #withoutImage>
51
+ <div class="w-full h-full flex flex-col gap-2">
52
+ <label
53
+ gnUiFilesDrop
54
+ class="block flex-1 border-2 border-dashed border-gray-300 rounded-lg p-6 flex flex-col items-center justify-center gap-4"
55
+ (dragFilesOver)="handleDragFilesOver($event)"
56
+ (dropFiles)="handleDropFiles($event)"
57
+ >
58
+ <div class="w-14 h-14 rounded-md bg-gray-200 grid">
59
+ <mat-icon
60
+ *ngIf="!dragFilesOver && !uploadProgress && !uploadError"
61
+ class="material-symbols-outlined place-self-center text-blue-500"
62
+ >image</mat-icon
63
+ >
64
+ <mat-icon
65
+ *ngIf="dragFilesOver && !uploadProgress && !uploadError"
66
+ class="material-symbols-outlined place-self-center text-blue-500"
67
+ >add_box</mat-icon
68
+ >
69
+ <div *ngIf="uploadProgress">
70
+ <mat-progress-spinner
71
+ class="place-self-center"
72
+ [diameter]="56"
73
+ [mode]="'determinate'"
74
+ [value]="uploadProgress"
75
+ ></mat-progress-spinner>
76
+ <span
77
+ class="text-sm font-medium relative inline-block width-[30px] bottom-[40px] left-[15px]"
78
+ >
79
+ {{ uploadProgress }}%
80
+ </span>
81
+ </div>
82
+ <mat-icon
83
+ *ngIf="uploadError"
84
+ class="material-symbols-outlined place-self-center text-rose-500"
85
+ >broken_image</mat-icon
86
+ >
87
+ </div>
88
+ <div class="flex flex-col items-center gap-1">
89
+ <p class="font-medium">{{ getPrimaryText() | translate }}</p>
90
+ <p
91
+ class="text-sm"
92
+ [class]="
93
+ uploadProgress || uploadError
94
+ ? 'font-bold text-blue-500 cursor-pointer'
95
+ : 'font-medium text-gray-500'
96
+ "
97
+ (click)="handleSecondaryTextClick()"
98
+ >
99
+ {{ getSecondaryText() | translate }}
100
+ </p>
101
+ </div>
102
+ <input
103
+ type="file"
104
+ class="hidden"
105
+ (change)="handleFileInput($event)"
106
+ [disabled]="showUrlInput || uploadProgress || uploadError"
107
+ />
108
+ </label>
109
+ <div *ngIf="!showUrlInput" class="flex-none">
110
+ <gn-ui-button
111
+ [extraClass]="'bg-gray-200 font-bold'"
112
+ (buttonClick)="displayUrlInput()"
113
+ >
114
+ <mat-icon class="material-symbols-outlined me-1">link</mat-icon>
115
+ {{ 'input.image.displayUrlInput' | translate }}
116
+ </gn-ui-button>
117
+ </div>
118
+ <div *ngIf="showUrlInput" class="flex-none flex flex-col gap-2">
119
+ <div class="h-2"></div>
120
+ <div class="flex gap-2 items-center">
121
+ <div class="flex-1 flex rounded-lg">
122
+ <span
123
+ class="material-symbols-outlined px-4 inline-flex items-center min-w-fit rounded-s-lg border-2 border-e-0 border-gray-300"
124
+ >link</span
125
+ >
126
+ <input
127
+ type="text"
128
+ class="py-3 ps-1 block w-full border-2 border-s-0 border-e-0 border-gray-300 text-sm font-medium"
129
+ placeholder="https://exemple.com/image.jpg"
130
+ (change)="handleUrlChange($event)"
131
+ />
132
+ <gn-ui-button
133
+ class="px-1 inline-flex items-center min-w-fit rounded-e-lg border-2 border-s-0 border-gray-300 text-white"
134
+ [extraClass]="
135
+ urlInputValue && !downloadError ? 'bg-blue-500' : 'bg-gray-500'
136
+ "
137
+ [disabled]="!urlInputValue || downloadError"
138
+ (buttonClick)="downloadUrl()"
139
+ >
140
+ <mat-icon class="material-symbols-outlined">arrow_upward</mat-icon>
141
+ </gn-ui-button>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ </div>
146
+ </ng-template>