@@ -45,16 +52,22 @@ figure.image {
color: #eee;
}
}
+
+.action-buttons {
+ display: flex;
+ flex-direction: column;
+}
diff --git a/js/src/graphql/actor.ts b/js/src/graphql/actor.ts
index 6c9f68e6..958d16f9 100644
--- a/js/src/graphql/actor.ts
+++ b/js/src/graphql/actor.ts
@@ -10,6 +10,7 @@ export const FETCH_PERSON = gql`
summary
preferredUsername
suspended
+ mediaSize
avatar {
id
name
@@ -51,6 +52,7 @@ export const GET_PERSON = gql`
summary
preferredUsername
suspended
+ mediaSize
avatar {
id
name
diff --git a/js/src/graphql/group.ts b/js/src/graphql/group.ts
index 4815d5e4..4c946b89 100644
--- a/js/src/graphql/group.ts
+++ b/js/src/graphql/group.ts
@@ -84,6 +84,7 @@ export const GROUP_FIELDS_FRAGMENTS = gql`
id
url
}
+ mediaSize
organizedEvents(
afterDatetime: $afterDateTime
beforeDatetime: $beforeDateTime
diff --git a/js/src/graphql/upload.ts b/js/src/graphql/upload.ts
index b1d1cafb..6d011cd1 100644
--- a/js/src/graphql/upload.ts
+++ b/js/src/graphql/upload.ts
@@ -1,6 +1,5 @@
import gql from "graphql-tag";
-/* eslint-disable import/prefer-default-export */
export const UPLOAD_PICTURE = gql`
mutation UploadPicture($file: Upload!, $alt: String, $name: String!) {
uploadPicture(file: $file, alt: $alt, name: $name) {
@@ -9,3 +8,11 @@ export const UPLOAD_PICTURE = gql`
}
}
`;
+
+export const REMOVE_PICTURE = gql`
+ mutation RemovePicture($id: ID!) {
+ removePicture(id: $id) {
+ id
+ }
+ }
+`;
diff --git a/js/src/graphql/user.ts b/js/src/graphql/user.ts
index c6fc4077..4f85f388 100644
--- a/js/src/graphql/user.ts
+++ b/js/src/graphql/user.ts
@@ -200,6 +200,7 @@ export const GET_USER = gql`
currentSignInAt
locale
disabled
+ mediaSize
defaultActor {
id
}
diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json
index 918c1a7d..d03b8364 100644
--- a/js/src/i18n/en_US.json
+++ b/js/src/i18n/en_US.json
@@ -799,5 +799,6 @@
"Mobilizon uses a system of profiles to compartiment your activities. You will be able to create as many profiles as you want.": "Mobilizon uses a system of profiles to compartiment your activities. You will be able to create as many profiles as you want.",
"Mobilizon is a federated software, meaning you can interact - depending on your admin's federation settings - with content from other instances, such as joining groups or events that were created elsewhere.": "Mobilizon is a federated software, meaning you can interact - depending on your admin federation settings - with content from other instances, such as joining groups or events that were created elsewhere.",
"This instance, {instanceName} ({domain}), hosts your profile, so remember its name.": "This instance, {instanceName} ({domain}), hosts your profile, so remember its name.",
- "If you are being asked for your federated indentity, it's composed of your username and your instance. For instance, the federated identity for your first profile is:": "If you are being asked for your federated indentity, it's composed of your username and your instance. For instance, the federated identity for your first profile is:"
+ "If you are being asked for your federated indentity, it's composed of your username and your instance. For instance, the federated identity for your first profile is:": "If you are being asked for your federated indentity, it's composed of your username and your instance. For instance, the federated identity for your first profile is:",
+ "Uploaded media size": "Uploaded media size"
}
diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json
index 34663c42..1e52c9b9 100644
--- a/js/src/i18n/fr_FR.json
+++ b/js/src/i18n/fr_FR.json
@@ -887,5 +887,6 @@
"Mobilizon uses a system of profiles to compartiment your activities. You will be able to create as many profiles as you want.": "Mobilizon utilise un système de profils pour compartimenter vos activités. Vous pourrez créer autant de profils que vous voulez.",
"Mobilizon is a federated software, meaning you can interact - depending on your admin's federation settings - with content from other instances, such as joining groups or events that were created elsewhere.": "Mobilizon est un logiciel fédéré, ce qui signifie que vous pouvez interagir - en fonction des paramètres de fédération de votre administrateur·ice - avec du contenu d'autres instances, comme par exemple rejoindre des groupes ou des événements ayant été créés ailleurs.",
"This instance, {instanceName} ({domain}), hosts your profile, so remember its name.": "Cette instance, {instanceName} ({domain}), héberge votre profil, donc notez bien son nom.",
- "If you are being asked for your federated indentity, it's composed of your username and your instance. For instance, the federated identity for your first profile is:": "Si l'on vous demande votre identité fédérée, elle est composée de votre nom d'utilisateur·ice et de votre instance. Par exemple, l'identité fédérée de votre premier profil est :"
+ "If you are being asked for your federated indentity, it's composed of your username and your instance. For instance, the federated identity for your first profile is:": "Si l'on vous demande votre identité fédérée, elle est composée de votre nom d'utilisateur·ice et de votre instance. Par exemple, l'identité fédérée de votre premier profil est :",
+ "Uploaded media size": "Taille des médias téléversés"
}
diff --git a/js/src/types/actor/actor.model.ts b/js/src/types/actor/actor.model.ts
index 65c838f2..7b11331f 100644
--- a/js/src/types/actor/actor.model.ts
+++ b/js/src/types/actor/actor.model.ts
@@ -13,6 +13,7 @@ export interface IActor {
url: string;
name: string;
domain: string | null;
+ mediaSize: number;
summary: string;
preferredUsername: string;
suspended: boolean;
@@ -30,6 +31,8 @@ export class Actor implements IActor {
domain: string | null = null;
+ mediaSize = 0;
+
name = "";
preferredUsername = "";
diff --git a/js/src/types/current-user.model.ts b/js/src/types/current-user.model.ts
index eed7d9eb..3b2a29ea 100644
--- a/js/src/types/current-user.model.ts
+++ b/js/src/types/current-user.model.ts
@@ -39,6 +39,7 @@ export interface IUser extends ICurrentUser {
actors: IPerson[];
disabled: boolean;
participations: Paginate;
+ mediaSize: number;
drafts: IEvent[];
settings: IUserSettings;
locale: string;
diff --git a/js/src/types/event.model.ts b/js/src/types/event.model.ts
index e9bedbef..133a6f88 100644
--- a/js/src/types/event.model.ts
+++ b/js/src/types/event.model.ts
@@ -69,7 +69,7 @@ interface IEventEditJSON {
visibility: EventVisibility;
joinOptions: EventJoinOptions;
draft: boolean;
- picture: IPicture | { pictureId: string } | null;
+ picture?: IPicture | { pictureId: string } | null;
attributedToId: string | null;
onlineAddress?: string;
phoneAddress?: string;
@@ -234,7 +234,6 @@ export class EventModel implements IEvent {
joinOptions: this.joinOptions,
draft: this.draft,
tags: this.tags.map((t) => t.title),
- picture: this.picture,
onlineAddress: this.onlineAddress,
phoneAddress: this.phoneAddress,
physicalAddress: this.physicalAddress,
diff --git a/js/src/utils/datetime.ts b/js/src/utils/datetime.ts
index f55420d5..e0b3210a 100644
--- a/js/src/utils/datetime.ts
+++ b/js/src/utils/datetime.ts
@@ -18,4 +18,17 @@ function localeShortWeekDayNames(): string[] {
return weekDayNames;
}
-export { localeMonthNames, localeShortWeekDayNames };
+// https://stackoverflow.com/a/18650828/10204399
+function formatBytes(bytes: number, decimals = 2): string {
+ if (bytes === 0) return "0 Bytes";
+
+ const k = 1024;
+ const dm = decimals < 0 ? 0 : decimals;
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
+
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+
+ return `${parseFloat((bytes / k ** i).toFixed(dm))} ${sizes[i]}`;
+}
+
+export { localeMonthNames, localeShortWeekDayNames, formatBytes };
diff --git a/js/src/utils/image.ts b/js/src/utils/image.ts
index 5c817168..304b7e4b 100644
--- a/js/src/utils/image.ts
+++ b/js/src/utils/image.ts
@@ -9,7 +9,7 @@ export async function buildFileFromIPicture(obj: IPicture | null | undefined): P
return new File([blob], obj.name);
}
-export function buildFileVariable(file: File | null, name: string, alt?: string): Record {
+export function buildFileVariable(file: File | null, name: string, alt?: string): Record {
if (!file) return {};
return {
diff --git a/js/src/views/Account/children/EditIdentity.vue b/js/src/views/Account/children/EditIdentity.vue
index 6054c1e2..ddedce7b 100644
--- a/js/src/views/Account/children/EditIdentity.vue
+++ b/js/src/views/Account/children/EditIdentity.vue
@@ -27,7 +27,7 @@
{{ $t("I create an identity") }}
-
+
import { Component, Prop, Watch } from "vue-property-decorator";
import { mixins } from "vue-class-component";
+import { IPicture } from "@/types/picture.model";
import {
CREATE_PERSON,
CURRENT_ACTOR_CLIENT,
@@ -136,7 +137,7 @@ import { IPerson, Person } from "../../../types/actor";
import PictureUpload from "../../../components/PictureUpload.vue";
import { MOBILIZON_INSTANCE_HOST } from "../../../api/_entrypoint";
import RouteName from "../../../router/name";
-import { buildFileVariable } from "../../../utils/image";
+import { buildFileFromIPicture, buildFileVariable } from "../../../utils/image";
import { changeIdentity } from "../../../utils/auth";
import identityEditionMixin from "../../../mixins/identityEdition";
@@ -186,13 +187,6 @@ export default class EditIdentity extends mixins(identityEditionMixin) {
) as string;
}
- get avatarUrl(): string | null {
- if (this.identity && this.identity.avatar && this.identity.avatar.url) {
- return this.identity.avatar.url;
- }
- return null;
- }
-
@Watch("isUpdate")
async isUpdateChanged(): Promise {
this.resetFields();
@@ -286,7 +280,6 @@ export default class EditIdentity extends mixins(identityEditionMixin) {
}
},
});
- this.avatarFile = null;
this.$notifier.success(
this.$t("Identity {displayName} updated", {
diff --git a/js/src/views/Admin/AdminGroupProfile.vue b/js/src/views/Admin/AdminGroupProfile.vue
index 8a27d06f..6b7cb927 100644
--- a/js/src/views/Admin/AdminGroupProfile.vue
+++ b/js/src/views/Admin/AdminGroupProfile.vue
@@ -198,6 +198,7 @@