diff --git a/lib/federation/activity_pub/publisher.ex b/lib/federation/activity_pub/publisher.ex index 257a2f6be..2b3d2629a 100644 --- a/lib/federation/activity_pub/publisher.ex +++ b/lib/federation/activity_pub/publisher.ex @@ -7,6 +7,7 @@ defmodule Mobilizon.Federation.ActivityPub.Publisher do alias Mobilizon.Config alias Mobilizon.Federation.ActivityPub.{Activity, Federator, Relay, Transmogrifier, Visibility} alias Mobilizon.Federation.HTTPSignatures.Signature + alias Mobilizon.Service.HTTP.ActivityPub, as: ActivityPubClient require Logger import Mobilizon.Federation.ActivityPub.Utils, @@ -95,16 +96,16 @@ defmodule Mobilizon.Federation.ActivityPub.Publisher do date: date }) - Tesla.post( - inbox, - json, - headers: [ - {"Content-Type", "application/activity+json"}, - {"signature", signature}, - {"digest", digest}, - {"date", date} - ] - ) + headers = [ + {"Content-Type", "application/activity+json"}, + {"signature", signature}, + {"digest", digest}, + {"date", date} + ] + + client = ActivityPubClient.client(headers: headers) + + ActivityPubClient.post(client, inbox, json) end @spec convert_followers_in_recipients(list(String.t())) :: {list(String.t()), list(String.t())} diff --git a/package-lock.json b/package-lock.json index 3b2b9ccac..8006b8a60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@fullcalendar/daygrid": "^6.1.10", "@fullcalendar/interaction": "^6.1.10", "@fullcalendar/vue3": "^6.1.10", - "@oruga-ui/oruga-next": "^0.8.2", + "@oruga-ui/oruga-next": "^0.8.10", "@oruga-ui/theme-oruga": "^0.2.0", "@sentry/tracing": "^7.1", "@sentry/vue": "^7.1", @@ -3138,9 +3138,9 @@ "dev": true }, "node_modules/@oruga-ui/oruga-next": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@oruga-ui/oruga-next/-/oruga-next-0.8.5.tgz", - "integrity": "sha512-HnODRTrurmke7O5rRNdrbqYuNIdMrnBJ+P3jh6J7/Lk/zgMnpsObSGj/6JfQRvdf5Wq++Ch5yVUys0V4Lm08JQ==", + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@oruga-ui/oruga-next/-/oruga-next-0.8.10.tgz", + "integrity": "sha512-ETPSoGZu1parbj8C3V2ZojQnN4ptQMiJEwS9Hx44NcaDzu4q/FDsYkKYiz6G9kx8cDceXXxvydfOUpZePVVdzw==", "peerDependencies": { "vue": "^3.0.0" } diff --git a/package.json b/package.json index d2b5182ef..83aed32c2 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@fullcalendar/daygrid": "^6.1.10", "@fullcalendar/interaction": "^6.1.10", "@fullcalendar/vue3": "^6.1.10", - "@oruga-ui/oruga-next": "^0.8.2", + "@oruga-ui/oruga-next": "^0.8.10", "@oruga-ui/theme-oruga": "^0.2.0", "@fullcalendar/core": "^6.1.10", "@fullcalendar/daygrid": "^6.1.10", diff --git a/src/components/Event/OrganizerPickerWrapper.vue b/src/components/Event/OrganizerPickerWrapper.vue index e1caf711f..b898ae79e 100644 --- a/src/components/Event/OrganizerPickerWrapper.vue +++ b/src/components/Event/OrganizerPickerWrapper.vue @@ -32,7 +32,7 @@
{{ `@${selectedActor.preferredUsername}` }}
- + {{ $t("Change") }} diff --git a/src/components/Event/TagInput.vue b/src/components/Event/TagInput.vue index dad5c7b9c..b8702c410 100644 --- a/src/components/Event/TagInput.vue +++ b/src/components/Event/TagInput.vue @@ -15,7 +15,8 @@ { const { load: fetchTags } = useFetchTags(); +initTagsStringsValue(); + const getFilteredTags = async (newText: string): Promise => { text.value = newText; const res = await fetchTags( @@ -91,11 +94,16 @@ const filteredTags = computed((): ITag[] => { ); }); -watch(props.modelValue, (newValue, oldValue) => { - if (newValue != oldValue) { - tagsStrings.value = propsValue.value.map((tag: ITag) => tag.title); - } -}); +// TODO It seems that '@update:modelValue="updateTags"' does not works anymore... +// so temporarily call the function updateTags() at remove and add tag event +// https://github.com/oruga-ui/oruga/issues/967 +function remove() { + updateTags(tagsStrings.value); +} + +function add() { + updateTags(tagsStrings.value); +} const updateTags = (newTagsStrings: string[]) => { const tagEntities = newTagsStrings.map((tag: string | ITag) => { @@ -106,4 +114,34 @@ const updateTags = (newTagsStrings: string[]) => { }); emit("update:modelValue", tagEntities); }; + +function isArraysEquals(array1: string[], array2: string[]) { + if (array1.length !== array2.length) { + return false; + } + + for (let i = 0; i < array1.length; i++) { + if (array1[i] !== array2[i]) { + return false; + } + } + + return true; +} + +function initTagsStringsValue() { + // This is useful when tag data is already cached from the API during navigation inside the app + tagsStrings.value = propsValue.value.map((tag: ITag) => tag.title); + + // This watch() function is useful when tag data loads directly from the API upon page load + watch(propsValue, () => { + const newTagsStrings = propsValue.value.map((tag: ITag) => tag.title); + + // Changing tagsStrings.value triggers updateTags(), updateTags() triggers this watch() function again. + // To stop the loop, edit tagsStrings.value only if it has changed ! + if (!isArraysEquals(tagsStrings.value, newTagsStrings)) { + tagsStrings.value = newTagsStrings; + } + }); +} diff --git a/src/views/Event/MyEventsView.vue b/src/views/Event/MyEventsView.vue index 7cf8bcf43..4045a33e5 100644 --- a/src/views/Event/MyEventsView.vue +++ b/src/views/Event/MyEventsView.vue @@ -23,10 +23,27 @@
- - {{ - showUpcoming ? t("Upcoming events") : t("Past events") - }} + + + {{ t("Drafts") }} @@ -50,28 +67,6 @@ ) }}

- - - -
{ + return (n > 9 ? "" : "0") + n.toString(); + }; + return ( + d.getFullYear() + + "-" + + pad(d.getMonth() + 1) + + "-" + + pad(d.getDate()) + + "T00:00:00Z" + ); +} + const showUpcoming = useRouteQuery("showUpcoming", true, booleanTransformer); const showDrafts = useRouteQuery("showDrafts", true, booleanTransformer); const showAttending = useRouteQuery("showAttending", true, booleanTransformer); const showMyGroups = useRouteQuery("showMyGroups", false, booleanTransformer); -const dateFilter = useRouteQuery("dateFilter", new Date(), { +const dateFilter = useRouteQuery("dateFilter", startOfDay(new Date()), { fromQuery(query) { if (query && /(\d{4}-\d{2}-\d{2})/.test(query)) { - return new Date(`${query}T00:00:00Z`); + return `${query}T00:00:00Z`; } - return new Date(); + return startOfDay(new Date()); }, - toQuery(value: Date) { - const pad = (number: number) => { - if (number < 10) { - return "0" + number; - } - return number; - }; - return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad( - value.getDate() - )}`; + toQuery(value: string) { + return value.slice(0, 10); + }, +}); + +// bridge between datepicker expecting a Date object and dateFilter being a string +const datePick = computed({ + get: () => { + return new Date(dateFilter.value); + }, + set: (d: Date) => { + dateFilter.value = startOfDay(d); }, }); @@ -323,10 +334,7 @@ const pastParticipations = computed( } ); -const monthlyEvents = ( - elements: Eventable[], - revertSort = false -): Map => { +const monthlyEvents = (elements: Eventable[]): Map => { const res = elements.filter((element: Eventable) => { if ("role" in element) { return ( @@ -336,19 +344,12 @@ const monthlyEvents = ( } return element.beginsOn != null; }); - if (revertSort) { - res.sort((a: Eventable, b: Eventable) => { - const aTime = "role" in a ? a.event.beginsOn : a.beginsOn; - const bTime = "role" in b ? b.event.beginsOn : b.beginsOn; - return new Date(bTime).getTime() - new Date(aTime).getTime(); - }); - } else { - res.sort((a: Eventable, b: Eventable) => { - const aTime = "role" in a ? a.event.beginsOn : a.beginsOn; - const bTime = "role" in b ? b.event.beginsOn : b.beginsOn; - return new Date(aTime).getTime() - new Date(bTime).getTime(); - }); - } + // sort by start date, ascending + res.sort((a: Eventable, b: Eventable) => { + const aTime = "role" in a ? a.event.beginsOn : a.beginsOn; + const bTime = "role" in b ? b.event.beginsOn : b.beginsOn; + return new Date(aTime).getTime() - new Date(bTime).getTime(); + }); return res.reduce((acc: Map, element: Eventable) => { const month = new Date( "role" in element ? element.event.beginsOn : element.beginsOn diff --git a/src/views/Posts/EditView.vue b/src/views/Posts/EditView.vue index db018434c..91564253b 100644 --- a/src/views/Posts/EditView.vue +++ b/src/views/Posts/EditView.vue @@ -195,6 +195,10 @@ onMounted(async () => { pictureFile.value = await buildFileFromIMedia(post.value?.picture); }); +// This is useful when post data is already cached from the API during navigation inside the app +editablePost.value = { ...editablePost.value, ...post.value }; + +// This watch() function is useful when post data loads directly from the API upon page load watch(post, async (newPost: IPost | undefined, oldPost: IPost | undefined) => { if (oldPost?.picture !== newPost?.picture) { pictureFile.value = await buildFileFromIMedia(post.value?.picture);