@@ -1,23 +1,23 @@
|
||||
<template>
|
||||
<div class="container mx-auto" v-if="hasCurrentActorPermissionsToEdit">
|
||||
<h1 class="" v-if="isUpdate === true">
|
||||
{{ $t("Update event {name}", { name: event.title }) }}
|
||||
{{ t("Update event {name}", { name: event.title }) }}
|
||||
</h1>
|
||||
<h1 class="" v-else>
|
||||
{{ $t("Create a new event") }}
|
||||
{{ t("Create a new event") }}
|
||||
</h1>
|
||||
|
||||
<form ref="form">
|
||||
<h2>{{ $t("General information") }}</h2>
|
||||
<h2>{{ t("General information") }}</h2>
|
||||
<picture-upload
|
||||
v-if="pictureFile"
|
||||
v-model:pictureFile="pictureFile"
|
||||
:textFallback="$t('Headline picture')"
|
||||
v-model:modelValue="pictureFile"
|
||||
:textFallback="t('Headline picture')"
|
||||
:defaultImage="event.picture"
|
||||
/>
|
||||
|
||||
<o-field
|
||||
:label="$t('Title')"
|
||||
:label="t('Title')"
|
||||
label-for="title"
|
||||
:type="checkTitleLength[0]"
|
||||
:message="checkTitleLength[1]"
|
||||
@@ -35,12 +35,12 @@
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<o-field
|
||||
v-if="eventCategories"
|
||||
:label="$t('Category')"
|
||||
:label="t('Category')"
|
||||
label-for="category"
|
||||
class="w-full md:max-w-fit"
|
||||
>
|
||||
<o-select
|
||||
:placeholder="$t('Select a category')"
|
||||
:placeholder="t('Select a category')"
|
||||
v-model="event.category"
|
||||
expanded
|
||||
>
|
||||
@@ -62,13 +62,13 @@
|
||||
|
||||
<o-field
|
||||
horizontal
|
||||
:label="$t('Starts on…')"
|
||||
:label="t('Starts on…')"
|
||||
class="begins-on-field"
|
||||
label-for="begins-on-field"
|
||||
>
|
||||
<o-datetimepicker
|
||||
class="datepicker starts-on"
|
||||
:placeholder="$t('Type or select a date…')"
|
||||
:placeholder="t('Type or select a date…')"
|
||||
icon="calendar-today"
|
||||
:locale="$i18n.locale"
|
||||
v-model="beginsOn"
|
||||
@@ -78,17 +78,17 @@
|
||||
:first-day-of-week="firstDayOfWeek"
|
||||
:datepicker="{
|
||||
id: 'begins-on-field',
|
||||
'aria-next-label': $t('Next month'),
|
||||
'aria-previous-label': $t('Previous month'),
|
||||
'aria-next-label': t('Next month'),
|
||||
'aria-previous-label': t('Previous month'),
|
||||
}"
|
||||
>
|
||||
</o-datetimepicker>
|
||||
</o-field>
|
||||
|
||||
<o-field horizontal :label="$t('Ends on…')" label-for="ends-on-field">
|
||||
<o-field horizontal :label="t('Ends on…')" label-for="ends-on-field">
|
||||
<o-datetimepicker
|
||||
class="datepicker ends-on"
|
||||
:placeholder="$t('Type or select a date…')"
|
||||
:placeholder="t('Type or select a date…')"
|
||||
icon="calendar-today"
|
||||
:locale="$i18n.locale"
|
||||
v-model="endsOn"
|
||||
@@ -99,41 +99,40 @@
|
||||
:first-day-of-week="firstDayOfWeek"
|
||||
:datepicker="{
|
||||
id: 'ends-on-field',
|
||||
'aria-next-label': $t('Next month'),
|
||||
'aria-previous-label': $t('Previous month'),
|
||||
'aria-next-label': t('Next month'),
|
||||
'aria-previous-label': t('Previous month'),
|
||||
}"
|
||||
>
|
||||
</o-datetimepicker>
|
||||
</o-field>
|
||||
|
||||
<o-button type="is-text" @click="dateSettingsIsOpen = true">
|
||||
{{ $t("Date parameters") }}
|
||||
<o-button class="block" variant="text" @click="dateSettingsIsOpen = true">
|
||||
{{ t("Date parameters") }}
|
||||
</o-button>
|
||||
|
||||
<div class="address">
|
||||
<div class="my-6">
|
||||
<full-address-auto-complete
|
||||
v-model="eventPhysicalAddress"
|
||||
:user-timezone="userActualTimezone"
|
||||
:disabled="isOnline"
|
||||
:disabled="event.options.isOnline"
|
||||
:hideSelected="true"
|
||||
/>
|
||||
<o-switch class="is-online" v-model="isOnline">{{
|
||||
$t("The event is fully online")
|
||||
<o-switch class="my-4" v-model="isOnline">{{
|
||||
t("The event is fully online")
|
||||
}}</o-switch>
|
||||
</div>
|
||||
|
||||
<div class="o-field field">
|
||||
<label class="o-field__label field-label">{{
|
||||
$t("Description")
|
||||
}}</label>
|
||||
<label class="o-field__label field-label">{{ t("Description") }}</label>
|
||||
<editor-component
|
||||
v-if="currentActor"
|
||||
:current-actor="(currentActor as IPerson)"
|
||||
v-model="event.description"
|
||||
:aria-label="$t('Event description body')"
|
||||
:aria-label="t('Event description body')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<o-field :label="$t('Website / URL')" label-for="website-url">
|
||||
<o-field :label="t('Website / URL')" label-for="website-url">
|
||||
<o-input
|
||||
icon="link"
|
||||
type="url"
|
||||
@@ -144,7 +143,7 @@
|
||||
</o-field>
|
||||
|
||||
<section class="my-4">
|
||||
<h2>{{ $t("Organizers") }}</h2>
|
||||
<h2>{{ t("Organizers") }}</h2>
|
||||
|
||||
<div v-if="features?.groups && organizerActor?.id">
|
||||
<o-field>
|
||||
@@ -155,21 +154,21 @@
|
||||
</o-field>
|
||||
<p v-if="!attributedToAGroup && organizerActorEqualToCurrentActor">
|
||||
{{
|
||||
$t("The event will show as attributed to your personal profile.")
|
||||
t("The event will show as attributed to your personal profile.")
|
||||
}}
|
||||
</p>
|
||||
<p v-else-if="!attributedToAGroup">
|
||||
{{ $t("The event will show as attributed to this profile.") }}
|
||||
{{ t("The event will show as attributed to this profile.") }}
|
||||
</p>
|
||||
<p v-else>
|
||||
<span>{{
|
||||
$t("The event will show as attributed to this group.")
|
||||
t("The event will show as attributed to this group.")
|
||||
}}</span>
|
||||
<span
|
||||
v-if="event.contacts && event.contacts.length"
|
||||
v-html="
|
||||
' ' +
|
||||
$t(
|
||||
t(
|
||||
'<b>{contact}</b> will be displayed as contact.',
|
||||
|
||||
{
|
||||
@@ -184,16 +183,16 @@
|
||||
"
|
||||
/>
|
||||
<span v-else>
|
||||
{{ $t("You may show some members as contacts.") }}
|
||||
{{ t("You may show some members as contacts.") }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<section class="my-4">
|
||||
<h2>{{ $t("Event metadata") }}</h2>
|
||||
<h2>{{ t("Event metadata") }}</h2>
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"Integrate this event with 3rd-party tools and show metadata for the event."
|
||||
)
|
||||
}}
|
||||
@@ -202,12 +201,12 @@
|
||||
</section>
|
||||
<section class="my-4">
|
||||
<h2>
|
||||
{{ $t("Who can view this event and participate") }}
|
||||
{{ t("Who can view this event and participate") }}
|
||||
</h2>
|
||||
<fieldset>
|
||||
<legend>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"When the event is private, you'll need to share the link around."
|
||||
)
|
||||
}}
|
||||
@@ -217,7 +216,7 @@
|
||||
v-model="event.visibility"
|
||||
name="eventVisibility"
|
||||
:native-value="EventVisibility.PUBLIC"
|
||||
>{{ $t("Visible everywhere on the web (public)") }}</o-radio
|
||||
>{{ t("Visible everywhere on the web (public)") }}</o-radio
|
||||
>
|
||||
</div>
|
||||
<div class="field">
|
||||
@@ -225,7 +224,7 @@
|
||||
v-model="event.visibility"
|
||||
name="eventVisibility"
|
||||
:native-value="EventVisibility.UNLISTED"
|
||||
>{{ $t("Only accessible through link (private)") }}</o-radio
|
||||
>{{ t("Only accessible through link (private)") }}</o-radio
|
||||
>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -233,7 +232,7 @@
|
||||
<o-radio v-model="event.visibility"
|
||||
name="eventVisibility"
|
||||
:native-value="EventVisibility.PRIVATE">
|
||||
{{ $t('Page limited to my group (asks for auth)') }}
|
||||
{{ t('Page limited to my group (asks for auth)') }}
|
||||
</o-radio>
|
||||
</div>-->
|
||||
|
||||
@@ -242,9 +241,7 @@
|
||||
:label="t('Anonymous participations')"
|
||||
>
|
||||
<o-switch v-model="eventOptions.anonymousParticipation">
|
||||
{{
|
||||
$t("I want to allow people to participate without an account.")
|
||||
}}
|
||||
{{ t("I want to allow people to participate without an account.") }}
|
||||
<small
|
||||
v-if="
|
||||
anonymousParticipationConfig?.validation.email
|
||||
@@ -253,7 +250,7 @@
|
||||
>
|
||||
<br />
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"Anonymous participants will be asked to confirm their participation through e-mail."
|
||||
)
|
||||
}}
|
||||
@@ -263,23 +260,23 @@
|
||||
|
||||
<o-field :label="t('Participation approval')">
|
||||
<o-switch v-model="needsApproval">{{
|
||||
$t("I want to approve every participation request")
|
||||
t("I want to approve every participation request")
|
||||
}}</o-switch>
|
||||
</o-field>
|
||||
|
||||
<o-field :label="t('Number of places')">
|
||||
<o-switch v-model="limitedPlaces">{{
|
||||
$t("Limited number of places")
|
||||
t("Limited number of places")
|
||||
}}</o-switch>
|
||||
</o-field>
|
||||
|
||||
<div class="" v-if="limitedPlaces">
|
||||
<o-field :label="$t('Number of places')" label-for="number-of-places">
|
||||
<o-field :label="t('Number of places')" label-for="number-of-places">
|
||||
<o-input
|
||||
type="number"
|
||||
controls-position="compact"
|
||||
:aria-minus-label="$t('Decrease')"
|
||||
:aria-plus-label="$t('Increase')"
|
||||
:aria-minus-label="t('Decrease')"
|
||||
:aria-plus-label="t('Increase')"
|
||||
min="1"
|
||||
v-model="eventOptions.maximumAttendeeCapacity"
|
||||
id="number-of-places"
|
||||
@@ -288,28 +285,28 @@
|
||||
<!--
|
||||
<o-field>
|
||||
<o-switch v-model="eventOptions.showRemainingAttendeeCapacity">
|
||||
{{ $t('Show remaining number of places') }}
|
||||
{{ t('Show remaining number of places') }}
|
||||
</o-switch>
|
||||
</o-field>
|
||||
|
||||
<o-field>
|
||||
<o-switch v-model="eventOptions.showParticipationPrice">
|
||||
{{ $t('Display participation price') }}
|
||||
{{ t('Display participation price') }}
|
||||
</o-switch>
|
||||
</o-field>-->
|
||||
</div>
|
||||
</section>
|
||||
<section class="my-4">
|
||||
<h2>{{ $t("Public comment moderation") }}</h2>
|
||||
<h2>{{ t("Public comment moderation") }}</h2>
|
||||
|
||||
<fieldset>
|
||||
<legend>{{ $t("Who can post a comment?") }}</legend>
|
||||
<legend>{{ t("Who can post a comment?") }}</legend>
|
||||
<o-field>
|
||||
<o-radio
|
||||
v-model="eventOptions.commentModeration"
|
||||
name="commentModeration"
|
||||
:native-value="CommentModeration.ALLOW_ALL"
|
||||
>{{ $t("Allow all comments from users with accounts") }}</o-radio
|
||||
>{{ t("Allow all comments from users with accounts") }}</o-radio
|
||||
>
|
||||
</o-field>
|
||||
|
||||
@@ -317,7 +314,7 @@
|
||||
<!-- <o-radio v-model="eventOptions.commentModeration"-->
|
||||
<!-- name="commentModeration"-->
|
||||
<!-- :native-value="CommentModeration.MODERATED">-->
|
||||
<!-- {{ $t('Moderated comments (shown after approval)') }}-->
|
||||
<!-- {{ t('Moderated comments (shown after approval)') }}-->
|
||||
<!-- </o-radio>-->
|
||||
<!-- </div>-->
|
||||
|
||||
@@ -326,18 +323,18 @@
|
||||
v-model="eventOptions.commentModeration"
|
||||
name="commentModeration"
|
||||
:native-value="CommentModeration.CLOSED"
|
||||
>{{ $t("Close comments for all (except for admins)") }}</o-radio
|
||||
>{{ t("Close comments for all (except for admins)") }}</o-radio
|
||||
>
|
||||
</o-field>
|
||||
</fieldset>
|
||||
</section>
|
||||
<section class="my-4">
|
||||
<h2>{{ $t("Status") }}</h2>
|
||||
<h2>{{ t("Status") }}</h2>
|
||||
|
||||
<fieldset>
|
||||
<legend>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"Does the event needs to be confirmed later or is it cancelled?"
|
||||
)
|
||||
}}
|
||||
@@ -350,7 +347,7 @@
|
||||
:native-value="EventStatus.TENTATIVE"
|
||||
>
|
||||
<o-icon icon="calendar-question" />
|
||||
{{ $t("Tentative: Will be confirmed later") }}
|
||||
{{ t("Tentative: Will be confirmed later") }}
|
||||
</o-radio>
|
||||
<o-radio
|
||||
v-model="event.status"
|
||||
@@ -359,7 +356,7 @@
|
||||
:native-value="EventStatus.CONFIRMED"
|
||||
>
|
||||
<o-icon icon="calendar-check" />
|
||||
{{ $t("Confirmed: Will happen") }}
|
||||
{{ t("Confirmed: Will happen") }}
|
||||
</o-radio>
|
||||
<o-radio
|
||||
v-model="event.status"
|
||||
@@ -368,7 +365,7 @@
|
||||
:native-value="EventStatus.CANCELLED"
|
||||
>
|
||||
<o-icon icon="calendar-remove" />
|
||||
{{ $t("Cancelled: Won't happen") }}
|
||||
{{ t("Cancelled: Won't happen") }}
|
||||
</o-radio>
|
||||
</o-field>
|
||||
</fieldset>
|
||||
@@ -377,30 +374,30 @@
|
||||
</div>
|
||||
<div class="container mx-auto" v-else>
|
||||
<o-notification variant="danger">
|
||||
{{ $t("Only group moderators can create, edit and delete events.") }}
|
||||
{{ t("Only group moderators can create, edit and delete events.") }}
|
||||
</o-notification>
|
||||
</div>
|
||||
<o-modal
|
||||
v-model:active="dateSettingsIsOpen"
|
||||
has-modal-card
|
||||
trap-focus
|
||||
:close-button-aria-label="$t('Close')"
|
||||
:close-button-aria-label="t('Close')"
|
||||
>
|
||||
<form class="p-3">
|
||||
<header class="">
|
||||
<h2 class="">{{ $t("Date and time settings") }}</h2>
|
||||
<h2 class="">{{ t("Date and time settings") }}</h2>
|
||||
</header>
|
||||
<section class="">
|
||||
<p>
|
||||
{{
|
||||
$t(
|
||||
t(
|
||||
"Event timezone will default to the timezone of the event's address if there is one, or to your own timezone setting."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<o-field :label="$t('Timezone')" label-for="timezone" expanded>
|
||||
<o-field :label="t('Timezone')" label-for="timezone" expanded>
|
||||
<o-select
|
||||
:placeholder="$t('Select a timezone')"
|
||||
:placeholder="t('Select a timezone')"
|
||||
:loading="timezoneLoading"
|
||||
v-model="timezone"
|
||||
id="timezone"
|
||||
@@ -424,23 +421,23 @@
|
||||
@click="timezone = null"
|
||||
class="reset-area"
|
||||
icon-left="close"
|
||||
:title="$t('Clear timezone field')"
|
||||
:title="t('Clear timezone field')"
|
||||
/>
|
||||
</o-field>
|
||||
<o-field :label="$t('Event page settings')">
|
||||
<o-field :label="t('Event page settings')">
|
||||
<o-switch v-model="eventOptions.showStartTime">{{
|
||||
$t("Show the time when the event begins")
|
||||
t("Show the time when the event begins")
|
||||
}}</o-switch>
|
||||
</o-field>
|
||||
<o-field>
|
||||
<o-switch v-model="eventOptions.showEndTime">{{
|
||||
$t("Show the time when the event ends")
|
||||
t("Show the time when the event ends")
|
||||
}}</o-switch>
|
||||
</o-field>
|
||||
</section>
|
||||
<footer class="mt-2">
|
||||
<o-button @click="dateSettingsIsOpen = false">
|
||||
{{ $t("OK") }}
|
||||
{{ t("OK") }}
|
||||
</o-button>
|
||||
</footer>
|
||||
</form>
|
||||
@@ -449,23 +446,22 @@
|
||||
<nav
|
||||
role="navigation"
|
||||
aria-label="main navigation"
|
||||
class="bg-secondary/70"
|
||||
class="bg-mbz-yellow-alt-200 py-3"
|
||||
:class="{ 'is-fixed-bottom': showFixedNavbar }"
|
||||
v-if="hasCurrentActorPermissionsToEdit"
|
||||
>
|
||||
<div class="container mx-auto">
|
||||
<div class="flex justify-between">
|
||||
<div class="">
|
||||
<span class="dark:text-gray-900" v-if="isEventModified">{{
|
||||
$t("Unsaved changes")
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="dark:text-gray-900" v-if="isEventModified">
|
||||
{{ t("Unsaved changes") }}
|
||||
</span>
|
||||
<div class="flex flex-wrap gap-3 items-center">
|
||||
<span class="">
|
||||
<o-button type="is-text" @click="confirmGoBack">{{
|
||||
$t("Cancel")
|
||||
}}</o-button>
|
||||
</span>
|
||||
<o-button
|
||||
variant="text"
|
||||
@click="confirmGoBack"
|
||||
class="dark:!text-black"
|
||||
>{{ t("Cancel") }}</o-button
|
||||
>
|
||||
<!-- If an event has been published we can't make it draft anymore -->
|
||||
<span class="" v-if="event.draft === true">
|
||||
<o-button
|
||||
@@ -473,7 +469,7 @@
|
||||
outlined
|
||||
@click="createOrUpdateDraft"
|
||||
:disabled="saving"
|
||||
>{{ $t("Save draft") }}</o-button
|
||||
>{{ t("Save draft") }}</o-button
|
||||
>
|
||||
</span>
|
||||
<span class="">
|
||||
@@ -483,9 +479,9 @@
|
||||
@click="createOrUpdatePublish"
|
||||
@keyup.enter="createOrUpdatePublish"
|
||||
>
|
||||
<span v-if="isUpdate === false">{{ $t("Create my event") }}</span>
|
||||
<span v-else-if="event.draft === true">{{ $t("Publish") }}</span>
|
||||
<span v-else>{{ $t("Update my event") }}</span>
|
||||
<span v-if="isUpdate === false">{{ t("Create my event") }}</span>
|
||||
<span v-else-if="event.draft === true">{{ t("Publish") }}</span>
|
||||
<span v-else>{{ t("Update my event") }}</span>
|
||||
</o-button>
|
||||
</span>
|
||||
</div>
|
||||
@@ -596,7 +592,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { getTimezoneOffset } from "date-fns-tz";
|
||||
import PictureUpload from "@/components/PictureUpload.vue";
|
||||
import EditorComponent from "@/components/Editor.vue";
|
||||
import EditorComponent from "@/components/TextEditor.vue";
|
||||
import TagInput from "@/components/Event/TagInput.vue";
|
||||
import FullAddressAutoComplete from "@/components/Event/FullAddressAutoComplete.vue";
|
||||
import EventMetadataList from "@/components/Event/EventMetadataList.vue";
|
||||
@@ -617,27 +613,33 @@ import {
|
||||
MemberRole,
|
||||
ParticipantRole,
|
||||
} from "@/types/enums";
|
||||
import OrganizerPickerWrapper from "../../components/Event/OrganizerPickerWrapper.vue";
|
||||
import OrganizerPickerWrapper from "@/components/Event/OrganizerPickerWrapper.vue";
|
||||
import {
|
||||
CREATE_EVENT,
|
||||
EDIT_EVENT,
|
||||
EVENT_PERSON_PARTICIPATION,
|
||||
} from "../../graphql/event";
|
||||
} from "@/graphql/event";
|
||||
import {
|
||||
EventModel,
|
||||
IEditableEvent,
|
||||
IEvent,
|
||||
removeTypeName,
|
||||
toEditJSON,
|
||||
} from "../../types/event.model";
|
||||
import { LOGGED_USER_DRAFTS } from "../../graphql/actor";
|
||||
import { IActor, IGroup, IPerson, usernameWithDomain } from "../../types/actor";
|
||||
} from "@/types/event.model";
|
||||
import { LOGGED_USER_DRAFTS } from "@/graphql/actor";
|
||||
import {
|
||||
IActor,
|
||||
IGroup,
|
||||
IPerson,
|
||||
usernameWithDomain,
|
||||
displayNameAndUsername,
|
||||
} from "@/types/actor";
|
||||
import {
|
||||
buildFileFromIMedia,
|
||||
buildFileVariable,
|
||||
readFileAsync,
|
||||
} from "../../utils/image";
|
||||
import RouteName from "../../router/name";
|
||||
} from "@/utils/image";
|
||||
import RouteName from "@/router/name";
|
||||
import "intersection-observer";
|
||||
import {
|
||||
ApolloCache,
|
||||
@@ -759,7 +761,7 @@ const unmodifiedEvent = ref<IEditableEvent>(new EventModel());
|
||||
|
||||
const pictureFile = ref<File | null>(null);
|
||||
|
||||
const canPromote = ref(true);
|
||||
// const canPromote = ref(true);
|
||||
const limitedPlaces = ref(false);
|
||||
const showFixedNavbar = ref(true);
|
||||
|
||||
@@ -905,7 +907,7 @@ onCreateEventMutationDone(async ({ data }) => {
|
||||
message: (event.value.draft
|
||||
? t("The event has been created as a draft")
|
||||
: t("The event has been published")) as string,
|
||||
variant: "is-success",
|
||||
variant: "success",
|
||||
position: "bottom-right",
|
||||
duration: 5000,
|
||||
});
|
||||
@@ -964,6 +966,7 @@ onEditEventMutationError((err) => {
|
||||
const updateEvent = async (): Promise<void> => {
|
||||
saving.value = true;
|
||||
const variables = await buildVariables();
|
||||
console.debug("update event", variables);
|
||||
editEventMutation(variables);
|
||||
};
|
||||
|
||||
@@ -1016,7 +1019,6 @@ const handleError = (err: any) => {
|
||||
*/
|
||||
const postCreateOrUpdate = (store: any, updatedEvent: IEvent) => {
|
||||
const resultEvent: IEvent = { ...updatedEvent };
|
||||
console.debug("resultEvent", resultEvent);
|
||||
if (!updatedEvent.draft) {
|
||||
store.writeQuery({
|
||||
query: EVENT_PERSON_PARTICIPATION,
|
||||
@@ -1056,7 +1058,6 @@ const postCreateOrUpdate = (store: any, updatedEvent: IEvent) => {
|
||||
/**
|
||||
* Refresh drafts or participation cache depending if the event is still draft or not
|
||||
*/
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
const postRefetchQueries = (
|
||||
updatedEvent: IEvent
|
||||
): InternalRefetchQueriesInclude => {
|
||||
@@ -1093,11 +1094,11 @@ const buildVariables = async () => {
|
||||
options: eventOptions.value,
|
||||
};
|
||||
|
||||
// const organizerActor = event.value?.organizerActor?.id
|
||||
// ? event.value.organizerActor
|
||||
// : organizerActor.value;
|
||||
const localOrganizerActor = event.value?.organizerActor?.id
|
||||
? event.value.organizerActor
|
||||
: organizerActor.value;
|
||||
if (organizerActor.value) {
|
||||
res = { ...res, organizerActorId: organizerActor.value?.id };
|
||||
res = { ...res, organizerActorId: localOrganizerActor?.id };
|
||||
}
|
||||
const attributedToId = event.value?.attributedTo?.id
|
||||
? event.value?.attributedTo.id
|
||||
@@ -1155,7 +1156,7 @@ const needsApproval = computed({
|
||||
|
||||
const checkTitleLength = computed((): Array<string | undefined> => {
|
||||
return event.value.title.length > 80
|
||||
? ["is-info", t("The event title will be ellipsed.") as string]
|
||||
? ["info", t("The event title will be ellipsed.")]
|
||||
: [undefined, undefined];
|
||||
});
|
||||
|
||||
@@ -1189,7 +1190,7 @@ const confirmGoElsewhere = (): Promise<boolean> => {
|
||||
message,
|
||||
confirmText: t("Abandon editing") as string,
|
||||
cancelText: t("Continue editing") as string,
|
||||
type: "is-warning",
|
||||
variant: "warning",
|
||||
hasIcon: true,
|
||||
onConfirm: () => resolve(true),
|
||||
onCancel: () => resolve(false),
|
||||
@@ -1356,6 +1357,13 @@ const isOnline = computed({
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
watch(isOnline, (newIsOnline) => {
|
||||
if (newIsOnline === true) {
|
||||
eventPhysicalAddress.value = null;
|
||||
}
|
||||
});
|
||||
|
||||
const dateFnsLocale = inject<Locale>("dateFnsLocale");
|
||||
|
||||
const firstDayOfWeek = computed((): number => {
|
||||
@@ -1366,6 +1374,15 @@ const { event: fetchedEvent, onResult: onFetchEventResult } = useFetchEvent(
|
||||
eventId.value
|
||||
);
|
||||
|
||||
watch(
|
||||
fetchedEvent,
|
||||
() => {
|
||||
if (!fetchedEvent.value) return;
|
||||
event.value = { ...fetchedEvent.value };
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
onFetchEventResult((result) => {
|
||||
if (!result.loading && result.data?.event) {
|
||||
event.value = { ...result.data?.event };
|
||||
@@ -65,36 +65,35 @@
|
||||
</popover-actor-card>
|
||||
</span>
|
||||
</div>
|
||||
<p class="flex gap-1 items-center" dir="auto">
|
||||
<tag v-if="eventCategory" class="category" capitalize>{{
|
||||
eventCategory
|
||||
}}</tag>
|
||||
<router-link
|
||||
v-for="tag in event?.tags ?? []"
|
||||
:key="tag.title"
|
||||
:to="{ name: RouteName.TAG, params: { tag: tag.title } }"
|
||||
>
|
||||
<tag>{{ tag.title }}</tag>
|
||||
</router-link>
|
||||
</p>
|
||||
<tag variant="warning" size="is-medium" v-if="event?.draft"
|
||||
>{{ t("Draft") }}
|
||||
</tag>
|
||||
<span
|
||||
class="event-status"
|
||||
v-if="event?.status !== EventStatus.CONFIRMED"
|
||||
>
|
||||
<tag
|
||||
variant="warning"
|
||||
v-if="event?.status === EventStatus.TENTATIVE"
|
||||
>{{ t("Event to be confirmed") }}</tag
|
||||
>
|
||||
<tag
|
||||
variant="danger"
|
||||
v-if="event?.status === EventStatus.CANCELLED"
|
||||
>{{ t("Event cancelled") }}</tag
|
||||
>
|
||||
</span>
|
||||
<div class="inline-flex items-center gap-1">
|
||||
<p v-if="event?.status !== EventStatus.CONFIRMED">
|
||||
<tag
|
||||
variant="warning"
|
||||
v-if="event?.status === EventStatus.TENTATIVE"
|
||||
>{{ t("Event to be confirmed") }}</tag
|
||||
>
|
||||
<tag
|
||||
variant="danger"
|
||||
v-if="event?.status === EventStatus.CANCELLED"
|
||||
>{{ t("Event cancelled") }}</tag
|
||||
>
|
||||
</p>
|
||||
<p class="flex gap-1 items-center" dir="auto">
|
||||
<tag v-if="eventCategory" class="category" capitalize>{{
|
||||
eventCategory
|
||||
}}</tag>
|
||||
<router-link
|
||||
v-for="tag in event?.tags ?? []"
|
||||
:key="tag.title"
|
||||
:to="{ name: RouteName.TAG, params: { tag: tag.title } }"
|
||||
>
|
||||
<tag>{{ tag.title }}</tag>
|
||||
</router-link>
|
||||
</p>
|
||||
<tag variant="warning" size="medium" v-if="event?.draft"
|
||||
>{{ t("Draft") }}
|
||||
</tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
@@ -375,7 +374,7 @@
|
||||
ref="reportModal"
|
||||
:close-button-aria-label="t('Close')"
|
||||
>
|
||||
<report-modal
|
||||
<ReportModal
|
||||
:on-confirm="reportEvent"
|
||||
:title="t('Report this event')"
|
||||
:outside-domain="organizerDomain"
|
||||
@@ -456,7 +455,7 @@
|
||||
<o-field :label="t('Message')">
|
||||
<o-input
|
||||
type="textarea"
|
||||
size="is-medium"
|
||||
size="medium"
|
||||
v-model="messageForConfirmation"
|
||||
minlength="10"
|
||||
></o-input>
|
||||
@@ -522,35 +521,28 @@ import {
|
||||
FETCH_EVENT,
|
||||
JOIN_EVENT,
|
||||
} from "@/graphql/event";
|
||||
import { CURRENT_ACTOR_CLIENT, PERSON_STATUS_GROUP } from "@/graphql/actor";
|
||||
import { EventModel, IEvent } from "@/types/event.model";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import {
|
||||
displayName,
|
||||
IActor,
|
||||
IPerson,
|
||||
Person,
|
||||
usernameWithDomain,
|
||||
} from "@/types/actor";
|
||||
import { GRAPHQL_API_ENDPOINT } from "@/api/_entrypoint";
|
||||
import DateCalendarIcon from "@/components/Event/DateCalendarIcon.vue";
|
||||
import MultiCard from "@/components/Event/MultiCard.vue";
|
||||
import ReportModal from "@/components/Report/ReportModal.vue";
|
||||
import { IReport } from "@/types/report.model";
|
||||
import { CREATE_REPORT } from "@/graphql/report";
|
||||
import EventMixin from "@/mixins/event";
|
||||
import IdentityPicker from "../Account/IdentityPicker.vue";
|
||||
import IdentityPicker from "@/views/Account/IdentityPicker.vue";
|
||||
import ParticipationSection from "@/components/Participation/ParticipationSection.vue";
|
||||
import RouteName from "@/router/name";
|
||||
import CommentTree from "@/components/Comment/CommentTree.vue";
|
||||
import "intersection-observer";
|
||||
import { CONFIG } from "@/graphql/config";
|
||||
import {
|
||||
AnonymousParticipationNotFoundError,
|
||||
getLeaveTokenForParticipation,
|
||||
isParticipatingInThisEvent,
|
||||
removeAnonymousParticipation,
|
||||
} from "@/services/AnonymousParticipationStorage";
|
||||
import { IConfig } from "@/types/config.model";
|
||||
import Tag from "@/components/Tag.vue";
|
||||
import EventMetadataSidebar from "@/components/Event/EventMetadataSidebar.vue";
|
||||
import EventBanner from "@/components/Event/EventBanner.vue";
|
||||
@@ -560,12 +552,9 @@ import { IParticipant } from "@/types/participant.model";
|
||||
import { ApolloCache, FetchResult } from "@apollo/client/core";
|
||||
import { IEventMetadataDescription } from "@/types/event-metadata";
|
||||
import { eventMetaDataList } from "@/services/EventMetadata";
|
||||
import { USER_SETTINGS } from "@/graphql/user";
|
||||
import { IUser } from "@/types/current-user.model";
|
||||
import { useDeleteEvent, useFetchEvent } from "@/composition/apollo/event";
|
||||
import {
|
||||
computed,
|
||||
handleError,
|
||||
onMounted,
|
||||
ref,
|
||||
watch,
|
||||
@@ -601,24 +590,26 @@ import { useI18n } from "vue-i18n";
|
||||
import { useProgrammatic } from "@oruga-ui/oruga-next";
|
||||
import { Dialog } from "@/plugins/dialog";
|
||||
import { Notifier } from "@/plugins/notifier";
|
||||
import { AbsintheGraphQLErrors } from "@/types/errors.model";
|
||||
import { useHead } from "@vueuse/head";
|
||||
|
||||
const ShareEventModal = defineAsyncComponent(
|
||||
() => import("@/components/Event/ShareEventModal.vue")
|
||||
);
|
||||
const IntegrationTwitch = defineAsyncComponent(
|
||||
() => import("@/components/Event/Integrations/Twitch.vue")
|
||||
() => import("@/components/Event/Integrations/TwitchIntegration.vue")
|
||||
);
|
||||
const IntegrationPeertube = defineAsyncComponent(
|
||||
() => import("@/components/Event/Integrations/PeerTube.vue")
|
||||
() => import("@/components/Event/Integrations/PeerTubeIntegration.vue")
|
||||
);
|
||||
const IntegrationYoutube = defineAsyncComponent(
|
||||
() => import("@/components/Event/Integrations/YouTube.vue")
|
||||
() => import("@/components/Event/Integrations/YouTubeIntegration.vue")
|
||||
);
|
||||
const IntegrationJitsiMeet = defineAsyncComponent(
|
||||
() => import("@/components/Event/Integrations/JitsiMeet.vue")
|
||||
() => import("@/components/Event/Integrations/JitsiMeetIntegration.vue")
|
||||
);
|
||||
const IntegrationEtherpad = defineAsyncComponent(
|
||||
() => import("@/components/Event/Integrations/Etherpad.vue")
|
||||
() => import("@/components/Event/Integrations/EtherpadIntegration.vue")
|
||||
);
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -1057,8 +1048,8 @@ const triggerShare = (): void => {
|
||||
title: event.value?.title,
|
||||
url: event.value?.url,
|
||||
})
|
||||
.then(() => console.log("Successful share"))
|
||||
.catch((error: any) => console.log("Error sharing", error));
|
||||
.then(() => console.debug("Successful share"))
|
||||
.catch((error: any) => console.debug("Error sharing", error));
|
||||
} else {
|
||||
isShareModalActive.value = true;
|
||||
// send popup
|
||||
@@ -1067,7 +1058,7 @@ const triggerShare = (): void => {
|
||||
// @ts-ignore-end
|
||||
};
|
||||
|
||||
const handleErrors = (errors: any[]): void => {
|
||||
const handleErrors = (errors: AbsintheGraphQLErrors): void => {
|
||||
if (
|
||||
errors.some((error) => error.status_code === 404) ||
|
||||
errors.some(({ message }) => message.includes("has invalid value $uuid"))
|
||||
@@ -1076,7 +1067,9 @@ const handleErrors = (errors: any[]): void => {
|
||||
}
|
||||
};
|
||||
|
||||
onFetchEventError(({ graphQlErrors }) => handleErrors(graphQLErrors));
|
||||
onFetchEventError(({ graphQLErrors }) =>
|
||||
handleErrors(graphQLErrors as AbsintheGraphQLErrors)
|
||||
);
|
||||
|
||||
const actorIsParticipant = computed((): boolean => {
|
||||
if (actorIsOrganizer.value) return true;
|
||||
@@ -1108,7 +1101,7 @@ const canManageEvent = computed((): boolean => {
|
||||
return actorIsOrganizer.value || hasGroupPrivileges.value;
|
||||
});
|
||||
|
||||
const endDate = computed((): Date | undefined => {
|
||||
const endDate = computed((): string | undefined => {
|
||||
return event.value?.endsOn && event.value.endsOn > event.value.beginsOn
|
||||
? event.value.endsOn
|
||||
: event.value?.beginsOn;
|
||||
@@ -1211,6 +1204,11 @@ const eventCategory = computed((): string | undefined => {
|
||||
return eventCategory.id === event.value?.category;
|
||||
})?.label as string;
|
||||
});
|
||||
|
||||
useHead({
|
||||
title: computed(() => eventTitle.value ?? ""),
|
||||
meta: [{ name: "description", content: eventDescription.value }],
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@use "@/styles/_mixins" as *;
|
||||
@@ -1380,10 +1378,6 @@ a.participations-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.event-status .tag {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.no-border {
|
||||
border: 0;
|
||||
cursor: auto;
|
||||
@@ -70,7 +70,7 @@
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<o-button type="is-text" tag="a" :href="group.url">
|
||||
<o-button variant="text" tag="a" :href="group.url">
|
||||
{{ $t("View the group profile on the original instance") }}
|
||||
</o-button>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
</div>
|
||||
<!-- <o-loading v-model:active="$apollo.loading"></o-loading> -->
|
||||
<div class="wrapper flex flex-wrap gap-4 items-start">
|
||||
<div class="event-filter text-violet-1 flex-auto md:flex-none">
|
||||
<div
|
||||
class="event-filter rounded p-3 flex-auto md:flex-none bg-zinc-300 dark:bg-zinc-700"
|
||||
>
|
||||
<o-field>
|
||||
<o-switch v-model="showUpcoming">{{
|
||||
showUpcoming ? t("Upcoming events") : t("Past events")
|
||||
@@ -56,10 +58,12 @@
|
||||
? t('Showing events starting on')
|
||||
: t('Showing events before')
|
||||
"
|
||||
labelFor="events-start-datepicker"
|
||||
>
|
||||
<o-datepicker
|
||||
v-model="dateFilter"
|
||||
:first-day-of-week="firstDayOfWeek"
|
||||
id="events-start-datepicker"
|
||||
/>
|
||||
<o-button
|
||||
@click="dateFilter = new Date()"
|
||||
@@ -469,9 +473,6 @@ section {
|
||||
|
||||
.event-filter {
|
||||
grid-area: filter;
|
||||
background: lightgray;
|
||||
border-radius: 5px;
|
||||
padding: 0.75rem 1.25rem 0.25rem;
|
||||
|
||||
// @include desktop {
|
||||
// padding: 2rem 1.25rem;
|
||||
@@ -55,16 +55,22 @@
|
||||
:key="format"
|
||||
aria-role="listitem"
|
||||
@click="
|
||||
exportParticipants({
|
||||
eventId: event?.id,
|
||||
format,
|
||||
})
|
||||
exportParticipants(
|
||||
{
|
||||
eventId: event?.id,
|
||||
format,
|
||||
},
|
||||
{ context: { type: format } }
|
||||
)
|
||||
"
|
||||
@keyup.enter="
|
||||
exportParticipants({
|
||||
eventId: event.value?.id,
|
||||
format,
|
||||
})
|
||||
exportParticipants(
|
||||
{
|
||||
eventId: event?.id,
|
||||
format,
|
||||
},
|
||||
{ context: { type: format } }
|
||||
)
|
||||
"
|
||||
>
|
||||
<button class="dropdown-button">
|
||||
@@ -81,9 +87,9 @@
|
||||
ref="queueTable"
|
||||
detailed
|
||||
detail-key="id"
|
||||
:checked-rows.sync="checkedRows"
|
||||
v-model:checked-rows="checkedRows"
|
||||
checkable
|
||||
:is-row-checkable="(row) => row.role !== ParticipantRole.CREATOR"
|
||||
:is-row-checkable="(row: IParticipant) => row.role !== ParticipantRole.CREATOR"
|
||||
checkbox-position="left"
|
||||
:show-detail-icon="false"
|
||||
:loading="participantsLoading"
|
||||
@@ -100,37 +106,38 @@
|
||||
backend-sorting
|
||||
:default-sort-direction="'desc'"
|
||||
:default-sort="['insertedAt', 'desc']"
|
||||
@page-change="(newPage) => (page = newPage)"
|
||||
@sort="(field, order) => emit('sort', field, order)"
|
||||
@page-change="(newPage: number) => (page = newPage)"
|
||||
@sort="(field: string, order: string) => emit('sort', field, order)"
|
||||
>
|
||||
<o-table-column
|
||||
field="actor.preferredUsername"
|
||||
:label="t('Participant')"
|
||||
v-slot="props"
|
||||
>
|
||||
<article class="media">
|
||||
<figure
|
||||
class="media-left image is-48x48"
|
||||
v-if="props.row.actor.avatar"
|
||||
>
|
||||
<img class="is-rounded" :src="props.row.actor.avatar.url" alt="" />
|
||||
<article>
|
||||
<figure v-if="props.row.actor.avatar">
|
||||
<img
|
||||
class="rounded"
|
||||
:src="props.row.actor.avatar.url"
|
||||
alt=""
|
||||
height="48"
|
||||
width="48"
|
||||
/>
|
||||
</figure>
|
||||
<Incognito
|
||||
v-else-if="props.row.actor.preferredUsername === 'anonymous'"
|
||||
:size="48"
|
||||
/>
|
||||
<AccountCircle v-else :size="48" />
|
||||
<div class="media-content">
|
||||
<div>
|
||||
<div class="prose dark:prose-invert">
|
||||
<span v-if="props.row.actor.preferredUsername !== 'anonymous'">
|
||||
<span v-if="props.row.actor.name">{{
|
||||
props.row.actor.name
|
||||
}}</span
|
||||
><br />
|
||||
<span class="is-size-7 has-text-grey-dark"
|
||||
>@{{ usernameWithDomain(props.row.actor) }}</span
|
||||
>
|
||||
</span>
|
||||
>@{{ usernameWithDomain(props.row.actor) }}</span
|
||||
>
|
||||
<span v-else>
|
||||
{{ t("Anonymous participant") }}
|
||||
</span>
|
||||
@@ -139,30 +146,30 @@
|
||||
</article>
|
||||
</o-table-column>
|
||||
<o-table-column field="role" :label="t('Role')" v-slot="props">
|
||||
<b-tag
|
||||
<tag
|
||||
variant="primary"
|
||||
v-if="props.row.role === ParticipantRole.CREATOR"
|
||||
>
|
||||
{{ t("Organizer") }}
|
||||
</b-tag>
|
||||
<b-tag v-else-if="props.row.role === ParticipantRole.PARTICIPANT">
|
||||
</tag>
|
||||
<tag v-else-if="props.row.role === ParticipantRole.PARTICIPANT">
|
||||
{{ t("Participant") }}
|
||||
</b-tag>
|
||||
<b-tag v-else-if="props.row.role === ParticipantRole.NOT_CONFIRMED">
|
||||
</tag>
|
||||
<tag v-else-if="props.row.role === ParticipantRole.NOT_CONFIRMED">
|
||||
{{ t("Not confirmed") }}
|
||||
</b-tag>
|
||||
<b-tag
|
||||
</tag>
|
||||
<tag
|
||||
variant="warning"
|
||||
v-else-if="props.row.role === ParticipantRole.NOT_APPROVED"
|
||||
>
|
||||
{{ t("Not approved") }}
|
||||
</b-tag>
|
||||
<b-tag
|
||||
</tag>
|
||||
<tag
|
||||
variant="danger"
|
||||
v-else-if="props.row.role === ParticipantRole.REJECTED"
|
||||
>
|
||||
{{ t("Rejected") }}
|
||||
</b-tag>
|
||||
</tag>
|
||||
</o-table-column>
|
||||
<o-table-column
|
||||
field="metadata.message"
|
||||
@@ -250,17 +257,17 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ParticipantRole } from "@/types/enums";
|
||||
import { IParticipant } from "../../types/participant.model";
|
||||
import { IEvent, IEventParticipantStats } from "../../types/event.model";
|
||||
import { IParticipant } from "@/types/participant.model";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import {
|
||||
EXPORT_EVENT_PARTICIPATIONS,
|
||||
PARTICIPANTS,
|
||||
UPDATE_PARTICIPANT,
|
||||
} from "../../graphql/event";
|
||||
import { usernameWithDomain } from "../../types/actor";
|
||||
import { nl2br } from "../../utils/html";
|
||||
import { asyncForEach } from "../../utils/asyncForEach";
|
||||
import RouteName from "../../router/name";
|
||||
} from "@/graphql/event";
|
||||
import { usernameWithDomain } from "@/types/actor";
|
||||
import { nl2br } from "@/utils/html";
|
||||
import { asyncForEach } from "@/utils/asyncForEach";
|
||||
import RouteName from "@/router/name";
|
||||
import { useCurrentActorClient } from "@/composition/apollo/actor";
|
||||
import { useParticipantsExportFormats } from "@/composition/config";
|
||||
import { useMutation, useQuery } from "@vue/apollo-composable";
|
||||
@@ -276,6 +283,7 @@ import AccountCircle from "vue-material-design-icons/AccountCircle.vue";
|
||||
import Incognito from "vue-material-design-icons/Incognito.vue";
|
||||
import EmptyContent from "@/components/Utils/EmptyContent.vue";
|
||||
import { Notifier } from "@/plugins/notifier";
|
||||
import Tag from "@/components/Tag.vue";
|
||||
|
||||
const PARTICIPANTS_PER_PAGE = 10;
|
||||
const MESSAGE_ELLIPSIS_LENGTH = 130;
|
||||
@@ -286,6 +294,8 @@ const props = defineProps<{
|
||||
eventId: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(["sort"]);
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
const { currentActor } = useCurrentActorClient();
|
||||
@@ -307,11 +317,9 @@ const role = useRouteQuery(
|
||||
enumTransformer(ParticipantRole)
|
||||
);
|
||||
|
||||
const limit = ref(PARTICIPANTS_PER_PAGE);
|
||||
|
||||
const checkedRows = ref<IParticipant[]>([]);
|
||||
|
||||
// const queueTable = ref(null);
|
||||
const queueTable = ref();
|
||||
|
||||
const { result: participantsResult, loading: participantsLoading } = useQuery<{
|
||||
event: IEvent;
|
||||
@@ -333,10 +341,10 @@ const { result: participantsResult, loading: participantsLoading } = useQuery<{
|
||||
|
||||
const event = computed(() => participantsResult.value?.event);
|
||||
|
||||
const participantStats = computed((): IEventParticipantStats | null => {
|
||||
if (!event.value) return null;
|
||||
return event.value.participantStats;
|
||||
});
|
||||
// const participantStats = computed((): IEventParticipantStats | null => {
|
||||
// if (!event.value) return null;
|
||||
// return event.value.participantStats;
|
||||
// });
|
||||
|
||||
const { mutate: updateParticipant, onError: onUpdateParticipantError } =
|
||||
useMutation(UPDATE_PARTICIPANT);
|
||||
@@ -373,14 +381,14 @@ const {
|
||||
onError: onExportParticipantsMutationError,
|
||||
} = useMutation(EXPORT_EVENT_PARTICIPATIONS);
|
||||
|
||||
onExportParticipantsMutationDone(({ data }) => {
|
||||
onExportParticipantsMutationDone(({ data, context }) => {
|
||||
const link =
|
||||
window.origin +
|
||||
"/exports/" +
|
||||
type.toLowerCase() +
|
||||
context?.type.toLowerCase() +
|
||||
"/" +
|
||||
exportEventParticipants;
|
||||
console.log(link);
|
||||
data?.exportEventParticipants;
|
||||
console.debug(link);
|
||||
const a = document.createElement("a");
|
||||
a.style.display = "none";
|
||||
document.body.appendChild(a);
|
||||
@@ -449,7 +457,7 @@ const toggleQueueDetails = (row: IParticipant): void => {
|
||||
}
|
||||
};
|
||||
|
||||
const openDetailedRows = <Record<string, boolean>>{};
|
||||
const openDetailedRows = ref<Record<string, boolean>>({});
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
@@ -485,21 +493,4 @@ nav.breadcrumb {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
button.dropdown-button {
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
color: #0a0a0a;
|
||||
}
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
background: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #4a4a4a;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
padding: 0.375rem 1rem;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user