Merge branch 'fixes' into 'master'

Some fixes

See merge request framasoft/mobilizon!869
This commit is contained in:
Thomas Citharel
2021-03-25 14:25:01 +00:00
35 changed files with 790 additions and 501 deletions

View File

@@ -24,6 +24,9 @@
v-model="newComment.text"
/>
</p>
<p class="help is-danger" v-if="emptyCommentError">
{{ $t("Comment text can't be empty") }}
</p>
</div>
<div class="send-comment">
<b-button
@@ -125,12 +128,23 @@ export default class CommentTree extends Vue {
CommentModeration = CommentModeration;
emptyCommentError = false;
@Watch("currentActor")
watchCurrentActor(currentActor: IPerson): void {
this.newComment.actor = currentActor;
}
@Watch("newComment", { deep: true })
resetEmptyCommentError(newComment: IComment): void {
if (this.emptyCommentError) {
this.emptyCommentError = ["", "<p></p>"].includes(newComment.text);
}
}
async createCommentForEvent(comment: IComment): Promise<void> {
this.emptyCommentError = ["", "<p></p>"].includes(comment.text);
if (this.emptyCommentError) return;
try {
if (!comment.actor) return;
await this.$apollo.mutate({
@@ -216,10 +230,13 @@ export default class CommentTree extends Vue {
// and reset the new comment field
this.newComment = new CommentModel();
} catch (error) {
console.error(error);
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
this.$notifier.error(error.graphQLErrors[0].message);
} catch (errors) {
console.error(errors);
if (errors.graphQLErrors && errors.graphQLErrors.length > 0) {
const error = errors.graphQLErrors[0];
if (error.field !== "text" && error.message[0] !== "can't be blank") {
this.$notifier.error(error.message);
}
}
}
}

View File

@@ -967,5 +967,7 @@
"You posted a comment on the event {event}.": "You posted a comment on the event {event}.",
"{profile} posted a comment on the event {event}.": "{profile} posted a comment on the event {event}.",
"You replied to a comment on the event {event}.": "You replied to a comment on the event {event}.",
"{profile} replied to a comment on the event {event}.": "{profile} replied to a comment on the event {event}."
"{profile} replied to a comment on the event {event}.": "{profile} replied to a comment on the event {event}.",
"New post": "New post",
"Comment text can't be empty": "Comment text can't be empty"
}

View File

@@ -1061,5 +1061,7 @@
"You posted a comment on the event {event}.": "Vous avez posté un commentaire sur l'événement {event}.",
"{profile} posted a comment on the event {event}.": "{profile} a posté un commentaire sur l'événement {event}.",
"You replied to a comment on the event {event}.": "Vous avez répondu à un commentaire sur l'événement {event}.",
"{profile} replied to a comment on the event {event}.": "{profile} a répondu à un commentaire sur l'événement {event}."
"{profile} replied to a comment on the event {event}.": "{profile} a répondu à un commentaire sur l'événement {event}.",
"New post": "Nouveau billet",
"Comment text can't be empty": "Le texte du commentaire ne peut être vide"
}

View File

@@ -34,7 +34,7 @@ import { Component, Vue } from "vue-property-decorator";
variables() {
return {
id: this.currentActor.id,
group: this.$route.params.preferredUsername,
group: this.group.preferredUsername,
};
},
subscribeToMore: {
@@ -42,14 +42,14 @@ import { Component, Vue } from "vue-property-decorator";
variables() {
return {
actorId: this.currentActor.id,
group: this.$route.params.preferredUsername,
group: this.group.preferredUsername,
};
},
skip() {
return (
!this.currentActor ||
!this.currentActor.id ||
!this.$route.params.preferredUsername
!this.group.preferredUsername
);
},
},
@@ -57,7 +57,7 @@ import { Component, Vue } from "vue-property-decorator";
return (
!this.currentActor ||
!this.currentActor.id ||
!this.$route.params.preferredUsername
!this.group.preferredUsername
);
},
},

View File

@@ -3,7 +3,11 @@
<h1>{{ $t("Create a discussion") }}</h1>
<form @submit.prevent="createDiscussion">
<b-field :label="$t('Title')">
<b-field
:label="$t('Title')"
:message="errors.title"
:type="errors.title ? 'is-danger' : undefined"
>
<b-input aria-required="true" required v-model="discussion.title" />
</b-field>
@@ -64,7 +68,10 @@ export default class CreateDiscussion extends Vue {
discussion = { title: "", text: "" };
errors = { title: "" };
async createDiscussion(): Promise<void> {
this.errors = { title: "" };
try {
if (!this.group.id || !this.currentActor.id) return;
const { data } = await this.$apollo.mutate({
@@ -86,7 +93,11 @@ export default class CreateDiscussion extends Vue {
} catch (error) {
console.error(error);
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
this.$notifier.error(error.graphQLErrors[0].message);
if (error.graphQLErrors[0].field == "title") {
this.errors.title = error.graphQLErrors[0].message;
} else {
this.$notifier.error(error.graphQLErrors[0].message);
}
}
}
}

View File

@@ -2,6 +2,43 @@
<div>
<form @submit.prevent="publish(false)" v-if="isCurrentActorAGroupModerator">
<div class="container section">
<nav class="breadcrumb" aria-label="breadcrumbs" v-if="actualGroup">
<ul>
<li>
<router-link
v-if="actualGroup"
:to="{
name: RouteName.GROUP,
params: {
preferredUsername: usernameWithDomain(actualGroup),
},
}"
>{{
actualGroup.name || actualGroup.preferredUsername
}}</router-link
>
<b-skeleton v-else :animated="true"></b-skeleton>
</li>
<li>
<router-link
v-if="actualGroup"
:to="{
name: RouteName.POSTS,
params: {
preferredUsername: usernameWithDomain(actualGroup),
},
}"
>{{ $t("Posts") }}</router-link
>
<b-skeleton v-else :animated="true"></b-skeleton>
</li>
<li class="is-active">
<span v-if="preferredUsername">{{ $t("New post") }}</span>
<span v-else-if="slug">{{ $t("Edit post") }}</span>
<b-skeleton v-else :animated="true"></b-skeleton>
</li>
</ul>
</nav>
<h1 class="title" v-if="isUpdate === true">
{{ $t("Edit post") }}
</h1>
@@ -111,7 +148,6 @@
<script lang="ts">
import { Component, Prop, Watch } from "vue-property-decorator";
import { mixins } from "vue-class-component";
import { FETCH_GROUP } from "@/graphql/group";
import {
buildFileFromIMedia,
buildFileVariable,
@@ -135,11 +171,24 @@ import TagInput from "../../components/Event/TagInput.vue";
import RouteName from "../../router/name";
import Subtitle from "../../components/Utils/Subtitle.vue";
import PictureUpload from "../../components/PictureUpload.vue";
import { PERSON_MEMBERSHIP_GROUP } from "@/graphql/actor";
import { FETCH_GROUP } from "@/graphql/group";
@Component({
apollo: {
tags: TAGS,
config: CONFIG,
group: {
query: FETCH_GROUP,
variables() {
return {
name: this.preferredUsername,
};
},
skip() {
return !this.preferredUsername;
},
},
post: {
query: FETCH_POST,
fetchPolicy: "cache-and-network",
@@ -152,15 +201,17 @@ import PictureUpload from "../../components/PictureUpload.vue";
return !this.slug;
},
},
group: {
query: FETCH_GROUP,
person: {
query: PERSON_MEMBERSHIP_GROUP,
fetchPolicy: "cache-and-network",
variables() {
return {
name: this.preferredUsername,
id: this.currentActor.id,
group: this.actualGroup.preferredUsername,
};
},
skip() {
return !this.preferredUsername;
return !this.currentActor?.id || !this.actualGroup?.preferredUsername;
},
},
},
@@ -206,6 +257,10 @@ export default class EditPost extends mixins(GroupMixin) {
errors: Record<string, unknown> = {};
RouteName = RouteName;
usernameWithDomain = usernameWithDomain;
async mounted(): Promise<void> {
this.pictureFile = await buildFileFromIMedia(this.post.picture);
}
@@ -331,18 +386,6 @@ export default class EditPost extends mixins(GroupMixin) {
}
return this.group;
}
hasCurrentActorThisRole(givenRole: string | string[]): boolean {
const roles = Array.isArray(givenRole) ? givenRole : [givenRole];
return (
this.person &&
this.actualGroup &&
this.person.memberships.elements.some(
({ parent: { id }, role }) =>
id === this.actualGroup.id && roles.includes(role)
)
);
}
}
</script>
<style lang="scss" scoped>
@@ -360,4 +403,8 @@ form {
}
}
}
.breadcrumb li.is-active > span {
padding: 0 0.75em;
}
</style>

View File

@@ -190,6 +190,9 @@
<b-modal :active.sync="createLinkResourceModal" has-modal-card>
<div class="modal-card">
<section class="modal-card-body">
<b-message type="is-danger" v-if="modalError">
{{ modalError }}
</b-message>
<form @submit.prevent="createResource">
<b-field :label="$t('URL')">
<b-input
@@ -317,6 +320,8 @@ export default class Resources extends Mixins(ResourceMixin) {
renameModal = false;
modalError = "";
groupObject: Record<string, unknown> = {
name: "resources",
pull: "clone",
@@ -341,6 +346,7 @@ export default class Resources extends Mixins(ResourceMixin) {
async createResource(): Promise<void> {
if (!this.resource.actor) return;
this.modalError = "";
try {
await this.$apollo.mutate({
mutation: CREATE_RESOURCE,
@@ -364,21 +370,28 @@ export default class Resources extends Mixins(ResourceMixin) {
this.newResource.resourceUrl = "";
} catch (err) {
console.error(err);
this.modalError = err.graphQLErrors[0].message;
}
}
async previewResource(): Promise<void> {
if (this.newResource.resourceUrl === "") return;
const { data } = await this.$apollo.mutate({
mutation: PREVIEW_RESOURCE_LINK,
variables: {
resourceUrl: this.newResource.resourceUrl,
},
});
this.newResource.title = data.previewResourceLink.title;
this.newResource.summary = data.previewResourceLink.description;
this.newResource.metadata = data.previewResourceLink;
this.newResource.type = "link";
this.modalError = "";
try {
if (this.newResource.resourceUrl === "") return;
const { data } = await this.$apollo.mutate({
mutation: PREVIEW_RESOURCE_LINK,
variables: {
resourceUrl: this.newResource.resourceUrl,
},
});
this.newResource.title = data.previewResourceLink.title;
this.newResource.summary = data.previewResourceLink.description;
this.newResource.metadata = data.previewResourceLink;
this.newResource.type = "link";
} catch (err) {
console.error(err);
this.modalError = err.graphQLErrors[0].message;
}
}
createSentenceForType(type: string): string {

View File

@@ -47,6 +47,7 @@ export default class Validate extends Vue {
this.loading = false;
await this.$router.push({ name: RouteName.HOME });
} catch (err) {
this.loading = false;
console.error(err);
this.failed = true;
}