Merge branch 'bugs' into 'main'

Various bugs

Closes #873 et #862

See merge request framasoft/mobilizon!1108
This commit is contained in:
Thomas Citharel 2021-11-13 15:12:25 +00:00
commit 3d2fea6bb8
21 changed files with 151 additions and 127 deletions

View File

@ -9,7 +9,7 @@
type="is-danger" type="is-danger"
:title="$t('Warning').toLocaleUpperCase()" :title="$t('Warning').toLocaleUpperCase()"
closable closable
aria-close-label="Close" :aria-close-label="$t('Close')"
> >
<p> <p>
{{ $t("This is a demonstration site to test Mobilizon.") }} {{ $t("This is a demonstration site to test Mobilizon.") }}

View File

@ -299,6 +299,10 @@ export default class Comment extends Vue {
onConfirm: this.reportComment, onConfirm: this.reportComment,
outsideDomain: this.comment.actor.domain, outsideDomain: this.comment.actor.domain,
}, },
// https://github.com/buefy/buefy/pull/3589
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
closeButtonAriaLabel: this.$t("Close"),
}); });
} }

View File

@ -45,8 +45,8 @@
type="is-primary" type="is-primary"
class="comment-button-submit" class="comment-button-submit"
icon-left="send" icon-left="send"
:aria-label="$t('Post a comment')" >{{ $t("Send") }}</b-button
/> >
</div> </div>
</article> </article>
</form> </form>
@ -63,7 +63,7 @@
<transition-group <transition-group
key="list" key="list"
name="comment-list" name="comment-list"
v-if="comments.length" v-if="filteredOrderedComments.length"
class="comment-list" class="comment-list"
tag="ul" tag="ul"
> >
@ -77,9 +77,9 @@
@delete-comment="deleteComment" @delete-comment="deleteComment"
/> />
</transition-group> </transition-group>
<div v-else class="no-comments" key="no-comments"> <empty-content v-else icon="comment" key="no-comments" :inline="true">
<span>{{ $t("No comments yet") }}</span> <span>{{ $t("No comments yet") }}</span>
</div> </empty-content>
</transition-group> </transition-group>
</div> </div>
</template> </template>
@ -99,6 +99,7 @@ import { CURRENT_ACTOR_CLIENT } from "../../graphql/actor";
import { IPerson } from "../../types/actor"; import { IPerson } from "../../types/actor";
import { IEvent } from "../../types/event.model"; import { IEvent } from "../../types/event.model";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
import EmptyContent from "@/components/Utils/EmptyContent.vue";
@Component({ @Component({
apollo: { apollo: {
@ -119,6 +120,7 @@ import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
components: { components: {
Comment, Comment,
IdentityPickerWrapper, IdentityPickerWrapper,
EmptyContent,
editor: () => editor: () =>
import(/* webpackChunkName: "editor" */ "@/components/Editor.vue"), import(/* webpackChunkName: "editor" */ "@/components/Editor.vue"),
}, },
@ -364,13 +366,25 @@ export default class CommentTree extends Vue {
<style lang="scss" scoped> <style lang="scss" scoped>
@use "@/styles/_mixins" as *; @use "@/styles/_mixins" as *;
@import "~bulma/sass/utilities/mixins.sass";
form.new-comment { form.new-comment {
padding-bottom: 1rem; padding-bottom: 1rem;
.media {
flex-wrap: wrap;
justify-content: center;
.media-left {
@include mobile {
@include margin-right(0.5rem);
@include margin-left(0.5rem);
}
}
.media-content { .media-content {
display: flex; display: flex;
align-items: center; align-items: center;
align-content: center; align-content: center;
width: min-content;
.field { .field {
flex: 1; flex: 1;
@ -383,6 +397,7 @@ form.new-comment {
} }
} }
} }
}
.no-comments { .no-comments {
display: flex; display: flex;

View File

@ -145,8 +145,10 @@ export default class DiscussionComment extends Vue {
} }
updateComment(): void { updateComment(): void {
this.comment.text = this.updatedComment; this.$emit("update-comment", {
this.$emit("update-comment", this.comment); ...this.comment,
text: this.updatedComment,
});
this.toggleEditMode(); this.toggleEditMode();
} }
} }

View File

@ -62,7 +62,11 @@
</b-button> </b-button>
</p> </p>
</b-field> </b-field>
<b-modal has-modal-card v-model="showNewElementModal"> <b-modal
has-modal-card
v-model="showNewElementModal"
:close-button-aria-label="$t('Close')"
>
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
<button <button

View File

@ -46,7 +46,11 @@
/> />
<b-icon v-else size="is-large" icon="account-circle" /> <b-icon v-else size="is-large" icon="account-circle" />
</span> </span>
<b-modal :active.sync="isComponentModalActive" has-modal-card> <b-modal
:active.sync="isComponentModalActive"
has-modal-card
:close-button-aria-label="$t('Close')"
>
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
<p class="modal-card-title">{{ $t("Pick a profile or a group") }}</p> <p class="modal-card-title">{{ $t("Pick a profile or a group") }}</p>

View File

@ -65,6 +65,7 @@
<b-modal <b-modal
:active.sync="isAnonymousParticipationModalOpen" :active.sync="isAnonymousParticipationModalOpen"
has-modal-card has-modal-card
:close-button-aria-label="$t('Close')"
ref="anonymous-participation-modal" ref="anonymous-participation-modal"
> >
<div class="modal-card"> <div class="modal-card">

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head" v-if="title"> <header class="modal-card-head" v-if="title">
<p class="modal-card-title">{{ title }}</p> <h2 class="modal-card-title">{{ title }}</h2>
</header> </header>
<section <section
@ -17,7 +17,7 @@
<article class="media"> <article class="media">
<div class="media-left"> <div class="media-left">
<figure class="image is-48x48" v-if="comment.actor.avatar"> <figure class="image is-48x48" v-if="comment.actor.avatar">
<img :src="comment.actor.avatar.url" alt="Image" /> <img :src="comment.actor.avatar.url" alt="" />
</figure> </figure>
<b-icon <b-icon
class="media-left" class="media-left"
@ -45,12 +45,16 @@
</p> </p>
<div class="control"> <div class="control">
<b-field
:label="$t('Additional comments')"
label-for="additonal-comments"
>
<b-input <b-input
v-model="content" v-model="content"
type="textarea" type="textarea"
@keyup.enter="confirm" id="additonal-comments"
:placeholder="$t('Additional comments')"
/> />
</b-field>
</div> </div>
<div class="control" v-if="outsideDomain"> <div class="control" v-if="outsideDomain">
@ -73,7 +77,12 @@
<button class="button" ref="cancelButton" @click="close"> <button class="button" ref="cancelButton" @click="close">
{{ translatedCancelText }} {{ translatedCancelText }}
</button> </button>
<button class="button is-primary" ref="confirmButton" @click="confirm"> <button
class="button is-primary"
ref="confirmButton"
@click="confirm"
@keyup.enter="confirm"
>
{{ translatedConfirmText }} {{ translatedConfirmText }}
</button> </button>
</footer> </footer>

View File

@ -1246,5 +1246,10 @@
"Your membership was approved by {profile}.": "Your membership was approved by {profile}.", "Your membership was approved by {profile}.": "Your membership was approved by {profile}.",
"{profile} approved {member}'s membership.": "{profile} approved {member}'s membership.", "{profile} approved {member}'s membership.": "{profile} approved {member}'s membership.",
"You rejected {member}'s membership request.": "You rejected {member}'s membership request.", "You rejected {member}'s membership request.": "You rejected {member}'s membership request.",
"{profile} rejected {member}'s membership request.": "{profile} rejected {member}'s membership request." "{profile} rejected {member}'s membership request.": "{profile} rejected {member}'s membership request.",
"Send": "Send",
"Approve member": "Approve member",
"Reject member": "Reject member",
"The membership request from {profile} was rejected": "The membership request from {profile} was rejected",
"The member was approved": "The member was approved"
} }

View File

@ -165,7 +165,7 @@
"Click for more information": "Cliquez pour plus d'informations", "Click for more information": "Cliquez pour plus d'informations",
"Click to select": "Cliquez pour sélectionner", "Click to select": "Cliquez pour sélectionner",
"Click to upload": "Cliquez pour téléverser", "Click to upload": "Cliquez pour téléverser",
"Close": "Fermé", "Close": "Fermer",
"Close comments for all (except for admins)": "Fermer les commentaires à tout le monde (excepté les administrateur⋅rice·s)", "Close comments for all (except for admins)": "Fermer les commentaires à tout le monde (excepté les administrateur⋅rice·s)",
"Closed": "Fermé", "Closed": "Fermé",
"Comment deleted": "Commentaire supprimé", "Comment deleted": "Commentaire supprimé",
@ -1350,5 +1350,10 @@
"Your membership was approved by {profile}.": "Votre demande d'adhésion a été approuvée par {profile}.", "Your membership was approved by {profile}.": "Votre demande d'adhésion a été approuvée par {profile}.",
"{profile} approved {member}'s membership.": "{profile} a approuvé la demande d'adhésion de {member}.", "{profile} approved {member}'s membership.": "{profile} a approuvé la demande d'adhésion de {member}.",
"You rejected {member}'s membership request.": "Vous avez rejeté la demande d'adhésion de {member}.", "You rejected {member}'s membership request.": "Vous avez rejeté la demande d'adhésion de {member}.",
"{profile} rejected {member}'s membership request.": "{profile} a rejeté la demande d'adhésion de {member}." "{profile} rejected {member}'s membership request.": "{profile} a rejeté la demande d'adhésion de {member}.",
"Send": "Envoyer",
"Approve member": "Approuver le ou la membre",
"Reject member": "Rejeter le ou la membre",
"The membership request from {profile} was rejected": "La demande d'adhésion de {profile} a été rejetée",
"The member was approved": "Le ou la membre a été approuvée"
} }

View File

@ -45,7 +45,11 @@
</figure> </figure>
<b-icon v-else size="is-large" icon="account-circle" /> <b-icon v-else size="is-large" icon="account-circle" />
</span> </span>
<b-modal v-model="isComponentModalActive" has-modal-card> <b-modal
v-model="isComponentModalActive"
has-modal-card
:close-button-aria-label="$t('Close')"
>
<identity-picker v-model="currentIdentity" /> <identity-picker v-model="currentIdentity" />
</b-modal> </b-modal>
</div> </div>

View File

@ -154,7 +154,7 @@ import { GraphQLError } from "graphql";
import { DELETE_COMMENT, UPDATE_COMMENT } from "@/graphql/comment"; import { DELETE_COMMENT, UPDATE_COMMENT } from "@/graphql/comment";
import RouteName from "../../router/name"; import RouteName from "../../router/name";
import { IComment } from "../../types/comment.model"; import { IComment } from "../../types/comment.model";
import { ApolloCache, FetchResult } from "@apollo/client/core"; import { ApolloCache, FetchResult, gql, Reference } from "@apollo/client/core";
import { mixins } from "vue-class-component"; import { mixins } from "vue-class-component";
import GroupMixin from "@/mixins/group"; import GroupMixin from "@/mixins/group";
@ -310,49 +310,23 @@ export default class Discussion extends mixins(GroupMixin) {
variables: { variables: {
commentId: comment.id, commentId: comment.id,
}, },
update: ( update: (store: ApolloCache<{ deleteComment: IComment }>) => {
store: ApolloCache<{ deleteComment: IComment }>, store.writeFragment({
{ data }: FetchResult id: store.identify(comment as unknown as Reference),
) => { fragment: gql`
if (!data || !data.deleteComment) return; fragment CommentDeleted on Comment {
const discussionData = store.readQuery<{ deletedAt
discussion: IDiscussion; actor {
}>({ id
query: GET_DISCUSSION,
variables: {
slug: this.slug,
page: this.page,
},
});
if (!discussionData) return;
const { discussion: discussionCached } = discussionData;
const index = discussionCached.comments.elements.findIndex(
({ id }) => id === data.deleteComment.id
);
let discussionUpdated = discussionCached;
if (index > -1) {
const updatedComment = {
...discussionCached.comments.elements[index],
deletedAt: new Date(),
actor: null,
updatedComment: {
text: "",
},
};
const elements = [...discussionCached.comments.elements];
elements.splice(index, 1, updatedComment);
discussionUpdated = {
...discussionCached,
comments: {
total: discussionCached.comments.total,
elements,
},
};
} }
store.writeQuery({ text
query: GET_DISCUSSION, }
variables: { slug: this.slug, page: this.page }, `,
data: { discussion: discussionUpdated }, data: {
deletedAt: new Date(),
text: "",
actor: null,
},
}); });
}, },
}); });
@ -369,20 +343,6 @@ export default class Discussion extends mixins(GroupMixin) {
page: this.page, page: this.page,
limit: this.COMMENTS_PER_PAGE, limit: this.COMMENTS_PER_PAGE,
}, },
updateQuery: (previousResult, { fetchMoreResult }) => {
return {
discussion: {
...previousResult.discussion,
comments: {
...fetchMoreResult.discussion.comments,
elements: [
...previousResult.discussion.comments.elements,
...fetchMoreResult.discussion.comments.elements,
],
},
},
};
},
}); });
this.hasMoreComments = !this.discussion.comments.elements this.hasMoreComments = !this.discussion.comments.elements
.map(({ id }) => id) .map(({ id }) => id)
@ -399,32 +359,6 @@ export default class Discussion extends mixins(GroupMixin) {
discussionId: this.discussion.id, discussionId: this.discussion.id,
title: this.newTitle, title: this.newTitle,
}, },
update: (
store: ApolloCache<{ updateDiscussion: IDiscussion }>,
{ data }: FetchResult<{ updateDiscussion: IDiscussion }>
) => {
const discussionData = store.readQuery<{
discussion: IDiscussion;
}>({
query: GET_DISCUSSION,
variables: {
slug: this.slug,
page: this.page,
},
});
if (discussionData && data?.updateDiscussion) {
store.writeQuery({
query: GET_DISCUSSION,
variables: { slug: this.slug, page: this.page },
data: {
discussion: {
...discussionData.discussion,
title: data?.updateDiscussion.title,
},
},
});
}
},
}); });
this.editTitleMode = false; this.editTitleMode = false;
} }

View File

@ -339,7 +339,12 @@
{{ $t("Only group moderators can create, edit and delete events.") }} {{ $t("Only group moderators can create, edit and delete events.") }}
</b-message> </b-message>
</div> </div>
<b-modal v-model="dateSettingsIsOpen" has-modal-card trap-focus> <b-modal
v-model="dateSettingsIsOpen"
has-modal-card
trap-focus
:close-button-aria-label="$t('Close')"
>
<form action> <form action>
<div class="modal-card" style="width: auto"> <div class="modal-card" style="width: auto">
<header class="modal-card-head"> <header class="modal-card-head">

View File

@ -325,6 +325,7 @@
:active.sync="isReportModalActive" :active.sync="isReportModalActive"
has-modal-card has-modal-card
ref="reportModal" ref="reportModal"
:close-button-aria-label="$t('Close')"
> >
<report-modal <report-modal
:on-confirm="reportEvent" :on-confirm="reportEvent"
@ -334,6 +335,7 @@
/> />
</b-modal> </b-modal>
<b-modal <b-modal
:close-button-aria-label="$t('Close')"
:active.sync="isShareModalActive" :active.sync="isShareModalActive"
has-modal-card has-modal-card
ref="shareModal" ref="shareModal"
@ -344,6 +346,7 @@
:active.sync="isJoinModalActive" :active.sync="isJoinModalActive"
has-modal-card has-modal-card
ref="participationModal" ref="participationModal"
:close-button-aria-label="$t('Close')"
> >
<identity-picker v-model="identity"> <identity-picker v-model="identity">
<template v-slot:footer> <template v-slot:footer>
@ -380,6 +383,7 @@
:active.sync="isJoinConfirmationModalActive" :active.sync="isJoinConfirmationModalActive"
has-modal-card has-modal-card
ref="joinConfirmationModal" ref="joinConfirmationModal"
:close-button-aria-label="$t('Close')"
> >
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
@ -427,6 +431,7 @@
</div> </div>
</b-modal> </b-modal>
<b-modal <b-modal
:close-button-aria-label="$t('Close')"
class="map-modal" class="map-modal"
v-if="event.physicalAddress && event.physicalAddress.geom" v-if="event.physicalAddress && event.physicalAddress.geom"
:active.sync="showMap" :active.sync="showMap"

View File

@ -647,6 +647,7 @@
<b-modal <b-modal
v-if="physicalAddress && physicalAddress.geom" v-if="physicalAddress && physicalAddress.geom"
:active.sync="showMap" :active.sync="showMap"
:close-button-aria-label="$t('Close')"
> >
<div class="map"> <div class="map">
<map-leaflet <map-leaflet
@ -660,6 +661,7 @@
</b-modal> </b-modal>
</div> </div>
<b-modal <b-modal
:close-button-aria-label="$t('Close')"
:active.sync="isReportModalActive" :active.sync="isReportModalActive"
has-modal-card has-modal-card
ref="reportModal" ref="reportModal"
@ -673,6 +675,7 @@
/> />
</b-modal> </b-modal>
<b-modal <b-modal
:close-button-aria-label="$t('Close')"
v-if="group" v-if="group"
:active.sync="isShareModalActive" :active.sync="isShareModalActive"
has-modal-card has-modal-card

View File

@ -176,6 +176,7 @@
</router-link> </router-link>
</section> </section>
<b-modal <b-modal
:close-button-aria-label="$t('Close')"
:active.sync="isReportModalActive" :active.sync="isReportModalActive"
has-modal-card has-modal-card
ref="reportModal" ref="reportModal"
@ -187,7 +188,12 @@
@close="$refs.reportModal.close()" @close="$refs.reportModal.close()"
/> />
</b-modal> </b-modal>
<b-modal :active.sync="isShareModalActive" has-modal-card ref="shareModal"> <b-modal
:active.sync="isShareModalActive"
has-modal-card
ref="shareModal"
:close-button-aria-label="$t('Close')"
>
<share-post-modal :post="post" /> <share-post-modal :post="post" />
</b-modal> </b-modal>
</article> </article>

View File

@ -157,7 +157,11 @@
:aria-current-label="$t('Current page')" :aria-current-label="$t('Current page')"
> >
</b-pagination> </b-pagination>
<b-modal :active.sync="renameModal" has-modal-card> <b-modal
:active.sync="renameModal"
has-modal-card
:close-button-aria-label="$t('Close')"
>
<div class="modal-card"> <div class="modal-card">
<section class="modal-card-body"> <section class="modal-card-body">
<form @submit.prevent="renameResource"> <form @submit.prevent="renameResource">
@ -172,7 +176,11 @@
</section> </section>
</div> </div>
</b-modal> </b-modal>
<b-modal :active.sync="moveModal" has-modal-card> <b-modal
:active.sync="moveModal"
has-modal-card
:close-button-aria-label="$t('Close')"
>
<div class="modal-card"> <div class="modal-card">
<section class="modal-card-body"> <section class="modal-card-body">
<resource-selector <resource-selector
@ -184,7 +192,11 @@
</section> </section>
</div> </div>
</b-modal> </b-modal>
<b-modal :active.sync="createResourceModal" has-modal-card> <b-modal
:active.sync="createResourceModal"
has-modal-card
:close-button-aria-label="$t('Close')"
>
<div class="modal-card"> <div class="modal-card">
<section class="modal-card-body"> <section class="modal-card-body">
<form @submit.prevent="createResource"> <form @submit.prevent="createResource">
@ -208,6 +220,7 @@
has-modal-card has-modal-card
class="link-resource-modal" class="link-resource-modal"
aria-modal aria-modal
:close-button-aria-label="$t('Close')"
> >
<div class="modal-card"> <div class="modal-card">
<section class="modal-card-body"> <section class="modal-card-body">

View File

@ -149,6 +149,7 @@
</b-button> </b-button>
<b-modal <b-modal
:close-button-aria-label="$t('Close')"
:active.sync="isDeleteAccountModalActive" :active.sync="isDeleteAccountModalActive"
has-modal-card has-modal-card
full-screen full-screen

View File

@ -162,7 +162,9 @@ describe("CommentTree", () => {
requestHandlers.eventCommentThreadsQueryHandler requestHandlers.eventCommentThreadsQueryHandler
).toHaveBeenCalledWith({ eventUUID: eventData.uuid }); ).toHaveBeenCalledWith({ eventUUID: eventData.uuid });
expect(wrapper.find(".no-comments").text()).toBe("No comments yet"); expect(wrapper.findComponent({ name: "EmptyContent" }).text()).toBe(
"No comments yet"
);
expect(wrapper.html()).toMatchSnapshot(); expect(wrapper.html()).toMatchSnapshot();
}); });
}); });

View File

@ -20,7 +20,7 @@ exports[`CommentTree renders a comment tree with comments 1`] = `
</div> </div>
</div> </div>
<div class="send-comment"> <div class="send-comment">
<b-button-stub type="is-primary" iconleft="send" nativetype="submit" tag="button" aria-label="Post a comment" class="comment-button-submit"></b-button-stub> <b-button-stub type="is-primary" iconleft="send" nativetype="submit" tag="button" class="comment-button-submit">Send</b-button-stub>
</div> </div>
</article> </article>
</form> </form>
@ -62,12 +62,12 @@ exports[`CommentTree renders an empty comment tree 1`] = `
</div> </div>
</div> </div>
<div class="send-comment"> <div class="send-comment">
<b-button-stub type="is-primary" iconleft="send" nativetype="submit" tag="button" aria-label="Post a comment" class="comment-button-submit"></b-button-stub> <b-button-stub type="is-primary" iconleft="send" nativetype="submit" tag="button" class="comment-button-submit">Send</b-button-stub>
</div> </div>
</article> </article>
</form> </form>
<transition-group-stub tag="div" name="comment-empty-list"> <transition-group-stub tag="div" name="comment-empty-list">
<div class="no-comments"><span>No comments yet</span></div> <empty-content-stub icon="comment" inline="true"><span>No comments yet</span></empty-content-stub>
</transition-group-stub> </transition-group-stub>
</div> </div>
`; `;

View File

@ -3,7 +3,7 @@ defmodule Mobilizon.Federation.ActivityPub.Audience do
Tools for calculating content audience Tools for calculating content audience
""" """
alias Mobilizon.{Actors, Events, Share} alias Mobilizon.{Actors, Discussions, Events, Share}
alias Mobilizon.Actors.{Actor, Member} alias Mobilizon.Actors.{Actor, Member}
alias Mobilizon.Discussions.{Comment, Discussion} alias Mobilizon.Discussions.{Comment, Discussion}
alias Mobilizon.Events.{Event, Participant} alias Mobilizon.Events.{Event, Participant}
@ -43,8 +43,10 @@ defmodule Mobilizon.Federation.ActivityPub.Audience do
%{"to" => [@ap_public], "cc" => []} %{"to" => [@ap_public], "cc" => []}
end end
def get_audience(%Comment{discussion: %Discussion{} = discussion}) do def get_audience(%Comment{discussion: %Discussion{id: discussion_id}}) do
get_audience(discussion) discussion_id
|> Discussions.get_discussion()
|> get_audience()
end end
def get_audience(%Comment{ def get_audience(%Comment{