@datagouv/components-next 1.0.2-dev.235 → 1.0.2-dev.236
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ImagePreview.client-CSRz7eUF.js → ImagePreview.client-DLua0loY.js} +7 -7
- package/dist/{JsonPreview.client-wT2hfYLv.js → JsonPreview.client-BccnDGn0.js} +2 -2
- package/dist/{PdfPreview.client-DifxM8Th.js → PdfPreview.client-BqkVStKD.js} +2 -2
- package/dist/{Pmtiles.client-OyXiX_7g.js → Pmtiles.client-CTXTfoSy.js} +11 -11
- package/dist/{PreviewWrapper-D7yfQyyH.js → PreviewWrapper-BnFrOpCg.js} +1 -1
- package/dist/{XmlPreview.client-BkPGZLn6.js → XmlPreview.client-sKyOWR0L.js} +2 -2
- package/dist/components-next.js +10625 -10501
- package/dist/components.css +1 -1
- package/dist/{vue-D5eMxsCr.js → config-jrnuUDOH.js} +6542 -6540
- package/dist/{france-BNatwStf.js → france-Ub9ufuh4.js} +66 -66
- package/dist/{resources-kuI_FosB.js → resources-DuiPzI4e.js} +22 -22
- package/package.json +1 -1
- package/src/components/ActivityList/ActivityActor.vue +38 -0
- package/src/components/ActivityList/ActivityList.vue +70 -84
- package/src/components/AvatarWithName.vue +40 -16
- package/src/functions/activities.ts +111 -0
- package/src/functions/users.ts +10 -1
- package/src/main.ts +2 -0
- package/src/types/activity.ts +25 -5
|
@@ -1,29 +1,49 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<span class="inline-flex items-center space-x-1">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{{
|
|
16
|
-
|
|
17
|
-
|
|
3
|
+
<!-- A deleted account has no name left to show and no page left to link to, so it
|
|
4
|
+
gets a neutral mark instead of the identicon generated from its identifier. -->
|
|
5
|
+
<template v-if="isDeleted">
|
|
6
|
+
<span
|
|
7
|
+
class="inline-flex flex-none items-center justify-center rounded-full border border-gray-default text-gray-medium"
|
|
8
|
+
:style="{ width: `${size}px`, height: `${size}px` }"
|
|
9
|
+
>
|
|
10
|
+
<RiUserLine
|
|
11
|
+
:size="String(Math.round(size * 0.6))"
|
|
12
|
+
aria-hidden="true"
|
|
13
|
+
/>
|
|
14
|
+
</span>
|
|
15
|
+
<span class="rounded bg-gray-some px-1.5 py-0.5 text-[11px] leading-5 text-gray-medium">{{ t('Compte supprimé') }}</span>
|
|
16
|
+
</template>
|
|
17
|
+
<template v-else>
|
|
18
|
+
<Avatar
|
|
19
|
+
v-bind="$attrs"
|
|
20
|
+
:user="user"
|
|
21
|
+
:size
|
|
22
|
+
:rounded="true"
|
|
23
|
+
/>
|
|
24
|
+
<component
|
|
25
|
+
:is="withLink ? AppLink : 'span'"
|
|
26
|
+
:to="withLink ? user.page : undefined"
|
|
27
|
+
class="truncate"
|
|
28
|
+
:class="{ 'font-bold': withLink }"
|
|
29
|
+
>
|
|
30
|
+
{{ user.first_name }}
|
|
31
|
+
{{ user.last_name }}
|
|
32
|
+
</component>
|
|
33
|
+
</template>
|
|
18
34
|
</span>
|
|
19
35
|
</template>
|
|
20
36
|
|
|
21
37
|
<script setup lang="ts">
|
|
38
|
+
import { RiUserLine } from '@remixicon/vue'
|
|
39
|
+
import { computed } from 'vue'
|
|
40
|
+
import { useTranslation } from '../composables/useTranslation'
|
|
41
|
+
import { isDeletedUser } from '../functions/users'
|
|
22
42
|
import type { User, UserReference } from '../types/users'
|
|
23
43
|
import AppLink from './AppLink.vue'
|
|
24
44
|
import Avatar from './Avatar.vue'
|
|
25
45
|
|
|
26
|
-
withDefaults(defineProps<{
|
|
46
|
+
const props = withDefaults(defineProps<{
|
|
27
47
|
user: User | UserReference
|
|
28
48
|
size?: number
|
|
29
49
|
withLink?: boolean
|
|
@@ -31,4 +51,8 @@ withDefaults(defineProps<{
|
|
|
31
51
|
size: 12,
|
|
32
52
|
withLink: true,
|
|
33
53
|
})
|
|
54
|
+
|
|
55
|
+
const { t } = useTranslation()
|
|
56
|
+
|
|
57
|
+
const isDeleted = computed(() => isDeletedUser(props.user))
|
|
34
58
|
</script>
|
|
@@ -34,3 +34,114 @@ export function getActivityTranslation(activity: Activity): string {
|
|
|
34
34
|
|
|
35
35
|
return translations[activity.key] || activity.label || activity.key
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* `changes` holds the model attribute paths the backend recorded, which are neither
|
|
40
|
+
* translated nor meant to be read as is.
|
|
41
|
+
*/
|
|
42
|
+
function getChangeLabels(): Record<string, string> {
|
|
43
|
+
const { t } = useTranslation()
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
// Shared across the models an activity can be about
|
|
47
|
+
'title': t('Titre'),
|
|
48
|
+
'name': t('Nom'),
|
|
49
|
+
'acronym': t('Sigle'),
|
|
50
|
+
'slug': t('Identifiant d\'URL'),
|
|
51
|
+
'description': t('Description'),
|
|
52
|
+
'description_short': t('Description courte'),
|
|
53
|
+
'tags': t('Mots-clés'),
|
|
54
|
+
'license': t('Licence'),
|
|
55
|
+
'private': t('Visibilité'),
|
|
56
|
+
'featured': t('Mise en avant'),
|
|
57
|
+
'badges': t('Badges'),
|
|
58
|
+
'owner': t('Propriétaire'),
|
|
59
|
+
'organization': t('Organisation'),
|
|
60
|
+
'archived': t('Archivage'),
|
|
61
|
+
'archived_at': t('Archivage'),
|
|
62
|
+
'archived_reason': t('Motif d\'archivage'),
|
|
63
|
+
'deleted': t('Suppression'),
|
|
64
|
+
'deleted_at': t('Suppression'),
|
|
65
|
+
'extras': t('Données supplémentaires'),
|
|
66
|
+
'url': t('URL'),
|
|
67
|
+
'created_at': t('Date de création'),
|
|
68
|
+
'created_at_internal': t('Date de création'),
|
|
69
|
+
'last_modified_internal': t('Date de modification'),
|
|
70
|
+
'spatial': t('Couverture géographique'),
|
|
71
|
+
'spatial.zones': t('Couverture géographique (zones)'),
|
|
72
|
+
'spatial.geom': t('Couverture géographique (tracé)'),
|
|
73
|
+
'spatial.granularity': t('Granularité géographique'),
|
|
74
|
+
'contact_points': t('Points de contact'),
|
|
75
|
+
|
|
76
|
+
// Dataset
|
|
77
|
+
'frequency': t('Fréquence de mise à jour'),
|
|
78
|
+
'frequency_date': t('Date de prochaine mise à jour'),
|
|
79
|
+
'temporal_coverage': t('Couverture temporelle'),
|
|
80
|
+
'schema': t('Schéma'),
|
|
81
|
+
'last_update': t('Date de dernière mise à jour'),
|
|
82
|
+
'access_type': t('Type d\'accès'),
|
|
83
|
+
'access_audiences': t('Publics concernés'),
|
|
84
|
+
'access_type_reason_category': t('Motif de restriction d\'accès'),
|
|
85
|
+
|
|
86
|
+
// Reuse
|
|
87
|
+
'type': t('Type'),
|
|
88
|
+
'image': t('Image'),
|
|
89
|
+
'datasets': t('Jeux de données'),
|
|
90
|
+
'dataservices': t('Services de données'),
|
|
91
|
+
'topic': t('Thématique'),
|
|
92
|
+
|
|
93
|
+
// Organization
|
|
94
|
+
'image_url': t('Logo'),
|
|
95
|
+
'logo': t('Logo'),
|
|
96
|
+
'business_number_id': t('Numéro SIRET'),
|
|
97
|
+
'presentation_blocs': t('Blocs de présentation'),
|
|
98
|
+
'presentation_blocs_published_at': t('Publication des blocs de présentation'),
|
|
99
|
+
'members': t('Membres'),
|
|
100
|
+
'teams': t('Équipes'),
|
|
101
|
+
'zone': t('Zone'),
|
|
102
|
+
|
|
103
|
+
// Dataservice
|
|
104
|
+
'base_api_url': t('URL de base de l\'API'),
|
|
105
|
+
'machine_documentation_url': t('Documentation machine'),
|
|
106
|
+
'technical_documentation_url': t('Documentation technique'),
|
|
107
|
+
'business_documentation_url': t('Documentation fonctionnelle'),
|
|
108
|
+
'rate_limiting': t('Limitation de débit'),
|
|
109
|
+
'rate_limiting_url': t('URL de la limitation de débit'),
|
|
110
|
+
'availability': t('Disponibilité'),
|
|
111
|
+
'availability_url': t('URL de la disponibilité'),
|
|
112
|
+
'format': t('Format'),
|
|
113
|
+
'uri': t('URI'),
|
|
114
|
+
'issued_at': t('Date de publication'),
|
|
115
|
+
'modified_at': t('Date de modification'),
|
|
116
|
+
'metadata_modified_at': t('Date de modification des métadonnées'),
|
|
117
|
+
'backend': t('Moissonnage : connecteur'),
|
|
118
|
+
'domain': t('Moissonnage : domaine'),
|
|
119
|
+
'source_id': t('Moissonnage : identifiant de la source'),
|
|
120
|
+
'source_url': t('Moissonnage : URL de la source'),
|
|
121
|
+
'remote_id': t('Moissonnage : identifiant distant'),
|
|
122
|
+
'remote_url': t('Moissonnage : URL distante'),
|
|
123
|
+
|
|
124
|
+
// Topic
|
|
125
|
+
'color': t('Couleur'),
|
|
126
|
+
'elements': t('Éléments'),
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The same attribute name can mean different things depending on what the activity is
|
|
132
|
+
* about, `related_to_kind` being what tells them apart.
|
|
133
|
+
*/
|
|
134
|
+
const CHANGE_LABELS_BY_KIND: Record<string, Record<string, string>> = {
|
|
135
|
+
Organization: { url: 'Site web' },
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function getActivityChangeLabel(activity: Activity, change: string): string {
|
|
139
|
+
const { t } = useTranslation()
|
|
140
|
+
const perKind = CHANGE_LABELS_BY_KIND[activity.related_to_kind]?.[change]
|
|
141
|
+
if (perKind) return t(perKind)
|
|
142
|
+
|
|
143
|
+
const labels = getChangeLabels()
|
|
144
|
+
// An embedded attribute the backend reports on its own (`spatial.zones`) falls back
|
|
145
|
+
// to the label of the attribute holding it rather than to its raw path.
|
|
146
|
+
return labels[change] ?? labels[change.split('.')[0]!] ?? change
|
|
147
|
+
}
|
package/src/functions/users.ts
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
|
-
import type { UserReference } from '../types/users'
|
|
1
|
+
import type { User, UserReference } from '../types/users'
|
|
2
2
|
import { useComponentsConfig } from '../config'
|
|
3
3
|
|
|
4
4
|
// Accept UserReference or UserSuggest (which has avatar_url instead of avatar_thumbnail)
|
|
5
5
|
type UserWithAvatar = UserReference | (Pick<UserReference, 'id'> & { avatar_url?: string | null })
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Deleting an account anonymises it in place: the names become `DELETED` and the slug
|
|
9
|
+
* `deleted-<id>`. The slug is what identifies it, being unique and out of the user's
|
|
10
|
+
* reach, where someone may legitimately be named DELETED.
|
|
11
|
+
*/
|
|
12
|
+
export function isDeletedUser(user: User | UserReference): boolean {
|
|
13
|
+
return user.slug.startsWith('deleted-')
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
export function useGetUserAvatar() {
|
|
8
17
|
const config = useComponentsConfig()
|
|
9
18
|
return (user: UserWithAvatar, size: number) => {
|
package/src/main.ts
CHANGED
|
@@ -30,6 +30,7 @@ import { getDefaultDatasetConfig, getDefaultDataserviceConfig, getDefaultReuseCo
|
|
|
30
30
|
import { useSearchFilter } from './composables/useSearchFilter'
|
|
31
31
|
import type { UseSearchFilterOptions } from './composables/useSearchFilter'
|
|
32
32
|
|
|
33
|
+
import ActivityActor from './components/ActivityList/ActivityActor.vue'
|
|
33
34
|
import ActivityList from './components/ActivityList/ActivityList.vue'
|
|
34
35
|
import UserActivityList from './components/ActivityList/UserActivityList.vue'
|
|
35
36
|
import AnimatedLoader from './components/AnimatedLoader.vue'
|
|
@@ -341,6 +342,7 @@ const datagouv: Plugin<PluginConfig> = {
|
|
|
341
342
|
export {
|
|
342
343
|
datagouv,
|
|
343
344
|
useComponentsConfig,
|
|
345
|
+
ActivityActor,
|
|
344
346
|
ActivityList,
|
|
345
347
|
AnimatedLoader,
|
|
346
348
|
AppLink,
|
package/src/types/activity.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { OrganizationReference } from './organizations'
|
|
2
|
+
import type { UserReference } from './users'
|
|
3
3
|
|
|
4
4
|
export type ActivityKey = 'dataset:created' | 'dataset:updated' | 'dataset:deleted' | 'dataset:discussed' | 'dataset:followed'
|
|
5
5
|
| 'dataset:resource:added' | 'dataset:resource:updated' | 'dataset:resource:deleted'
|
|
@@ -8,9 +8,29 @@ export type ActivityKey = 'dataset:created' | 'dataset:updated' | 'dataset:delet
|
|
|
8
8
|
| 'reuse:created' | 'reuse:updated' | 'reuse:deleted' | 'reuse:discussed' | 'reuse:followed'
|
|
9
9
|
| 'user:followed' | 'topic:created' | 'topic:updated'
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Who an action is attributed to. Not necessarily a person: harvesting and API tokens
|
|
13
|
+
* act on their own behalf. `class` is the discriminator every API reference carries.
|
|
14
|
+
*/
|
|
15
|
+
export type ActivityActor
|
|
16
|
+
= | UserReference
|
|
17
|
+
| { class: 'HarvestSource', id: string, name: string }
|
|
18
|
+
| { class: 'ApiToken', id: string, name: string }
|
|
19
|
+
|
|
20
|
+
export type ActivityExtras = {
|
|
21
|
+
/** Set on the `dataset:resource:*` keys. */
|
|
22
|
+
resource_id?: string
|
|
23
|
+
/**
|
|
24
|
+
* Copied when the activity is emitted, so a resource removed or renamed since still
|
|
25
|
+
* reads under the name it had that day. Absent from the activities recorded before
|
|
26
|
+
* the backend started storing it.
|
|
27
|
+
*/
|
|
28
|
+
resource_title?: string
|
|
29
|
+
}
|
|
30
|
+
|
|
11
31
|
export type Activity = {
|
|
12
|
-
actor:
|
|
13
|
-
organization:
|
|
32
|
+
actor: ActivityActor
|
|
33
|
+
organization: OrganizationReference | null
|
|
14
34
|
related_to: string
|
|
15
35
|
related_to_id: string
|
|
16
36
|
related_to_kind: string
|
|
@@ -19,6 +39,6 @@ export type Activity = {
|
|
|
19
39
|
label: string
|
|
20
40
|
key: ActivityKey
|
|
21
41
|
icon: string
|
|
22
|
-
extras:
|
|
42
|
+
extras: ActivityExtras
|
|
23
43
|
changes?: Array<string>
|
|
24
44
|
}
|