Fix lint issues
And disable eslint when building in prod mode Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
da42522073
commit
2d541f2e32
@ -4,4 +4,4 @@ indent_size = 2
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
max_line_length = 100
|
||||
max_line_length = 80
|
||||
|
@ -38,8 +38,11 @@ module.exports = {
|
||||
"error",
|
||||
{
|
||||
ignoreStrings: true,
|
||||
ignoreHTMLTextContents: true,
|
||||
ignoreTemplateLiterals: true,
|
||||
ignoreComments: true,
|
||||
template: 170,
|
||||
code: 100,
|
||||
code: 80,
|
||||
},
|
||||
],
|
||||
"prettier/prettier": "error",
|
||||
@ -56,7 +59,10 @@ module.exports = {
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ["**/__tests__/*.{j,t}s?(x)", "**/tests/unit/**/*.spec.{j,t}s?(x)"],
|
||||
files: [
|
||||
"**/__tests__/*.{j,t}s?(x)",
|
||||
"**/tests/unit/**/*.spec.{j,t}s?(x)",
|
||||
],
|
||||
env: {
|
||||
mocha: true,
|
||||
},
|
||||
|
@ -24,7 +24,9 @@ fetch(`http://localhost:4000/api`, {
|
||||
.then((result) => result.json())
|
||||
.then((result) => {
|
||||
// here we're filtering out any type information unrelated to unions or interfaces
|
||||
const filteredData = result.data.__schema.types.filter((type) => type.possibleTypes !== null);
|
||||
const filteredData = result.data.__schema.types.filter(
|
||||
(type) => type.possibleTypes !== null
|
||||
);
|
||||
result.data.__schema.types = filteredData;
|
||||
fs.writeFile("./fragmentTypes.json", JSON.stringify(result.data), (err) => {
|
||||
if (err) {
|
||||
|
@ -32,8 +32,16 @@
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
import NavBar from "./components/NavBar.vue";
|
||||
import { AUTH_ACCESS_TOKEN, AUTH_USER_EMAIL, AUTH_USER_ID, AUTH_USER_ROLE } from "./constants";
|
||||
import { CURRENT_USER_CLIENT, UPDATE_CURRENT_USER_CLIENT } from "./graphql/user";
|
||||
import {
|
||||
AUTH_ACCESS_TOKEN,
|
||||
AUTH_USER_EMAIL,
|
||||
AUTH_USER_ID,
|
||||
AUTH_USER_ROLE,
|
||||
} from "./constants";
|
||||
import {
|
||||
CURRENT_USER_CLIENT,
|
||||
UPDATE_CURRENT_USER_CLIENT,
|
||||
} from "./graphql/user";
|
||||
import Footer from "./components/Footer.vue";
|
||||
import Logo from "./components/Logo.vue";
|
||||
import { initializeCurrentActor } from "./utils/auth";
|
||||
|
@ -56,7 +56,12 @@ export default function buildCurrentUserResolver(
|
||||
preferredUsername,
|
||||
avatar,
|
||||
name,
|
||||
}: { id: string; preferredUsername: string; avatar: string; name: string },
|
||||
}: {
|
||||
id: string;
|
||||
preferredUsername: string;
|
||||
avatar: string;
|
||||
name: string;
|
||||
},
|
||||
{ cache: localCache }: { cache: ApolloCache<NormalizedCacheObject> }
|
||||
) => {
|
||||
const data = {
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { IntrospectionFragmentMatcher, NormalizedCacheObject } from "apollo-cache-inmemory";
|
||||
import {
|
||||
IntrospectionFragmentMatcher,
|
||||
NormalizedCacheObject,
|
||||
} from "apollo-cache-inmemory";
|
||||
import { AUTH_ACCESS_TOKEN, AUTH_REFRESH_TOKEN } from "@/constants";
|
||||
import { REFRESH_TOKEN } from "@/graphql/auth";
|
||||
import { saveTokenData } from "@/utils/auth";
|
||||
@ -11,7 +14,11 @@ export const fragmentMatcher = new IntrospectionFragmentMatcher({
|
||||
{
|
||||
kind: "UNION",
|
||||
name: "SearchResult",
|
||||
possibleTypes: [{ name: "Event" }, { name: "Person" }, { name: "Group" }],
|
||||
possibleTypes: [
|
||||
{ name: "Event" },
|
||||
{ name: "Person" },
|
||||
{ name: "Group" },
|
||||
],
|
||||
},
|
||||
{
|
||||
kind: "INTERFACE",
|
||||
|
@ -13,7 +13,12 @@
|
||||
<template slot-scope="props">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<img width="32" :src="props.option.avatar.url" v-if="props.option.avatar" alt="" />
|
||||
<img
|
||||
width="32"
|
||||
:src="props.option.avatar.url"
|
||||
v-if="props.option.avatar"
|
||||
alt=""
|
||||
/>
|
||||
<b-icon v-else icon="account-circle" />
|
||||
</div>
|
||||
<div class="media-content">
|
||||
@ -21,7 +26,9 @@
|
||||
{{ props.option.name }}
|
||||
<br />
|
||||
<small>{{ `@${props.option.preferredUsername}` }}</small>
|
||||
<small v-if="props.option.domain">{{ `@${props.option.domain}` }}</small>
|
||||
<small v-if="props.option.domain">{{
|
||||
`@${props.option.domain}`
|
||||
}}</small>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ `@${props.option.preferredUsername}` }}
|
||||
@ -53,7 +60,9 @@ export default class ActorAutoComplete extends Vue {
|
||||
|
||||
selected: IPerson | null = this.defaultSelected;
|
||||
|
||||
name: string = this.defaultSelected ? this.defaultSelected.preferredUsername : "";
|
||||
name: string = this.defaultSelected
|
||||
? this.defaultSelected.preferredUsername
|
||||
: "";
|
||||
|
||||
page = 1;
|
||||
|
||||
|
@ -12,8 +12,15 @@
|
||||
<p>
|
||||
{{ actor.name || `@${usernameWithDomain(actor)}` }}
|
||||
</p>
|
||||
<p class="has-text-grey" v-if="actor.name">@{{ usernameWithDomain(actor) }}</p>
|
||||
<div v-if="full" class="summary" :class="{ limit: limit }" v-html="actor.summary" />
|
||||
<p class="has-text-grey" v-if="actor.name">
|
||||
@{{ usernameWithDomain(actor) }}
|
||||
</p>
|
||||
<div
|
||||
v-if="full"
|
||||
class="summary"
|
||||
:class="{ limit: limit }"
|
||||
v-html="actor.summary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,7 +7,10 @@
|
||||
<ul class="identities">
|
||||
<li v-for="identity in identities" :key="identity.id">
|
||||
<router-link
|
||||
:to="{ name: 'UpdateIdentity', params: { identityName: identity.preferredUsername } }"
|
||||
:to="{
|
||||
name: 'UpdateIdentity',
|
||||
params: { identityName: identity.preferredUsername },
|
||||
}"
|
||||
class="media identity"
|
||||
v-bind:class="{ 'is-current-identity': isCurrentIdentity(identity) }"
|
||||
>
|
||||
@ -24,7 +27,10 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<router-link :to="{ name: 'CreateIdentity' }" class="button create-identity is-primary">
|
||||
<router-link
|
||||
:to="{ name: 'CreateIdentity' }"
|
||||
class="button create-identity is-primary"
|
||||
>
|
||||
{{ $t("Create a new identity") }}
|
||||
</router-link>
|
||||
</section>
|
||||
|
@ -16,11 +16,21 @@
|
||||
checkable
|
||||
checkbox-position="left"
|
||||
>
|
||||
<b-table-column field="actor.id" label="ID" width="40" numeric v-slot="props">{{
|
||||
props.row.actor.id
|
||||
}}</b-table-column>
|
||||
<b-table-column
|
||||
field="actor.id"
|
||||
label="ID"
|
||||
width="40"
|
||||
numeric
|
||||
v-slot="props"
|
||||
>{{ props.row.actor.id }}</b-table-column
|
||||
>
|
||||
|
||||
<b-table-column field="actor.type" :label="$t('Type')" width="80" v-slot="props">
|
||||
<b-table-column
|
||||
field="actor.type"
|
||||
:label="$t('Type')"
|
||||
width="80"
|
||||
v-slot="props"
|
||||
>
|
||||
<b-icon icon="lan" v-if="RelayMixin.isInstance(props.row.actor)" />
|
||||
<b-icon icon="account-circle" v-else />
|
||||
</b-table-column>
|
||||
@ -33,26 +43,39 @@
|
||||
centered
|
||||
v-slot="props"
|
||||
>
|
||||
<span :class="`tag ${props.row.approved ? 'is-success' : 'is-danger'}`">{{
|
||||
props.row.approved ? $t("Accepted") : $t("Pending")
|
||||
}}</span>
|
||||
<span
|
||||
:class="`tag ${props.row.approved ? 'is-success' : 'is-danger'}`"
|
||||
>{{ props.row.approved ? $t("Accepted") : $t("Pending") }}</span
|
||||
>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="actor.domain" :label="$t('Domain')" sortable>
|
||||
<template v-slot:default="props">
|
||||
<a @click="toggle(props.row)" v-if="RelayMixin.isInstance(props.row.actor)">{{
|
||||
props.row.actor.domain
|
||||
}}</a>
|
||||
<a
|
||||
@click="toggle(props.row)"
|
||||
v-if="RelayMixin.isInstance(props.row.actor)"
|
||||
>{{ props.row.actor.domain }}</a
|
||||
>
|
||||
<a @click="toggle(props.row)" v-else>{{
|
||||
`${props.row.actor.preferredUsername}@${props.row.actor.domain}`
|
||||
}}</a>
|
||||
</template>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="targetActor.updatedAt" :label="$t('Date')" sortable v-slot="props">
|
||||
<span :title="$options.filters.formatDateTimeString(props.row.updatedAt)">{{
|
||||
formatDistanceToNow(new Date(props.row.updatedAt), { locale: $dateFnsLocale })
|
||||
}}</span></b-table-column
|
||||
<b-table-column
|
||||
field="targetActor.updatedAt"
|
||||
:label="$t('Date')"
|
||||
sortable
|
||||
v-slot="props"
|
||||
>
|
||||
<span
|
||||
:title="$options.filters.formatDateTimeString(props.row.updatedAt)"
|
||||
>{{
|
||||
formatDistanceToNow(new Date(props.row.updatedAt), {
|
||||
locale: $dateFnsLocale,
|
||||
})
|
||||
}}</span
|
||||
></b-table-column
|
||||
>
|
||||
|
||||
<template slot="detail" slot-scope="props">
|
||||
@ -143,7 +166,11 @@ export default class Followers extends Mixins(RelayMixin) {
|
||||
await this.$apollo.queries.relayFollowers.refetch();
|
||||
this.checkedRows = [];
|
||||
} catch (e) {
|
||||
Snackbar.open({ message: e.message, type: "is-danger", position: "is-bottom" });
|
||||
Snackbar.open({
|
||||
message: e.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +185,11 @@ export default class Followers extends Mixins(RelayMixin) {
|
||||
await this.$apollo.queries.relayFollowers.refetch();
|
||||
this.checkedRows = [];
|
||||
} catch (e) {
|
||||
Snackbar.open({ message: e.message, type: "is-danger", position: "is-bottom" });
|
||||
Snackbar.open({
|
||||
message: e.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
<form @submit="followRelay">
|
||||
<b-field :label="$t('Add an instance')" custom-class="add-relay" horizontal>
|
||||
<b-field
|
||||
:label="$t('Add an instance')"
|
||||
custom-class="add-relay"
|
||||
horizontal
|
||||
>
|
||||
<b-field grouped expanded size="is-large">
|
||||
<p class="control">
|
||||
<b-input v-model="newRelayAddress" :placeholder="$t('Ex: mobilizon.fr')" />
|
||||
<b-input
|
||||
v-model="newRelayAddress"
|
||||
:placeholder="$t('Ex: mobilizon.fr')"
|
||||
/>
|
||||
</p>
|
||||
<p class="control">
|
||||
<b-button type="is-primary" native-type="submit">{{ $t("Add an instance") }}</b-button>
|
||||
<b-button type="is-primary" native-type="submit">{{
|
||||
$t("Add an instance")
|
||||
}}</b-button>
|
||||
</p>
|
||||
</b-field>
|
||||
</b-field>
|
||||
@ -29,12 +38,25 @@
|
||||
checkable
|
||||
checkbox-position="left"
|
||||
>
|
||||
<b-table-column field="targetActor.id" label="ID" width="40" numeric v-slot="props">{{
|
||||
props.row.targetActor.id
|
||||
}}</b-table-column>
|
||||
<b-table-column
|
||||
field="targetActor.id"
|
||||
label="ID"
|
||||
width="40"
|
||||
numeric
|
||||
v-slot="props"
|
||||
>{{ props.row.targetActor.id }}</b-table-column
|
||||
>
|
||||
|
||||
<b-table-column field="targetActor.type" :label="$t('Type')" width="80" v-slot="props">
|
||||
<b-icon icon="lan" v-if="RelayMixin.isInstance(props.row.targetActor)" />
|
||||
<b-table-column
|
||||
field="targetActor.type"
|
||||
:label="$t('Type')"
|
||||
width="80"
|
||||
v-slot="props"
|
||||
>
|
||||
<b-icon
|
||||
icon="lan"
|
||||
v-if="RelayMixin.isInstance(props.row.targetActor)"
|
||||
/>
|
||||
<b-icon icon="account-circle" v-else />
|
||||
</b-table-column>
|
||||
|
||||
@ -46,26 +68,39 @@
|
||||
centered
|
||||
v-slot="props"
|
||||
>
|
||||
<span :class="`tag ${props.row.approved ? 'is-success' : 'is-danger'}`">{{
|
||||
props.row.approved ? $t("Accepted") : $t("Pending")
|
||||
}}</span>
|
||||
<span
|
||||
:class="`tag ${props.row.approved ? 'is-success' : 'is-danger'}`"
|
||||
>{{ props.row.approved ? $t("Accepted") : $t("Pending") }}</span
|
||||
>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="targetActor.domain" :label="$t('Domain')" sortable>
|
||||
<template v-slot:default="props">
|
||||
<a @click="toggle(props.row)" v-if="RelayMixin.isInstance(props.row.targetActor)">{{
|
||||
props.row.targetActor.domain
|
||||
}}</a>
|
||||
<a
|
||||
@click="toggle(props.row)"
|
||||
v-if="RelayMixin.isInstance(props.row.targetActor)"
|
||||
>{{ props.row.targetActor.domain }}</a
|
||||
>
|
||||
<a @click="toggle(props.row)" v-else>{{
|
||||
`${props.row.targetActor.preferredUsername}@${props.row.targetActor.domain}`
|
||||
}}</a>
|
||||
</template>
|
||||
</b-table-column>
|
||||
|
||||
<b-table-column field="targetActor.updatedAt" :label="$t('Date')" sortable v-slot="props">
|
||||
<span :title="$options.filters.formatDateTimeString(props.row.updatedAt)">{{
|
||||
formatDistanceToNow(new Date(props.row.updatedAt), { locale: $dateFnsLocale })
|
||||
}}</span></b-table-column
|
||||
<b-table-column
|
||||
field="targetActor.updatedAt"
|
||||
:label="$t('Date')"
|
||||
sortable
|
||||
v-slot="props"
|
||||
>
|
||||
<span
|
||||
:title="$options.filters.formatDateTimeString(props.row.updatedAt)"
|
||||
>{{
|
||||
formatDistanceToNow(new Date(props.row.updatedAt), {
|
||||
locale: $dateFnsLocale,
|
||||
})
|
||||
}}</span
|
||||
></b-table-column
|
||||
>
|
||||
|
||||
<template slot="detail" slot-scope="props">
|
||||
@ -132,13 +167,19 @@ export default class Followings extends Mixins(RelayMixin) {
|
||||
await this.$apollo.queries.relayFollowings.refetch();
|
||||
this.newRelayAddress = "";
|
||||
} catch (err) {
|
||||
Snackbar.open({ message: err.message, type: "is-danger", position: "is-bottom" });
|
||||
Snackbar.open({
|
||||
message: err.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async removeRelays(): Promise<void> {
|
||||
await this.checkedRows.forEach((row: IFollower) => {
|
||||
this.removeRelay(`${row.targetActor.preferredUsername}@${row.targetActor.domain}`);
|
||||
this.removeRelay(
|
||||
`${row.targetActor.preferredUsername}@${row.targetActor.domain}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -153,7 +194,11 @@ export default class Followings extends Mixins(RelayMixin) {
|
||||
await this.$apollo.queries.relayFollowings.refetch();
|
||||
this.checkedRows = [];
|
||||
} catch (e) {
|
||||
Snackbar.open({ message: e.message, type: "is-danger", position: "is-bottom" });
|
||||
Snackbar.open({
|
||||
message: e.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,34 @@
|
||||
<template>
|
||||
<li :class="{ reply: comment.inReplyToComment }">
|
||||
<article class="media" :class="{ selected: commentSelected }" :id="commentId">
|
||||
<article
|
||||
class="media"
|
||||
:class="{ selected: commentSelected }"
|
||||
:id="commentId"
|
||||
>
|
||||
<popover-actor-card
|
||||
class="media-left"
|
||||
:actor="comment.actor"
|
||||
:inline="true"
|
||||
v-if="comment.actor"
|
||||
>
|
||||
<figure class="image is-48x48" v-if="!comment.deletedAt && comment.actor.avatar">
|
||||
<figure
|
||||
class="image is-48x48"
|
||||
v-if="!comment.deletedAt && comment.actor.avatar"
|
||||
>
|
||||
<img class="is-rounded" :src="comment.actor.avatar.url" alt="" />
|
||||
</figure>
|
||||
<b-icon class="media-left" v-else size="is-large" icon="account-circle" />
|
||||
<b-icon
|
||||
class="media-left"
|
||||
v-else
|
||||
size="is-large"
|
||||
icon="account-circle"
|
||||
/>
|
||||
</popover-actor-card>
|
||||
<div v-else class="media-left">
|
||||
<figure class="image is-48x48" v-if="!comment.deletedAt && comment.actor.avatar">
|
||||
<figure
|
||||
class="image is-48x48"
|
||||
v-if="!comment.deletedAt && comment.actor.avatar"
|
||||
>
|
||||
<img class="is-rounded" :src="comment.actor.avatar.url" alt="" />
|
||||
</figure>
|
||||
<b-icon v-else size="is-large" icon="account-circle" />
|
||||
@ -21,7 +36,9 @@
|
||||
<div class="media-content">
|
||||
<div class="content">
|
||||
<span class="first-line" v-if="!comment.deletedAt">
|
||||
<strong :class="{ organizer: commentFromOrganizer }">{{ comment.actor.name }}</strong>
|
||||
<strong :class="{ organizer: commentFromOrganizer }">{{
|
||||
comment.actor.name
|
||||
}}</strong>
|
||||
<small>@{{ usernameWithDomain(comment.actor) }}</small>
|
||||
<a class="comment-link has-text-grey" :href="commentURL">
|
||||
<small>{{
|
||||
@ -54,10 +71,15 @@
|
||||
<div class="load-replies" v-if="comment.totalReplies">
|
||||
<p v-if="!showReplies" @click="fetchReplies">
|
||||
<b-icon icon="chevron-down" /><span>{{
|
||||
$tc("View a reply", comment.totalReplies, { totalReplies: comment.totalReplies })
|
||||
$tc("View a reply", comment.totalReplies, {
|
||||
totalReplies: comment.totalReplies,
|
||||
})
|
||||
}}</span>
|
||||
</p>
|
||||
<p v-else-if="comment.totalReplies && showReplies" @click="showReplies = false">
|
||||
<p
|
||||
v-else-if="comment.totalReplies && showReplies"
|
||||
@click="showReplies = false"
|
||||
>
|
||||
<b-icon icon="chevron-up" />
|
||||
<span>{{ $t("Hide replies") }}</span>
|
||||
</p>
|
||||
@ -86,14 +108,24 @@
|
||||
</nav>
|
||||
</div>
|
||||
</article>
|
||||
<form class="reply" @submit.prevent="replyToComment" v-if="currentActor.id" v-show="replyTo">
|
||||
<form
|
||||
class="reply"
|
||||
@submit.prevent="replyToComment"
|
||||
v-if="currentActor.id"
|
||||
v-show="replyTo"
|
||||
>
|
||||
<article class="media reply">
|
||||
<figure class="media-left" v-if="currentActor.avatar">
|
||||
<p class="image is-48x48">
|
||||
<img :src="currentActor.avatar.url" alt="" />
|
||||
</p>
|
||||
</figure>
|
||||
<b-icon class="media-left" v-else size="is-large" icon="account-circle" />
|
||||
<b-icon
|
||||
class="media-left"
|
||||
v-else
|
||||
size="is-large"
|
||||
icon="account-circle"
|
||||
/>
|
||||
<div class="media-content">
|
||||
<div class="content">
|
||||
<span class="first-line">
|
||||
@ -102,7 +134,12 @@
|
||||
</span>
|
||||
<br />
|
||||
<span class="editor-line">
|
||||
<editor class="editor" ref="commentEditor" v-model="newComment.text" mode="comment" />
|
||||
<editor
|
||||
class="editor"
|
||||
ref="commentEditor"
|
||||
v-model="newComment.text"
|
||||
mode="comment"
|
||||
/>
|
||||
<b-button
|
||||
:disabled="newComment.text.trim().length === 0"
|
||||
native-type="submit"
|
||||
@ -118,7 +155,12 @@
|
||||
<div class="left">
|
||||
<div class="vertical-border" @click="showReplies = false" />
|
||||
</div>
|
||||
<transition-group name="comment-replies" v-if="showReplies" class="comment-replies" tag="ul">
|
||||
<transition-group
|
||||
name="comment-replies"
|
||||
v-if="showReplies"
|
||||
class="comment-replies"
|
||||
tag="ul"
|
||||
>
|
||||
<comment
|
||||
class="reply"
|
||||
v-for="reply in comment.replies"
|
||||
@ -155,7 +197,8 @@ import PopoverActorCard from "../Account/PopoverActorCard.vue";
|
||||
},
|
||||
},
|
||||
components: {
|
||||
editor: () => import(/* webpackChunkName: "editor" */ "@/components/Editor.vue"),
|
||||
editor: () =>
|
||||
import(/* webpackChunkName: "editor" */ "@/components/Editor.vue"),
|
||||
comment: () => import(/* webpackChunkName: "comment" */ "./Comment.vue"),
|
||||
PopoverActorCard,
|
||||
},
|
||||
@ -167,7 +210,9 @@ export default class Comment extends Vue {
|
||||
|
||||
// Hack because Vue only exports it's own interface.
|
||||
// See https://github.com/kaorun343/vue-property-decorator/issues/257
|
||||
@Ref() readonly commentEditor!: EditorComponent & { replyToComment: (comment: IComment) => void };
|
||||
@Ref() readonly commentEditor!: EditorComponent & {
|
||||
replyToComment: (comment: IComment) => void;
|
||||
};
|
||||
|
||||
currentActor!: IPerson;
|
||||
|
||||
@ -231,7 +276,9 @@ export default class Comment extends Vue {
|
||||
if (!eventData) return;
|
||||
const { event } = eventData;
|
||||
const { comments } = event;
|
||||
const parentCommentIndex = comments.findIndex((oldComment) => oldComment.id === parentId);
|
||||
const parentCommentIndex = comments.findIndex(
|
||||
(oldComment) => oldComment.id === parentId
|
||||
);
|
||||
const parentComment = comments[parentCommentIndex];
|
||||
if (!parentComment) return;
|
||||
parentComment.replies = thread;
|
||||
@ -303,7 +350,11 @@ export default class Comment extends Vue {
|
||||
duration: 5000,
|
||||
});
|
||||
} catch (e) {
|
||||
Snackbar.open({ message: e.message, type: "is-danger", position: "is-bottom" });
|
||||
Snackbar.open({
|
||||
message: e.message,
|
||||
type: "is-danger",
|
||||
position: "is-bottom",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,11 @@
|
||||
@submit.prevent="createCommentForEvent(newComment)"
|
||||
@keyup.ctrl.enter="createCommentForEvent(newComment)"
|
||||
>
|
||||
<b-notification v-if="isEventOrganiser && !areCommentsClosed" :closable="false">{{
|
||||
$t("Comments are closed for everybody else.")
|
||||
}}</b-notification>
|
||||
<b-notification
|
||||
v-if="isEventOrganiser && !areCommentsClosed"
|
||||
:closable="false"
|
||||
>{{ $t("Comments are closed for everybody else.") }}</b-notification
|
||||
>
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<identity-picker-wrapper :inline="false" v-model="newComment.actor" />
|
||||
@ -16,11 +18,17 @@
|
||||
<div class="media-content">
|
||||
<div class="field">
|
||||
<p class="control">
|
||||
<editor ref="commenteditor" mode="comment" v-model="newComment.text" />
|
||||
<editor
|
||||
ref="commenteditor"
|
||||
mode="comment"
|
||||
v-model="newComment.text"
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<div class="send-comment">
|
||||
<b-button native-type="submit" type="is-primary">{{ $t("Post a comment") }}</b-button>
|
||||
<b-button native-type="submit" type="is-primary">{{
|
||||
$t("Post a comment")
|
||||
}}</b-button>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
@ -29,7 +37,12 @@
|
||||
$t("The organiser has chosen to close comments.")
|
||||
}}</b-notification>
|
||||
<transition name="comment-empty-list" mode="out-in">
|
||||
<transition-group name="comment-list" v-if="comments.length" class="comment-list" tag="ul">
|
||||
<transition-group
|
||||
name="comment-list"
|
||||
v-if="comments.length"
|
||||
class="comment-list"
|
||||
tag="ul"
|
||||
>
|
||||
<comment
|
||||
class="root-comment"
|
||||
:comment="comment"
|
||||
@ -76,7 +89,9 @@ import { IEvent } from "../../types/event.model";
|
||||
};
|
||||
},
|
||||
update(data) {
|
||||
return data.event.comments.map((comment: IComment) => new CommentModel(comment));
|
||||
return data.event.comments.map(
|
||||
(comment: IComment) => new CommentModel(comment)
|
||||
);
|
||||
},
|
||||
skip() {
|
||||
return !this.event.uuid;
|
||||
@ -86,7 +101,8 @@ import { IEvent } from "../../types/event.model";
|
||||
components: {
|
||||
Comment,
|
||||
IdentityPickerWrapper,
|
||||
editor: () => import(/* webpackChunkName: "editor" */ "@/components/Editor.vue"),
|
||||
editor: () =>
|
||||
import(/* webpackChunkName: "editor" */ "@/components/Editor.vue"),
|
||||
},
|
||||
})
|
||||
export default class CommentTree extends Vue {
|
||||
@ -113,7 +129,9 @@ export default class CommentTree extends Vue {
|
||||
variables: {
|
||||
eventId: this.event.id,
|
||||
text: comment.text,
|
||||
inReplyToCommentId: comment.inReplyToComment ? comment.inReplyToComment.id : null,
|
||||
inReplyToCommentId: comment.inReplyToComment
|
||||
? comment.inReplyToComment.id
|
||||
: null,
|
||||
},
|
||||
update: (store, { data }) => {
|
||||
if (data == null) return;
|
||||
@ -228,7 +246,9 @@ export default class CommentTree extends Vue {
|
||||
});
|
||||
if (!localData) return;
|
||||
const { thread: oldReplyList } = localData;
|
||||
const replies = oldReplyList.filter((reply) => reply.id !== deletedCommentId);
|
||||
const replies = oldReplyList.filter(
|
||||
(reply) => reply.id !== deletedCommentId
|
||||
);
|
||||
store.writeQuery({
|
||||
query: FETCH_THREAD_REPLIES,
|
||||
variables: {
|
||||
@ -249,7 +269,9 @@ export default class CommentTree extends Vue {
|
||||
event.comments = oldComments;
|
||||
} else {
|
||||
// we have deleted a thread itself
|
||||
event.comments = oldComments.filter((reply) => reply.id !== deletedCommentId);
|
||||
event.comments = oldComments.filter(
|
||||
(reply) => reply.id !== deletedCommentId
|
||||
);
|
||||
}
|
||||
store.writeQuery({
|
||||
query: COMMENTS_THREADS,
|
||||
@ -274,14 +296,18 @@ export default class CommentTree extends Vue {
|
||||
.filter((comment) => comment.inReplyToComment == null)
|
||||
.sort((a, b) => {
|
||||
if (a.updatedAt && b.updatedAt) {
|
||||
return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
|
||||
return (
|
||||
new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
get filteredOrderedComments(): IComment[] {
|
||||
return this.orderedComments.filter((comment) => !comment.deletedAt || comment.totalReplies > 0);
|
||||
return this.orderedComments.filter(
|
||||
(comment) => !comment.deletedAt || comment.totalReplies > 0
|
||||
);
|
||||
}
|
||||
|
||||
get isEventOrganiser(): boolean {
|
||||
|
@ -15,7 +15,10 @@
|
||||
<span v-else class="name comment-link has-text-grey">
|
||||
{{ $t("[deleted]") }}
|
||||
</span>
|
||||
<span class="icons" v-if="!comment.deletedAt && comment.actor.id === currentActor.id">
|
||||
<span
|
||||
class="icons"
|
||||
v-if="!comment.deletedAt && comment.actor.id === currentActor.id"
|
||||
>
|
||||
<b-dropdown aria-role="list">
|
||||
<b-icon slot="trigger" role="button" icon="dots-horizontal" />
|
||||
|
||||
@ -44,8 +47,9 @@
|
||||
<div class="post-infos">
|
||||
<span :title="comment.insertedAt | formatDateTimeString">
|
||||
{{
|
||||
formatDistanceToNow(new Date(comment.updatedAt), { locale: $dateFnsLocale }) ||
|
||||
$t("Right now")
|
||||
formatDistanceToNow(new Date(comment.updatedAt), {
|
||||
locale: $dateFnsLocale,
|
||||
}) || $t("Right now")
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
@ -77,7 +81,9 @@
|
||||
type="is-primary"
|
||||
>{{ $t("Update") }}</b-button
|
||||
>
|
||||
<b-button native-type="button" @click="toggleEditMode">{{ $t("Cancel") }}</b-button>
|
||||
<b-button native-type="button" @click="toggleEditMode">{{
|
||||
$t("Cancel")
|
||||
}}</b-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -95,7 +101,8 @@ import { CURRENT_ACTOR_CLIENT } from "../../graphql/actor";
|
||||
currentActor: CURRENT_ACTOR_CLIENT,
|
||||
},
|
||||
components: {
|
||||
editor: () => import(/* webpackChunkName: "editor" */ "@/components/Editor.vue"),
|
||||
editor: () =>
|
||||
import(/* webpackChunkName: "editor" */ "@/components/Editor.vue"),
|
||||
},
|
||||
})
|
||||
export default class DiscussionComment extends Vue {
|
||||
|
@ -1,14 +1,23 @@
|
||||
<template>
|
||||
<router-link
|
||||
class="discussion-minimalist-card-wrapper"
|
||||
:to="{ name: RouteName.DISCUSSION, params: { slug: discussion.slug, id: discussion.id } }"
|
||||
:to="{
|
||||
name: RouteName.DISCUSSION,
|
||||
params: { slug: discussion.slug, id: discussion.id },
|
||||
}"
|
||||
>
|
||||
<div class="media-left">
|
||||
<figure
|
||||
class="image is-32x32"
|
||||
v-if="discussion.lastComment.actor && discussion.lastComment.actor.avatar"
|
||||
v-if="
|
||||
discussion.lastComment.actor && discussion.lastComment.actor.avatar
|
||||
"
|
||||
>
|
||||
<img class="is-rounded" :src="discussion.lastComment.actor.avatar.url" alt />
|
||||
<img
|
||||
class="is-rounded"
|
||||
:src="discussion.lastComment.actor.avatar.url"
|
||||
alt
|
||||
/>
|
||||
</figure>
|
||||
<b-icon v-else size="is-medium" icon="account-circle" />
|
||||
</div>
|
||||
@ -17,15 +26,18 @@
|
||||
<p class="discussion-minimalist-title">{{ discussion.title }}</p>
|
||||
<span :title="actualDate | formatDateTimeString">
|
||||
{{
|
||||
formatDistanceToNowStrict(new Date(actualDate), { locale: $dateFnsLocale }) ||
|
||||
$t("Right now")
|
||||
formatDistanceToNowStrict(new Date(actualDate), {
|
||||
locale: $dateFnsLocale,
|
||||
}) || $t("Right now")
|
||||
}}</span
|
||||
>
|
||||
</div>
|
||||
<div class="has-text-grey" v-if="!discussion.lastComment.deletedAt">
|
||||
{{ htmlTextEllipsis }}
|
||||
</div>
|
||||
<div v-else class="has-text-grey">{{ $t("[This comment has been deleted]") }}</div>
|
||||
<div v-else class="has-text-grey">
|
||||
{{ $t("[This comment has been deleted]") }}
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
</template>
|
||||
@ -54,7 +66,10 @@ export default class DiscussionListItem extends Vue {
|
||||
}
|
||||
|
||||
get actualDate(): string | Date | undefined {
|
||||
if (this.discussion.updatedAt === this.discussion.insertedAt && this.discussion.lastComment) {
|
||||
if (
|
||||
this.discussion.updatedAt === this.discussion.insertedAt &&
|
||||
this.discussion.lastComment
|
||||
) {
|
||||
return this.discussion.lastComment.publishedAt;
|
||||
}
|
||||
return this.discussion.updatedAt;
|
||||
@ -83,7 +98,8 @@ export default class DiscussionListItem extends Vue {
|
||||
|
||||
.discussion-minimalist-title {
|
||||
color: #3c376e;
|
||||
font-family: "Liberation Sans", "Helvetica Neue", Roboto, Helvetica, Arial, serif;
|
||||
font-family: "Liberation Sans", "Helvetica Neue", Roboto, Helvetica,
|
||||
Arial, serif;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
flex: 1;
|
||||
|
@ -117,11 +117,21 @@
|
||||
<b-icon icon="format-quote-close" />
|
||||
</button>
|
||||
|
||||
<button v-if="!isBasicMode" class="menubar__button" @click="commands.undo" type="button">
|
||||
<button
|
||||
v-if="!isBasicMode"
|
||||
class="menubar__button"
|
||||
@click="commands.undo"
|
||||
type="button"
|
||||
>
|
||||
<b-icon icon="undo" />
|
||||
</button>
|
||||
|
||||
<button v-if="!isBasicMode" class="menubar__button" @click="commands.redo" type="button">
|
||||
<button
|
||||
v-if="!isBasicMode"
|
||||
class="menubar__button"
|
||||
@click="commands.redo"
|
||||
type="button"
|
||||
>
|
||||
<b-icon icon="redo" />
|
||||
</button>
|
||||
</div>
|
||||
@ -181,7 +191,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="suggestion-list__item is-empty">{{ $t("No profiles found") }}</div>
|
||||
<div v-else class="suggestion-list__item is-empty">
|
||||
{{ $t("No profiles found") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -430,7 +442,8 @@ export default class EditorComponent extends Vue {
|
||||
|
||||
upHandler(): void {
|
||||
this.navigatedActorIndex =
|
||||
(this.navigatedActorIndex + this.filteredActors.length - 1) % this.filteredActors.length;
|
||||
(this.navigatedActorIndex + this.filteredActors.length - 1) %
|
||||
this.filteredActors.length;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -438,7 +451,8 @@ export default class EditorComponent extends Vue {
|
||||
* if it's the last item, navigate to the first one
|
||||
*/
|
||||
downHandler(): void {
|
||||
this.navigatedActorIndex = (this.navigatedActorIndex + 1) % this.filteredActors.length;
|
||||
this.navigatedActorIndex =
|
||||
(this.navigatedActorIndex + 1) % this.filteredActors.length;
|
||||
}
|
||||
|
||||
enterHandler(): void {
|
||||
@ -533,7 +547,10 @@ export default class EditorComponent extends Vue {
|
||||
},
|
||||
});
|
||||
if (data.uploadMedia && data.uploadMedia.url) {
|
||||
command({ src: data.uploadMedia.url, "data-media-id": data.uploadMedia.id });
|
||||
command({
|
||||
src: data.uploadMedia.url,
|
||||
"data-media-id": data.uploadMedia.id,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
@ -48,9 +48,14 @@ export default class Image extends Node {
|
||||
}
|
||||
|
||||
commands({ type }: { type: NodeType }): any {
|
||||
return (attrs: { [key: string]: string }) => (state: EditorState, dispatch: DispatchFn) => {
|
||||
return (attrs: { [key: string]: string }) => (
|
||||
state: EditorState,
|
||||
dispatch: DispatchFn
|
||||
) => {
|
||||
const { selection }: { selection: TextSelection } = state;
|
||||
const position = selection.$cursor ? selection.$cursor.pos : selection.$to.pos;
|
||||
const position = selection.$cursor
|
||||
? selection.$cursor.pos
|
||||
: selection.$to.pos;
|
||||
const node = type.create(attrs);
|
||||
const transaction = state.tr.insert(position, node);
|
||||
dispatch(transaction);
|
||||
@ -75,7 +80,8 @@ export default class Image extends Node {
|
||||
}
|
||||
|
||||
const images = Array.from(realEvent.dataTransfer.files).filter(
|
||||
(file: any) => /image/i.test(file.type) && !/svg/i.test(file.type)
|
||||
(file: any) =>
|
||||
/image/i.test(file.type) && !/svg/i.test(file.type)
|
||||
);
|
||||
|
||||
if (images.length === 0) {
|
||||
@ -105,7 +111,10 @@ export default class Image extends Node {
|
||||
src: data.uploadMedia.url,
|
||||
"data-media-id": data.uploadMedia.id,
|
||||
});
|
||||
const transaction = view.state.tr.insert(coordinates.pos, node);
|
||||
const transaction = view.state.tr.insert(
|
||||
coordinates.pos,
|
||||
node
|
||||
);
|
||||
view.dispatch(transaction);
|
||||
});
|
||||
return true;
|
||||
|
@ -21,9 +21,13 @@
|
||||
</b-autocomplete>
|
||||
</b-field>
|
||||
<b-field v-if="isSecureContext()">
|
||||
<b-button type="is-text" v-if="!gettingLocation" icon-right="target" @click="locateMe">{{
|
||||
$t("Use my location")
|
||||
}}</b-button>
|
||||
<b-button
|
||||
type="is-text"
|
||||
v-if="!gettingLocation"
|
||||
icon-right="target"
|
||||
@click="locateMe"
|
||||
>{{ $t("Use my location") }}</b-button
|
||||
>
|
||||
<span v-else>{{ $t("Getting location") }}</span>
|
||||
</b-field>
|
||||
<!--
|
||||
@ -58,7 +62,8 @@ import { IConfig } from "../../types/config.model";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
"map-leaflet": () => import(/* webpackChunkName: "map" */ "@/components/Map.vue"),
|
||||
"map-leaflet": () =>
|
||||
import(/* webpackChunkName: "map" */ "@/components/Map.vue"),
|
||||
},
|
||||
apollo: {
|
||||
config: CONFIG,
|
||||
@ -121,7 +126,9 @@ export default class AddressAutoComplete extends Vue {
|
||||
},
|
||||
});
|
||||
|
||||
this.addressData = result.data.searchAddress.map((address: IAddress) => new Address(address));
|
||||
this.addressData = result.data.searchAddress.map(
|
||||
(address: IAddress) => new Address(address)
|
||||
);
|
||||
this.isFetching = false;
|
||||
}
|
||||
|
||||
@ -174,7 +181,9 @@ export default class AddressAutoComplete extends Vue {
|
||||
},
|
||||
});
|
||||
|
||||
this.addressData = result.data.reverseGeocode.map((address: IAddress) => new Address(address));
|
||||
this.addressData = result.data.reverseGeocode.map(
|
||||
(address: IAddress) => new Address(address)
|
||||
);
|
||||
if (this.addressData.length > 0) {
|
||||
const defaultAddress = new Address(this.addressData[0]);
|
||||
this.selected = defaultAddress;
|
||||
@ -197,7 +206,10 @@ export default class AddressAutoComplete extends Vue {
|
||||
this.location = await AddressAutoComplete.getLocation();
|
||||
this.mapDefaultZoom = 12;
|
||||
this.reverseGeoCode(
|
||||
new LatLng(this.location.coords.latitude, this.location.coords.longitude),
|
||||
new LatLng(
|
||||
this.location.coords.latitude,
|
||||
this.location.coords.longitude
|
||||
),
|
||||
12
|
||||
);
|
||||
} catch (e) {
|
||||
|
@ -102,14 +102,20 @@ export default class DateTimePicker extends Vue {
|
||||
}
|
||||
|
||||
get minTime(): Date | null {
|
||||
if (this.minDatetime && this.datesAreOnSameDay(this.dateWithTime, this.minDatetime)) {
|
||||
if (
|
||||
this.minDatetime &&
|
||||
this.datesAreOnSameDay(this.dateWithTime, this.minDatetime)
|
||||
) {
|
||||
return this.minDatetime;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
get maxTime(): Date | null {
|
||||
if (this.maxDatetime && this.datesAreOnSameDay(this.dateWithTime, this.maxDatetime)) {
|
||||
if (
|
||||
this.maxDatetime &&
|
||||
this.datesAreOnSameDay(this.dateWithTime, this.maxDatetime)
|
||||
) {
|
||||
return this.maxDatetime;
|
||||
}
|
||||
return null;
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<router-link class="card" :to="{ name: 'Event', params: { uuid: event.uuid } }">
|
||||
<router-link
|
||||
class="card"
|
||||
:to="{ name: 'Event', params: { uuid: event.uuid } }"
|
||||
>
|
||||
<div class="card-image">
|
||||
<figure
|
||||
class="image is-16by9"
|
||||
@ -21,14 +24,18 @@
|
||||
<div class="card-content">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<date-calendar-icon v-if="!mergedOptions.hideDate" :date="event.beginsOn" />
|
||||
<date-calendar-icon
|
||||
v-if="!mergedOptions.hideDate"
|
||||
:date="event.beginsOn"
|
||||
/>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p class="event-title">{{ event.title }}</p>
|
||||
<div class="event-subtitle" v-if="event.physicalAddress">
|
||||
<!-- <p>{{ $t('By @{username}', { username: actor.preferredUsername }) }}</p>-->
|
||||
<span>
|
||||
{{ event.physicalAddress.description }}, {{ event.physicalAddress.locality }}
|
||||
{{ event.physicalAddress.description }},
|
||||
{{ event.physicalAddress.locality }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -18,7 +18,9 @@
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<span v-if="!endsOn">{{ beginsOn | formatDateTimeString(showStartTime) }}</span>
|
||||
<span v-if="!endsOn">{{
|
||||
beginsOn | formatDateTimeString(showStartTime)
|
||||
}}</span>
|
||||
<span v-else-if="isSameDay() && showStartTime && showEndTime">
|
||||
{{
|
||||
$t("On {date} from {startTime} to {endTime}", {
|
||||
@ -44,7 +46,9 @@
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<span v-else-if="isSameDay()">{{ $t("On {date}", { date: formatDate(beginsOn) }) }}</span>
|
||||
<span v-else-if="isSameDay()">{{
|
||||
$t("On {date}", { date: formatDate(beginsOn) })
|
||||
}}</span>
|
||||
<span v-else-if="endsOn && showStartTime && showEndTime">
|
||||
{{
|
||||
$t("From the {startDate} at {startTime} to the {endDate} at {endTime}", {
|
||||
@ -97,7 +101,9 @@ export default class EventFullDate extends Vue {
|
||||
}
|
||||
|
||||
isSameDay(): boolean {
|
||||
const sameDay = new Date(this.beginsOn).toDateString() === new Date(this.endsOn).toDateString();
|
||||
const sameDay =
|
||||
new Date(this.beginsOn).toDateString() ===
|
||||
new Date(this.endsOn).toDateString();
|
||||
return this.endsOn !== undefined && sameDay;
|
||||
}
|
||||
}
|
||||
|
@ -6,25 +6,38 @@
|
||||
<div class="date-component">
|
||||
<date-calendar-icon :date="participation.event.beginsOn" />
|
||||
</div>
|
||||
<router-link :to="{ name: RouteName.EVENT, params: { uuid: participation.event.uuid } }">
|
||||
<router-link
|
||||
:to="{
|
||||
name: RouteName.EVENT,
|
||||
params: { uuid: participation.event.uuid },
|
||||
}"
|
||||
>
|
||||
<h3 class="title">{{ participation.event.title }}</h3>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="participation-actor has-text-grey">
|
||||
<span>
|
||||
<b-icon icon="earth" v-if="participation.event.visibility === EventVisibility.PUBLIC" />
|
||||
<b-icon
|
||||
icon="earth"
|
||||
v-if="participation.event.visibility === EventVisibility.PUBLIC"
|
||||
/>
|
||||
<b-icon
|
||||
icon="link"
|
||||
v-else-if="participation.event.visibility === EventVisibility.UNLISTED"
|
||||
v-else-if="
|
||||
participation.event.visibility === EventVisibility.UNLISTED
|
||||
"
|
||||
/>
|
||||
<b-icon
|
||||
icon="lock"
|
||||
v-else-if="participation.event.visibility === EventVisibility.PRIVATE"
|
||||
v-else-if="
|
||||
participation.event.visibility === EventVisibility.PRIVATE
|
||||
"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
v-if="
|
||||
participation.event.physicalAddress && participation.event.physicalAddress.locality
|
||||
participation.event.physicalAddress &&
|
||||
participation.event.physicalAddress.locality
|
||||
"
|
||||
>{{ participation.event.physicalAddress.locality }} -</span
|
||||
>
|
||||
@ -43,7 +56,11 @@
|
||||
path="Going as {name}"
|
||||
tag="span"
|
||||
>
|
||||
<popover-actor-card slot="name" :actor="participation.actor" :inline="true">
|
||||
<popover-actor-card
|
||||
slot="name"
|
||||
:actor="participation.actor"
|
||||
:inline="true"
|
||||
>
|
||||
{{ participation.actor.displayName() }}
|
||||
</popover-actor-card>
|
||||
< |