Skip to content

Commit

Permalink
CRISTAL-384: Realtime should use the real user names
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelleduc committed Jan 10, 2025
1 parent e21c06c commit 39cfe68
Show file tree
Hide file tree
Showing 21 changed files with 187 additions and 175 deletions.
6 changes: 6 additions & 0 deletions core/authentication/authentication-api/src/userDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,10 @@
export interface UserDetails {
profile?: string;
name: string;
/**
* URL of the user avatar. Must be publicly accessible.
*
* @since 0.14
*/
avatar?: string;
}
9 changes: 7 additions & 2 deletions core/authentication/authentication-ui/src/vue/UserDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ const authenticationManager = cristal

const browserApi = cristal.getContainer().get<BrowserApi>(browserApiName);

const { profile, name, error } = await getUserProfile(authenticationManager);
const { profile, name, error, avatar } = await getUserProfile(
authenticationManager,
);

function logout() {
authenticationManager.logout().then(() => browserApi.reload());
Expand All @@ -49,7 +51,10 @@ function logout() {
<template>
<template v-if="!error">
<i18n-t keypath="userDescription" tag="span">
<a :href="profile">{{ name }}</a>
<a :href="profile">
<x-avatar v-if="avatar" :image="avatar" :name="name"></x-avatar>
{{ name }}
</a>
</i18n-t>
</template>
<span v-else>{{ t("userDetails.error") }}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,17 @@ import type { AuthenticationManager } from "@xwiki/cristal-authentication-api";
export async function getUserProfile(
authenticationManager: AuthenticationManager,
): Promise<{
name: string | undefined;
profile: string | undefined;
name?: string;
profile?: string;
avatar?: string;
error: boolean;
}> {
let profile = undefined;
let name = undefined;
let error = false;
try {
const details = await authenticationManager.getUserDetails();
profile = details.profile;
name = details.name;
const { profile, name, avatar } =
await authenticationManager.getUserDetails();
return { profile, name, avatar, error: false };
} catch (e) {
console.log(e);
error = true;
console.error("Failed to access the user profile", e);
return { error: true };
}
return { profile, name, error };
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ export class XWikiAuthenticationManager implements AuthenticationManager {
},
};
const {
data: { profile, name },
data: { profile, name, picture },
} = await axios.get(userinfoUrl, data);

return { profile, name };
return { profile, name, avatar: picture };
}

async logout(): Promise<void> {
Expand Down
9 changes: 8 additions & 1 deletion ds/api/src/XAvatar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ type AvatarProps = {
* Image URL.
*/
image?: string;
alt?: string;
/**
* Image maximum dimension, with a unit (e.g., 30 px)
*/
size?: string;
/**
* User name.
*/
name?: string;
};

export type { AvatarProps };
1 change: 1 addition & 0 deletions ds/dsfr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@gouvfr/dsfr": "1.11.2",
"@gouvminint/vue-dsfr": "5.11.0",
"@xwiki/cristal-api": "workspace:*",
"@xwiki/cristal-dsapi": "workspace:*",
"inversify": "6.2.1",
"vue": "3.5.13"
},
Expand Down
17 changes: 15 additions & 2 deletions ds/dsfr/src/vue/x-avatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,21 @@ import { AvatarProps } from "@xwiki/cristal-dsapi";
defineProps<AvatarProps>();
</script>
<template>
<DsfrPicture v-if="image" :src="image" class="avatar"></DsfrPicture>
<DsfrPicture v-else size="small" class="avatar" src=""></DsfrPicture>
<DsfrPicture
v-if="image"
:src="image"
class="avatar"
:alt="name"
:title="name"
></DsfrPicture>
<DsfrPicture
v-else
size="small"
class="avatar"
src=""
:alt="name"
:title="name"
></DsfrPicture>
</template>

<style scoped>
Expand Down
23 changes: 16 additions & 7 deletions ds/shoelace/src/vue/x-avatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@ License along with this software; if not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
<template>
<sl-avatar :image="image"></sl-avatar>
</template>
<script lang="ts">
<script lang="ts" setup>
import "@shoelace-style/shoelace/dist/components/avatar/avatar";
import type { AvatarProps } from "@xwiki/cristal-dsapi";

export default {
props: { image: { type: String, required: true } },
};
withDefaults(defineProps<AvatarProps>(), {
// reuse shoelace default avatar size when no explicit size value is passed in the props.
size: "3rem",
});
</script>

<template>
<sl-avatar :image="image" :label="name" class="avatar"></sl-avatar>
</template>

<style scoped>
.avatar {
--size: v-bind("size");
}
</style>
18 changes: 9 additions & 9 deletions ds/vuetify/src/vue/x-avatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ License along with this software; if not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
<script lang="ts" setup>
import type { AvatarProps } from "@xwiki/cristal-dsapi";

defineProps<AvatarProps>();
</script>
<template>
<v-avatar :image="image" :size="size"></v-avatar>
<v-avatar :size="size">
<v-img v-if="image" :alt="name" :src="image"></v-img>
<span v-else>{{ name }}</span>
</v-avatar>
</template>
<script lang="ts">
export default {
props: {
image: { type: String, required: true },
size: { type: String, required: true },
},
};
</script>
3 changes: 2 additions & 1 deletion editors/tiptap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@
"@tiptap/suggestion": "2.11.0",
"@tiptap/vue-3": "2.11.0",
"@xwiki/cristal-api": "workspace:*",
"@xwiki/cristal-authentication-api": "workspace:*",
"@xwiki/cristal-backend-api": "workspace:*",
"@xwiki/cristal-document-api": "workspace:*",
"@xwiki/cristal-dsapi": "workspace:*",
"@xwiki/cristal-icons": "workspace:*",
"@xwiki/cristal-link-suggest-api": "workspace:*",
"@xwiki/cristal-markdown-default": "workspace:*",
Expand All @@ -54,7 +56,6 @@
"@xwiki/cristal-skin": "workspace:*",
"@xwiki/cristal-tiptap-extension-image": "workspace:*",
"@xwiki/cristal-tiptap-link-suggest-ui": "workspace:*",
"avvvatars-vue": "1.1.0",
"eventemitter3": "5.0.1",
"inversify": "6.2.1",
"lodash": "4.17.21",
Expand Down
32 changes: 1 addition & 31 deletions editors/tiptap/src/extensions/collaboration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,38 +52,9 @@ export interface User {
* The user's name, displayed near the user's cursor.
*/
name: string;
avatar: string;
}

const colors = [
"#958DF1",
"#F98181",
"#FBBC88",
"#FAF594",
"#70CFF8",
"#94FADB",
"#B9F18D",
"#C3E2C2",
"#EAECCC",
"#AFC8AD",
"#EEC759",
"#9BB8CD",
"#FF90BC",
"#FFC0D9",
"#DC8686",
"#7ED7C1",
"#F3EEEA",
"#89B9AD",
"#D0BFFF",
"#FFF8C9",
"#CBFFA9",
"#9BABB8",
"#E3F4F4",
];

const getRandomElement = <T>(array: Array<T>) =>
array[Math.floor(Math.random() * array.length)];
const getRandomColor = () => getRandomElement(colors);

export const CollaborationKit = Extension.create<CollaborationKitOptions>({
name: "cristalCollaborationKit",

Expand Down Expand Up @@ -124,7 +95,6 @@ export const CollaborationKit = Extension.create<CollaborationKitOptions>({
CollaborationCursor.configure({
provider: this.storage.provider,
user: {
color: getRandomColor(),
...this.options.user,
},
}),
Expand Down
Binary file added editors/tiptap/src/images/noavatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions editors/tiptap/src/png.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* See the LICENSE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
declare module "*.png";
19 changes: 12 additions & 7 deletions editors/tiptap/src/vue/c-connection-status.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import {
onStatusParameters,
} from "@hocuspocus/provider";
import { CIcon, Size } from "@xwiki/cristal-icons";
import { Avvvatars } from "avvvatars-vue";
import { ref } from "vue";
import type { Ref } from "vue";

Expand Down Expand Up @@ -81,19 +80,25 @@ provider.on("awarenessChange", (event: onAwarenessChangeParameters) => {
v-if="status === WebSocketStatus.Connected"
class="connection-status-users"
>
<Avvvatars
<x-avatar
v-for="user in users"
:key="user.name"
:value="user.name"
variant="shape"
:border="true"
:size="28"
/>
class="avatar"
:image="user.avatar"
:name="user.name"
:size="'28px'"
>
{{ user.name }}
</x-avatar>
</span>
</span>
</template>

<style scoped>
.avatar {
max-width: 28px;
height: 28px;
}
.connection-status-icon + .connection-status-label {
margin-left: 0.2em;
}
Expand Down
Loading

0 comments on commit 39cfe68

Please sign in to comment.