geonetwork-ui 2.6.0-dev.97a89c313 → 2.6.0-dev.9b9a26109

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 (133) hide show
  1. package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +39 -4
  2. package/esm2022/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.mjs +1 -1
  3. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.mjs +8 -4
  4. package/esm2022/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.mjs +5 -2
  5. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +3 -3
  6. package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +2 -2
  7. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +3 -3
  8. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +60 -9
  9. package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +7 -1
  10. package/esm2022/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.mjs +2 -1
  11. package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
  12. package/esm2022/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.mjs +266 -11
  13. package/esm2022/libs/feature/record/src/lib/state/mdview.actions.mjs +3 -1
  14. package/esm2022/libs/feature/record/src/lib/state/mdview.effects.mjs +7 -1
  15. package/esm2022/libs/feature/record/src/lib/state/mdview.facade.mjs +3 -1
  16. package/esm2022/libs/feature/record/src/lib/state/mdview.reducer.mjs +7 -1
  17. package/esm2022/libs/feature/record/src/lib/state/mdview.selectors.mjs +3 -1
  18. package/esm2022/libs/feature/search/src/lib/results-table/results-table-container.component.mjs +13 -10
  19. package/esm2022/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.mjs +19 -34
  20. package/esm2022/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.mjs +59 -0
  21. package/esm2022/libs/ui/layout/src/lib/interactive-table/interactive-table.component.mjs +20 -10
  22. package/esm2022/libs/ui/search/src/index.mjs +2 -1
  23. package/esm2022/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.mjs +21 -12
  24. package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +39 -18
  25. package/esm2022/libs/ui/search/src/lib/ui-search.module.mjs +10 -4
  26. package/esm2022/libs/util/i18n/src/lib/i18n.constants.mjs +42 -1
  27. package/esm2022/libs/util/i18n/src/lib/language-codes.mjs +24 -2
  28. package/esm2022/translations/de.json +32 -6
  29. package/esm2022/translations/en.json +32 -6
  30. package/esm2022/translations/es.json +31 -5
  31. package/esm2022/translations/fr.json +32 -6
  32. package/esm2022/translations/it.json +31 -5
  33. package/esm2022/translations/nl.json +31 -5
  34. package/esm2022/translations/pt.json +31 -5
  35. package/fesm2022/geonetwork-ui.mjs +887 -205
  36. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  37. package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
  38. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts +0 -1
  39. package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts.map +1 -1
  40. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts +1 -0
  41. package/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.d.ts.map +1 -1
  42. package/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.d.ts.map +1 -1
  43. package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
  44. package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
  45. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts +1 -1
  46. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts.map +1 -1
  47. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +13 -2
  48. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  49. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts +2 -0
  50. package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
  51. package/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.d.ts +1 -0
  52. package/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.d.ts.map +1 -1
  53. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +6 -0
  54. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts.map +1 -1
  55. package/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.d.ts +48 -3
  56. package/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.d.ts.map +1 -1
  57. package/libs/feature/record/src/lib/state/mdview.actions.d.ts +10 -0
  58. package/libs/feature/record/src/lib/state/mdview.actions.d.ts.map +1 -1
  59. package/libs/feature/record/src/lib/state/mdview.effects.d.ts +6 -0
  60. package/libs/feature/record/src/lib/state/mdview.effects.d.ts.map +1 -1
  61. package/libs/feature/record/src/lib/state/mdview.facade.d.ts +2 -0
  62. package/libs/feature/record/src/lib/state/mdview.facade.d.ts.map +1 -1
  63. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts +2 -0
  64. package/libs/feature/record/src/lib/state/mdview.reducer.d.ts.map +1 -1
  65. package/libs/feature/record/src/lib/state/mdview.selectors.d.ts +2 -0
  66. package/libs/feature/record/src/lib/state/mdview.selectors.d.ts.map +1 -1
  67. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts +6 -5
  68. package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts.map +1 -1
  69. package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts +3 -6
  70. package/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.d.ts.map +1 -1
  71. package/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.d.ts +14 -0
  72. package/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.d.ts.map +1 -0
  73. package/libs/ui/layout/src/lib/interactive-table/interactive-table.component.d.ts +4 -2
  74. package/libs/ui/layout/src/lib/interactive-table/interactive-table.component.d.ts.map +1 -1
  75. package/libs/ui/search/src/index.d.ts +1 -0
  76. package/libs/ui/search/src/index.d.ts.map +1 -1
  77. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts +4 -3
  78. package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts.map +1 -1
  79. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +10 -4
  80. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
  81. package/libs/ui/search/src/lib/ui-search.module.d.ts +2 -1
  82. package/libs/ui/search/src/lib/ui-search.module.d.ts.map +1 -1
  83. package/libs/util/i18n/src/lib/i18n.constants.d.ts +1 -0
  84. package/libs/util/i18n/src/lib/i18n.constants.d.ts.map +1 -1
  85. package/libs/util/i18n/src/lib/language-codes.d.ts +23 -1
  86. package/libs/util/i18n/src/lib/language-codes.d.ts.map +1 -1
  87. package/package.json +1 -1
  88. package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +1 -1
  89. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +61 -4
  90. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +0 -1
  91. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +13 -3
  92. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +5 -1
  93. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +6 -3
  94. package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +4 -1
  95. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +2 -2
  96. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +96 -9
  97. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +11 -0
  98. package/src/libs/api/repository/src/lib/gn4/settings/gn4-settings.service.ts +3 -0
  99. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +6 -0
  100. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +49 -0
  101. package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.html +117 -11
  102. package/src/libs/feature/editor/src/lib/components/multilingual-panel/multilingual-panel.component.ts +316 -6
  103. package/src/libs/feature/record/src/lib/state/mdview.actions.ts +10 -0
  104. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +22 -0
  105. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +4 -0
  106. package/src/libs/feature/record/src/lib/state/mdview.reducer.ts +12 -0
  107. package/src/libs/feature/record/src/lib/state/mdview.selectors.ts +9 -0
  108. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.html +1 -0
  109. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +13 -3
  110. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.html +7 -75
  111. package/src/libs/ui/elements/src/lib/internal-link-card/internal-link-card.component.ts +20 -51
  112. package/src/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.html +69 -0
  113. package/src/libs/ui/elements/src/lib/internal-link-card-contact/internal-link-card-contact.component.ts +61 -0
  114. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +3 -2
  115. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +13 -6
  116. package/src/libs/ui/search/src/index.ts +1 -0
  117. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +16 -6
  118. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +15 -11
  119. package/src/libs/ui/search/src/lib/results-table/results-table.component.css +4 -0
  120. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +31 -27
  121. package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +33 -15
  122. package/src/libs/ui/search/src/lib/ui-search.module.ts +3 -0
  123. package/src/libs/util/i18n/src/lib/i18n.constants.ts +42 -0
  124. package/src/libs/util/i18n/src/lib/language-codes.ts +23 -1
  125. package/tailwind.base.css +1 -1
  126. package/translations/de.json +32 -6
  127. package/translations/en.json +32 -6
  128. package/translations/es.json +31 -5
  129. package/translations/fr.json +32 -6
  130. package/translations/it.json +31 -5
  131. package/translations/nl.json +31 -5
  132. package/translations/pt.json +31 -5
  133. package/translations/sk.json +31 -5
@@ -12,7 +12,7 @@ import { SearchService } from '../utils/service/search.service'
12
12
  import { RecordsRepositoryInterface } from '../../../../../../libs/common/domain/src/lib/repository/records-repository.interface'
13
13
  import { ResultsTableComponent } from '../../../../../../libs/ui/search/src'
14
14
  import { CommonModule } from '@angular/common'
15
- import { Subscription } from 'rxjs'
15
+ import { Observable, Subscription } from 'rxjs'
16
16
  import { NotificationsService } from '../../../../../../libs/feature/notifications/src'
17
17
  import { TranslateService } from '@ngx-translate/core'
18
18
 
@@ -24,8 +24,6 @@ import { TranslateService } from '@ngx-translate/core'
24
24
  imports: [CommonModule, ResultsTableComponent],
25
25
  })
26
26
  export class ResultsTableContainerComponent implements OnDestroy {
27
- @Input() canDuplicate: (record: CatalogRecord) => boolean = () => true
28
- @Input() canDelete: (record: CatalogRecord) => boolean = () => true
29
27
  @Input() isDuplicating: false
30
28
 
31
29
  @Output() recordClick = new EventEmitter<CatalogRecord>()
@@ -39,6 +37,18 @@ export class ResultsTableContainerComponent implements OnDestroy {
39
37
  hasDraft = (record: CatalogRecord): boolean =>
40
38
  this.recordsRepository.recordHasDraft(record.uniqueIdentifier)
41
39
 
40
+ canDuplicate = (record: CatalogRecord): boolean => {
41
+ return this.recordsRepository.canDuplicate(record)
42
+ }
43
+
44
+ canDelete = (record: CatalogRecord): Observable<boolean> => {
45
+ return this.recordsRepository.canDelete(record)
46
+ }
47
+
48
+ canEdit = (record: CatalogRecord): Observable<boolean> => {
49
+ return this.recordsRepository.canEditIndexedRecord(record)
50
+ }
51
+
42
52
  constructor(
43
53
  protected searchFacade: SearchFacade,
44
54
  private searchService: SearchService,
@@ -60,8 +60,9 @@
60
60
  </h4>
61
61
  </div>
62
62
  <div
63
- *ngIf="size === 'L'"
64
- class="mr-6 text-xs text-gray-900 line-clamp-2 overflow-hidden"
63
+ *ngIf="displayAbstract()"
64
+ class="mr-6 text-xs text-gray-900 overflow-hidden"
65
+ [ngClass]="getAbstractClass()"
65
66
  data-cy="recordAbstract"
66
67
  >
67
68
  <gn-ui-markdown-parser
@@ -71,80 +72,11 @@
71
72
  </div>
72
73
  </div>
73
74
 
74
- <div
75
- data-cy="recordOrg"
75
+ <gn-ui-internal-link-card-contact
76
76
  *ngIf="size !== 'XS' && record.ownerOrganization?.name"
77
- class="flex items-center justify-evenly bg-gray-50 rounded-lg h-[53px] px-2"
78
- >
79
- <div class="flex items-center flex-1 min-w-0">
80
- <div
81
- class="w-[45px] h-[45px] rounded-lg overflow-hidden shrink-0 mr-3"
82
- >
83
- <gn-ui-thumbnail
84
- [thumbnailUrl]="
85
- record.ownerOrganization?.logoUrl?.toString() || ''
86
- "
87
- [fit]="'contain'"
88
- class="w-full h-full rounded-lg"
89
- ></gn-ui-thumbnail>
90
- </div>
91
- <div *ngIf="organization?.name" class="flex-1 w-0 overflow-hidden">
92
- <div
93
- class="text-xs text-black font-normal leading-tight truncate"
94
- translate
95
- >
96
- record.card.metadata.contact
97
- </div>
98
- <div
99
- data-cy="recordOrgName"
100
- class="text-xl text-primary-black font-medium truncate"
101
- >
102
- {{ organization.name }}
103
- </div>
104
- </div>
105
- </div>
106
- <div *ngIf="size === 'L'" class="ml-2 flex space-x-2">
107
- <div *ngIf="organization?.website" class="flex">
108
- <button
109
- [title]="organization.website"
110
- class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
111
- (click)="openExternalUrl($event, organization.website)"
112
- >
113
- <ng-icon name="iconoirInternet"></ng-icon>
114
- </button>
115
- </div>
116
- <div *ngIf="contacts[0]?.email" class="flex">
117
- <button
118
- [title]="contacts[0].email"
119
- class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
120
- data-cy="contact-email"
121
- (click)="openMailto($event, contacts[0].email)"
122
- >
123
- <ng-icon name="matEmailOutline"></ng-icon>
124
- </button>
125
- </div>
126
- <div *ngIf="contacts[0]?.phone" class="flex">
127
- <button
128
- [title]="'Copy to clipboard'"
129
- class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
130
- data-cy="contact-phone"
131
- (click)="copyToClipboard($event, contacts[0].phone)"
132
- >
133
- <ng-icon name="matPhoneOutline"></ng-icon>
134
- </button>
135
- </div>
136
- <div *ngIf="contacts[0]?.address" class="flex">
137
- <button
138
- [title]="'Copy to clipboard'"
139
- class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
140
- data-cy="contact-phone"
141
- (click)="copyToClipboard($event, contacts[0].address)"
142
- >
143
- <ng-icon name="matLocationOnOutline"></ng-icon>
144
- </button>
145
- </div>
146
- </div>
147
- </div>
77
+ [record]="record"
78
+ [size]="size"
79
+ ></gn-ui-internal-link-card-contact>
148
80
  </div>
149
81
  </div>
150
82
  </div>
@@ -7,35 +7,20 @@ import {
7
7
  EventEmitter,
8
8
  ElementRef,
9
9
  } from '@angular/core'
10
- import {
11
- CatalogRecord,
12
- Organization,
13
- } from '../../../../../../libs/common/domain/src/lib/model/record'
10
+ import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
14
11
  import { NgClass, NgIf, NgTemplateOutlet } from '@angular/common'
15
12
  import { GeoDataBadgeComponent } from '../geo-data-badge/geo-data-badge.component'
16
13
  import { KindBadgeComponent } from '../kind-badge/kind-badge.component'
17
14
  import { MarkdownParserComponent } from '../markdown-parser/markdown-parser.component'
18
15
  import { MetadataQualityComponent } from '../metadata-quality/metadata-quality.component'
19
- import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
20
- import {
21
- propagateToDocumentOnly,
22
- removeWhitespace,
23
- stripHtml,
24
- } from '../../../../../../libs/util/shared/src'
25
- import {
26
- NgIconComponent,
27
- provideIcons,
28
- provideNgIconsConfig,
29
- } from '@ng-icons/core'
30
- import {
31
- matLocationSearchingOutline,
32
- matEmailOutline,
33
- matPhoneOutline,
34
- matLocationOnOutline,
35
- } from '@ng-icons/material-icons/outline'
16
+ import { InternalLinkCardContactComponent } from '../internal-link-card-contact/internal-link-card-contact.component'
17
+ import { removeWhitespace, stripHtml } from '../../../../../../libs/util/shared/src'
18
+ import { provideIcons, provideNgIconsConfig } from '@ng-icons/core'
19
+ import { matLocationSearchingOutline } from '@ng-icons/material-icons/outline'
36
20
  import { iconoirInternet } from '@ng-icons/iconoir'
37
21
  import { TranslateModule } from '@ngx-translate/core'
38
22
  import { fromEvent, Subscription } from 'rxjs'
23
+ import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
39
24
 
40
25
  type CardSize = 'L' | 'M' | 'S' | 'XS'
41
26
 
@@ -45,22 +30,19 @@ type CardSize = 'L' | 'M' | 'S' | 'XS'
45
30
  imports: [
46
31
  NgClass,
47
32
  NgIf,
48
- ThumbnailComponent,
49
33
  MetadataQualityComponent,
50
34
  NgTemplateOutlet,
51
- NgIconComponent,
52
35
  TranslateModule,
53
36
  GeoDataBadgeComponent,
54
37
  KindBadgeComponent,
55
38
  MarkdownParserComponent,
39
+ InternalLinkCardContactComponent,
40
+ ThumbnailComponent,
56
41
  ],
57
42
  providers: [
58
43
  provideIcons({
59
44
  iconoirInternet,
60
45
  matLocationSearchingOutline,
61
- matEmailOutline,
62
- matPhoneOutline,
63
- matLocationOnOutline,
64
46
  }),
65
47
  provideNgIconsConfig({
66
48
  size: '1.2em',
@@ -125,35 +107,22 @@ export class InternalLinkCardComponent implements OnInit {
125
107
  )
126
108
  }
127
109
 
128
- get organization(): Organization {
129
- return this.record.ownerOrganization
130
- }
131
-
132
- get contacts() {
133
- return (
134
- (this.record.kind === 'dataset'
135
- ? this.record.contactsForResource
136
- : this.record.contacts) || []
137
- )
138
- }
139
-
140
110
  getTitleClass() {
141
111
  return this.titleClassMap[this._size]
142
112
  }
143
-
144
- openExternalUrl(event: Event, url: URL): void {
145
- event.stopPropagation()
146
- window.open(url, '_blank')
147
- }
148
-
149
- openMailto(event: Event, email: string): void {
150
- event.stopPropagation()
151
- window.open(`mailto:${email}`, '_blank')
113
+ getAbstractClass(): string {
114
+ const marginClass = ['S', 'XS'].includes(this.size) ? 'ml-2' : ''
115
+ const clampClass =
116
+ this.size === 'L' && !this.record.ownerOrganization?.name
117
+ ? 'line-clamp-6'
118
+ : 'line-clamp-2'
119
+ return `${clampClass} ${marginClass}`.trim()
152
120
  }
153
-
154
- copyToClipboard(event: Event, text: string): void {
155
- event.stopPropagation()
156
- navigator.clipboard.writeText(text)
121
+ displayAbstract(): boolean {
122
+ return (
123
+ this.size === 'L' ||
124
+ (['M', 'S'].includes(this.size) && !this.record.ownerOrganization?.name)
125
+ )
157
126
  }
158
127
 
159
128
  get shouldShowThumbnail(): boolean {
@@ -0,0 +1,69 @@
1
+ <div
2
+ data-cy="recordOrg"
3
+ class="flex items-center justify-evenly bg-gray-50 rounded-lg h-[53px] px-2"
4
+ >
5
+ <div class="flex items-center flex-1 min-w-0">
6
+ <div class="w-[45px] h-[45px] rounded-lg overflow-hidden shrink-0 mr-3">
7
+ <gn-ui-thumbnail
8
+ [thumbnailUrl]="record.ownerOrganization?.logoUrl?.toString() || ''"
9
+ [fit]="'contain'"
10
+ class="w-full h-full rounded-lg"
11
+ ></gn-ui-thumbnail>
12
+ </div>
13
+ <div *ngIf="organization?.name" class="flex-1 w-0 overflow-hidden">
14
+ <div
15
+ class="text-xs text-black font-normal leading-tight truncate"
16
+ translate
17
+ >
18
+ record.card.metadata.contact
19
+ </div>
20
+ <div
21
+ data-cy="recordOrgName"
22
+ class="text-xl text-primary-black font-medium truncate"
23
+ >
24
+ {{ organization.name }}
25
+ </div>
26
+ </div>
27
+ </div>
28
+ <div *ngIf="size === 'L'" class="ml-2 flex space-x-2">
29
+ <div *ngIf="organization?.website" class="flex">
30
+ <button
31
+ [title]="organization.website"
32
+ class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
33
+ (click)="openExternalUrl($event, organization.website)"
34
+ >
35
+ <ng-icon name="iconoirInternet"></ng-icon>
36
+ </button>
37
+ </div>
38
+ <div *ngIf="contacts[0]?.email" class="flex">
39
+ <button
40
+ [title]="contacts[0].email"
41
+ class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest"
42
+ data-cy="contact-email"
43
+ (click)="openMailto($event, contacts[0].email)"
44
+ >
45
+ <ng-icon name="matEmailOutline"></ng-icon>
46
+ </button>
47
+ </div>
48
+ <div *ngIf="contacts[0]?.phone" class="flex">
49
+ <button
50
+ [title]="'Copy to clipboard'"
51
+ class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
52
+ data-cy="contact-phone"
53
+ (click)="copyToClipboard($event, contacts[0].phone)"
54
+ >
55
+ <ng-icon name="matPhoneOutline"></ng-icon>
56
+ </button>
57
+ </div>
58
+ <div *ngIf="contacts[0]?.address" class="flex">
59
+ <button
60
+ [title]="'Copy to clipboard'"
61
+ class="w-[40px] h-[32px] flex items-center justify-center rounded-lg border border-[#D4D3D7] px-[8px] py-[4px] hover:bg-primary-lightest relative group"
62
+ data-cy="contact-phone"
63
+ (click)="copyToClipboard($event, contacts[0].address)"
64
+ >
65
+ <ng-icon name="matLocationOnOutline"></ng-icon>
66
+ </button>
67
+ </div>
68
+ </div>
69
+ </div>
@@ -0,0 +1,61 @@
1
+ import { Component, Input } from '@angular/core'
2
+ import { NgIf } from '@angular/common'
3
+ import {
4
+ CatalogRecord,
5
+ Organization,
6
+ } from '../../../../../../libs/common/domain/src/lib/model/record'
7
+ import { ThumbnailComponent } from '../thumbnail/thumbnail.component'
8
+ import { NgIconComponent, provideIcons } from '@ng-icons/core'
9
+ import {
10
+ matEmailOutline,
11
+ matPhoneOutline,
12
+ matLocationOnOutline,
13
+ } from '@ng-icons/material-icons/outline'
14
+ import { iconoirInternet } from '@ng-icons/iconoir'
15
+ import { TranslateModule } from '@ngx-translate/core'
16
+
17
+ @Component({
18
+ selector: 'gn-ui-internal-link-card-contact',
19
+ standalone: true,
20
+ imports: [NgIf, ThumbnailComponent, NgIconComponent, TranslateModule],
21
+ providers: [
22
+ provideIcons({
23
+ iconoirInternet,
24
+ matEmailOutline,
25
+ matPhoneOutline,
26
+ matLocationOnOutline,
27
+ }),
28
+ ],
29
+ templateUrl: './internal-link-card-contact.component.html',
30
+ })
31
+ export class InternalLinkCardContactComponent {
32
+ @Input() record: CatalogRecord
33
+ @Input() size: 'L' | 'M' | 'S' | 'XS' = 'M'
34
+
35
+ get organization(): Organization {
36
+ return this.record.ownerOrganization
37
+ }
38
+
39
+ get contacts() {
40
+ return (
41
+ (this.record.kind === 'dataset'
42
+ ? this.record.contactsForResource
43
+ : this.record.contacts) || []
44
+ )
45
+ }
46
+
47
+ openExternalUrl(event: Event, url: URL): void {
48
+ event.stopPropagation()
49
+ window.open(url, '_blank')
50
+ }
51
+
52
+ openMailto(event: Event, email: string): void {
53
+ event.stopPropagation()
54
+ window.open(`mailto:${email}`, '_blank')
55
+ }
56
+
57
+ copyToClipboard(event: Event, text: string): void {
58
+ event.stopPropagation()
59
+ navigator.clipboard.writeText(text)
60
+ }
61
+ }
@@ -31,6 +31,7 @@
31
31
  *ngFor="let item of items"
32
32
  (click)="handleRowClick(item)"
33
33
  data-cy="table-row"
34
+ [attr.data-cy-title]="item.title"
34
35
  [title]="getItemTitle(item) | translate"
35
36
  >
36
37
  <div
@@ -48,9 +49,9 @@
48
49
  class="table-row-cell px-3 py-1.5 flex items-center bg-white transition-colors duration-75 truncate border-b border-gray-200"
49
50
  [ngClass]="{
50
51
  'text-purple-light cursor-default':
51
- (!item.extras?.edit && !isDraftPage) || item.kind !== 'dataset',
52
+ (canEditItem(item) | async) === false,
52
53
  'group-hover:text-main group-hover:bg-gray-50':
53
- (item.extras?.edit || isDraftPage) && item.kind === 'dataset',
54
+ canEditItem(item) | async,
54
55
  }"
55
56
  >
56
57
  <ng-container
@@ -14,9 +14,11 @@ import { iconoirNavArrowDown, iconoirNavArrowUp } from '@ng-icons/iconoir'
14
14
  import { TranslateModule } from '@ngx-translate/core'
15
15
  import { marker } from '@biesbjerg/ngx-translate-extract-marker'
16
16
  import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
17
+ import { Observable, of } from 'rxjs'
17
18
 
18
- marker('editor.record.lock.reason')
19
- marker('editor.record.lock.format')
19
+ marker('editor.record.lock.resourceType')
20
+ marker('editor.record.lock.harvested')
21
+ marker('editor.record.lock.owner')
20
22
  @Component({
21
23
  selector: 'gn-ui-interactive-table',
22
24
  templateUrl: './interactive-table.component.html',
@@ -31,6 +33,7 @@ export class InteractiveTableComponent {
31
33
  columns: QueryList<InteractiveTableColumnComponent>
32
34
 
33
35
  @Input() items: unknown[] = []
36
+ @Input() canEditItem: (item: unknown) => Observable<boolean> = () => of(true)
34
37
  @Input() isDraftPage = false
35
38
  @Output() itemClick = new EventEmitter<unknown>()
36
39
 
@@ -49,10 +52,14 @@ export class InteractiveTableComponent {
49
52
  }
50
53
 
51
54
  getItemTitle(item: CatalogRecord) {
52
- if (!item.extras?.edit && !this.isDraftPage && item.kind === 'dataset') {
53
- return 'editor.record.lock.reason'
54
- } else if (item.kind !== 'dataset') {
55
- return 'editor.record.lock.format'
55
+ if (!this.isDraftPage) {
56
+ if (item.kind !== 'dataset') {
57
+ return 'editor.record.lock.resourceType'
58
+ } else if (item.extras?.isHarvested) {
59
+ return 'editor.record.lock.harvested'
60
+ } else if (!item.extras?.edit) {
61
+ return 'editor.record.lock.owner'
62
+ }
56
63
  }
57
64
  return ''
58
65
  }
@@ -19,3 +19,4 @@ export * from './lib/results-list-item/results-list-item.component'
19
19
  export * from './lib/results-hits-search-kind/results-hits-search-kind.component'
20
20
  export * from './lib/results-hits-number/results-hits-number.component'
21
21
  export * from './lib/results-table/results-table.component'
22
+ export * from './lib/results-table/action-menu/action-menu.component'
@@ -6,17 +6,27 @@
6
6
  >
7
7
  <ul class="flex flex-col gap-2 w-full">
8
8
  <gn-ui-button
9
- *ngIf="!isDraftPage"
9
+ *ngIf="page === 'main'"
10
10
  type="light"
11
11
  extraClass="flex flex-row items-center gap-2 w-full justify-start"
12
12
  (buttonClick)="duplicate.emit()"
13
13
  [disabled]="!canDuplicate"
14
14
  data-test="record-menu-duplicate-button"
15
15
  >
16
- <span *ngIf="canDuplicate" translate>record.action.duplicate</span>
17
- <span *ngIf="!canDuplicate" translate
16
+ <span *ngIf="isDuplicating; else notDuplicating" translate
18
17
  >record.action.duplicating</span
19
- ></gn-ui-button
18
+ >
19
+ <ng-template #notDuplicating>
20
+ <span translate>record.action.duplicate</span>
21
+ </ng-template>
22
+ </gn-ui-button>
23
+ <gn-ui-button
24
+ *ngIf="page === 'record'"
25
+ type="light"
26
+ extraClass="flex flex-row items-center gap-2 w-full justify-start"
27
+ (buttonClick)="switch.emit()"
28
+ data-test="record-menu-switch-button"
29
+ ><span translate>record.action.switchLang</span></gn-ui-button
20
30
  >
21
31
  <gn-ui-button
22
32
  type="light"
@@ -24,8 +34,8 @@
24
34
  (buttonClick)="displayDeleteMenu()"
25
35
  [disabled]="!canDelete"
26
36
  data-test="record-menu-delete-button"
27
- ><span *ngIf="!isDraftPage" translate>record.action.delete</span>
28
- <span *ngIf="isDraftPage" translate
37
+ ><span *ngIf="page !== 'draft'" translate>record.action.delete</span>
38
+ <span *ngIf="page === 'draft'" translate
29
39
  >record.action.rollback</span
30
40
  ></gn-ui-button
31
41
  >
@@ -30,13 +30,15 @@ type ActionMenuPage = 'mainMenu' | 'deleteMenu' | 'rollbackMenu'
30
30
  ],
31
31
  })
32
32
  export class ActionMenuComponent {
33
- @Input() canDuplicate: boolean
34
- @Input() canDelete: boolean
35
- @Input() isDraftPage: boolean
33
+ @Input() canDuplicate = true
34
+ @Input() isDuplicating: boolean
35
+ @Input() canDelete = true
36
+ @Input() page: 'draft' | 'main' | 'record'
36
37
  @Output() duplicate = new EventEmitter<void>()
37
38
  @Output() delete = new EventEmitter<void>()
38
39
  @Output() closeActionMenu = new EventEmitter<void>()
39
40
  @Output() rollback = new EventEmitter<void>()
41
+ @Output() switch = new EventEmitter<void>()
40
42
 
41
43
  @ViewChild(MatMenuTrigger) trigger: MatMenuTrigger
42
44
 
@@ -47,20 +49,22 @@ export class ActionMenuComponent {
47
49
  private cdr: ChangeDetectorRef
48
50
  ) {}
49
51
 
50
- openMenu() {
51
- this.trigger.openMenu()
52
- }
53
-
54
52
  displayMainMenu() {
55
53
  this.sectionDisplayed = 'mainMenu'
56
54
  this.cdr.markForCheck()
57
55
  }
58
56
 
59
57
  displayDeleteMenu() {
60
- if (this.isDraftPage) {
61
- this.sectionDisplayed = 'rollbackMenu'
62
- } else {
63
- this.sectionDisplayed = 'deleteMenu'
58
+ switch (this.page) {
59
+ case 'draft':
60
+ this.sectionDisplayed = 'rollbackMenu'
61
+ break
62
+ case 'record':
63
+ this.delete.emit()
64
+ break
65
+ case 'main':
66
+ default:
67
+ this.sectionDisplayed = 'deleteMenu'
64
68
  }
65
69
  this.cdr.markForCheck()
66
70
  }
@@ -0,0 +1,4 @@
1
+ :host {
2
+ --gn-ui-button-height: 40px;
3
+ --gn-ui-button-width: 40px;
4
+ }
@@ -1,5 +1,6 @@
1
1
  <gn-ui-interactive-table
2
2
  [items]="records"
3
+ [canEditItem]="canEdit"
3
4
  [isDraftPage]="isDraftPage"
4
5
  (itemClick)="handleRecordClick($event)"
5
6
  >
@@ -9,15 +10,16 @@
9
10
  <ng-icon
10
11
  name="iconoirLock"
11
12
  class="text-purple"
12
- *ngIf="(!item.extras?.edit && !isDraftPage) || item.kind !== 'dataset'"
13
+ *ngIf="(canEdit(item) | async) === false; else selectCheckbox"
13
14
  ></ng-icon>
14
- <gn-ui-checkbox
15
- *ngIf="(item.extras?.edit || isDraftPage) && item.kind === 'dataset'"
16
- [checked]="isChecked(item)"
17
- (changed)="handleRecordSelectedChange($event, item)"
18
- class="-m-2"
19
- type="default"
20
- ></gn-ui-checkbox>
15
+ <ng-template #selectCheckbox>
16
+ <gn-ui-checkbox
17
+ [checked]="isChecked(item)"
18
+ (changed)="handleRecordSelectedChange($event, item)"
19
+ class="-m-2"
20
+ type="default"
21
+ ></gn-ui-checkbox>
22
+ </ng-template>
21
23
  </ng-template>
22
24
  </gn-ui-interactive-table-column>
23
25
 
@@ -143,29 +145,31 @@
143
145
  <gn-ui-interactive-table-column>
144
146
  <ng-template #header> </ng-template>
145
147
  <ng-template #cell let-item>
146
- <gn-ui-button
147
- cdkOverlayOrigin
148
- #actionMenuButton
149
- (buttonClick)="openActionMenu(item, template)"
150
- type="light"
151
- data-test="record-menu-button"
152
- [disabled]="
153
- (!item.extras?.edit && !isDraftPage) || item.kind !== 'dataset'
154
- "
155
- >
148
+ <div class="flex justify-end items-center gap-4 w-full">
149
+ <!-- IS MULTILINGUAL -->
156
150
  <ng-icon
157
- [ngClass]="{
158
- 'text-purple-light':
159
- (!item.extras?.edit && !isDraftPage) || item.kind !== 'dataset',
160
- }"
161
- name="matMoreVert"
151
+ *ngIf="isMultilingual(item)"
152
+ data-cy="multilingual-indicator"
153
+ name="iconoirTranslate"
154
+ [attr.title]="getTxtHoverMultilingual(item)"
162
155
  ></ng-icon>
163
- </gn-ui-button>
156
+ <!-- MORE ACTIONS MENU BUTTON -->
157
+ <gn-ui-button
158
+ cdkOverlayOrigin
159
+ #actionMenuButton
160
+ (buttonClick)="openActionMenu(item, template)"
161
+ type="light"
162
+ data-test="record-menu-button"
163
+ >
164
+ <ng-icon name="matMoreVert"></ng-icon>
165
+ </gn-ui-button>
166
+ </div>
164
167
  <ng-template #template>
165
168
  <gn-ui-action-menu
166
- [canDuplicate]="canDuplicate(item) && !isDuplicating"
167
- [canDelete]="canDelete(item)"
168
- [isDraftPage]="isDraftPage"
169
+ [canDuplicate]="canDuplicate(item)"
170
+ [isDuplicating]="isDuplicating"
171
+ [canDelete]="canDelete(item) | async"
172
+ [page]="isDraftPage ? 'draft' : 'main'"
169
173
  (duplicate)="handleDuplicate(item)"
170
174
  (delete)="handleDelete(item)"
171
175
  (closeActionMenu)="closeActionMenu()"