diff --git a/src/graphql/admin.ts b/src/graphql/admin.ts
index 86d5c4381..d20cf2d1b 100644
--- a/src/graphql/admin.ts
+++ b/src/graphql/admin.ts
@@ -200,6 +200,11 @@ export const ADMIN_SETTINGS_FRAGMENT = gql`
instanceLongDescription
instanceSlogan
contact
+ externalUrls {
+ label
+ url
+ enabled
+ }
instanceLogo {
uuid
url
@@ -246,6 +251,7 @@ export const SAVE_ADMIN_SETTINGS = gql`
$instanceLongDescription: String
$instanceSlogan: String
$contact: String
+ $externalUrls: [ExternalUrlInput]
$instanceLogo: MediaInput
$instanceFavicon: MediaInput
$defaultPicture: MediaInput
@@ -268,6 +274,7 @@ export const SAVE_ADMIN_SETTINGS = gql`
instanceLongDescription: $instanceLongDescription
instanceSlogan: $instanceSlogan
contact: $contact
+ externalUrls: $externalUrls
instanceLogo: $instanceLogo
instanceFavicon: $instanceFavicon
defaultPicture: $defaultPicture
diff --git a/src/i18n/en_US.json b/src/i18n/en_US.json
index 1ff7d7b8f..18434733a 100644
--- a/src/i18n/en_US.json
+++ b/src/i18n/en_US.json
@@ -84,6 +84,7 @@
"Add / Remove\u2026": "Add / Remove\u2026",
"Add a contact": "Add a contact",
"Add a new post": "Add a new post",
+ "Add a new link": "Add a new link",
"Add a note": "Add a note",
"Add a recipient": "Add a recipient",
"Add a todo": "Add a todo",
@@ -345,6 +346,7 @@
"Delete this discussion": "Delete this discussion",
"Delete this identity": "Delete this identity",
"Delete your identity": "Delete your identity",
+ "Delete this link": "Delete this link",
"Delete {eventTitle}": "Delete {eventTitle}",
"Delete {preferredUsername}": "Delete {preferredUsername}",
"Deleting comment": "Deleting comment",
@@ -453,6 +455,7 @@
"Explore events": "Explore events",
"Explore!": "Explore!",
"Export": "Export",
+ "External links":"External links",
"External provider URL": "External provider URL",
"External registration": "External registration",
"Failed to get location.": "Failed to get location.",
@@ -1283,6 +1286,7 @@
"This profile is from another instance, the informations shown here may be incomplete.": "This profile is from another instance, the informations shown here may be incomplete.",
"This profile is located on this instance, so you need to {access_the_corresponding_account} to suspend it.": "This profile is located on this instance, so you need to {access_the_corresponding_account} to suspend it.",
"This profile was not found": "This profile was not found",
+ "This section lets you add links to external websites to the menu.":"This section lets you add links to external websites to the menu.",
"This setting will be used to display the website and send you emails in the correct language.": "This setting will be used to display the website and send you emails in the correct language.",
"This user doesn't have any profiles": "This user doesn't have any profiles",
"This user was not found": "This user was not found",
diff --git a/src/i18n/fr_FR.json b/src/i18n/fr_FR.json
index 5f3c95117..0f9bf4f1b 100644
--- a/src/i18n/fr_FR.json
+++ b/src/i18n/fr_FR.json
@@ -47,6 +47,7 @@
"Add an instance": "Ajouter une instance",
"Add a contact": "Ajouter un contact",
"Add a new post": "Ajouter un nouveau billet",
+ "Add a new link": "Ajouter un nouveau lien",
"Add a note": "Ajouter une note",
"Add a recipient": "Ajouter un·e destinataire",
"Add a todo": "Ajouter un todo",
@@ -337,6 +338,7 @@
"Delete this conversation": "Supprimer cette conversation",
"Delete this discussion": "Supprimer cette discussion",
"Delete this identity": "Supprimer cette identité",
+ "Delete this link": "Supprimer ce lien",
"Delete your identity": "Supprimer votre identité",
"Delete {eventTitle}": "Supprimer {eventTitle}",
"Delete {preferredUsername}": "Supprimer {preferredUsername}",
@@ -448,6 +450,7 @@
"Explore!": "Explorer !",
"Explore": "Explorer",
"Export": "Export",
+ "External links":"Liens externes",
"External provider URL": "URL du fournisseur externe",
"External registration": "Inscription externe",
"Ex: mobilizon.fr": "Ex : mobilizon.fr",
@@ -1289,6 +1292,7 @@
"This profile is from another instance, the informations shown here may be incomplete.": "Ce profil provient d'une autre instance, les informations montrées ici peuvent être incomplètes.",
"This profile is located on this instance, so you need to {access_the_corresponding_account} to suspend it.": "Ce profil se situe sur cette instance, vous devez donc {access_the_corresponding_account} afin de le suspendre.",
"This profile was not found": "Ce profil n'a pas été trouvé",
+ "This section lets you add links to external websites to the menu.": "Cette section vous permet d'ajouter des liens vers des sites internets externes au menu.",
"This setting will be used to display the website and send you emails in the correct language.": "Ce paramètre sera utilisé pour l'affichage du site et pour vous envoyer des courriels dans la bonne langue.",
"This URL doesn't seem to be valid": "Cette URL ne semble pas être valide",
"This URL is not supported": "Cette URL n'est pas supportée",
diff --git a/src/types/admin.model.ts b/src/types/admin.model.ts
index de08b7ee9..ce4f6d2e8 100644
--- a/src/types/admin.model.ts
+++ b/src/types/admin.model.ts
@@ -28,6 +28,7 @@ export interface IAdminSettings {
contact: string;
instanceLogo: IMedia | null;
instanceFavicon: IMedia | null;
+ externalUrls: { url: string; label: string; enabled: boolean }[];
defaultPicture: IMedia | null;
primaryColor: string;
secondaryColor: string;
diff --git a/src/views/Admin/SettingsView.vue b/src/views/Admin/SettingsView.vue
index b9792c085..faea41f37 100644
--- a/src/views/Admin/SettingsView.vue
+++ b/src/views/Admin/SettingsView.vue
@@ -458,6 +458,47 @@
+
+ {{ t("External links") }}
+
+ {{
+ t(
+ "This section lets you add links to external websites to the menu."
+ )
+ }}
+
+
+
+
+
+
{{
t("Save instance settings")
}}
@@ -479,7 +520,7 @@ import {
import { IAdminSettings, ILanguage } from "@/types/admin.model";
import RouteName from "@/router/name";
import { useMutation, useQuery } from "@vue/apollo-composable";
-import { ref, computed, watch, inject } from "vue";
+import { ref, computed, watch, inject, toRaw } from "vue";
import { useI18n } from "vue-i18n";
import { useHead } from "@/utils/head";
import type { Notifier } from "@/plugins/notifier";
@@ -515,6 +556,7 @@ const defaultAdminSettings: IAdminSettings = {
registrationsOpen: false,
registrationsModeration: false,
instanceLanguages: [],
+ externalUrls: [],
};
const { onResult: onAdminSettingsResult } = useQuery<{
@@ -556,9 +598,25 @@ useHead({
const settingsToWrite = ref(defaultAdminSettings);
watch(adminSettings, () => {
- settingsToWrite.value = { ...adminSettings.value };
+ // We need to use structuredClone to clone deep properties of adminSettings (like externalUrls)
+ // {... } only shadow clone, so externalUrls is not reactive doing this
+ if (adminSettings.value) {
+ settingsToWrite.value = structuredClone(toRaw(adminSettings.value));
+ }
});
+const addLink = () => {
+ settingsToWrite.value.externalUrls.push({
+ url: "",
+ label: "",
+ enabled: false,
+ });
+};
+
+const deleteLink = (index: number) => {
+ settingsToWrite.value.externalUrls.splice(index, 1);
+};
+
const filteredLanguages = ref([]);
const registrationsMode = computed({
@@ -614,14 +672,15 @@ const {
onDone: saveAdminSettingsDone,
onError: saveAdminSettingsError,
} = useMutation(SAVE_ADMIN_SETTINGS, () => ({
- // We need to update the cache because we just changed admin settings
- // We want to update the related query ADMIN_SETTINGS
update(cache, { data }) {
if (!data?.saveAdminSettings) {
console.error("can't acces new admin settings");
return;
}
+ // We need to update the cache because we just changed admin settings
+ // We want to update the related query ADMIN_SETTINGS
+ // Usefull if we comeback to this page
cache.writeQuery({
query: ADMIN_SETTINGS,
data: { adminSettings: data?.saveAdminSettings },