Merge branch 'improvements' into 'master'

Upgrade vue-apollo to @vue/apollo-option

See merge request framasoft/mobilizon!937
This commit is contained in:
Thomas Citharel 2021-06-11 16:59:54 +00:00
commit 3fa6001eae
37 changed files with 457 additions and 347 deletions

View file

@ -29,6 +29,7 @@
"@tiptap/extension-underline": "^2.0.0-beta.7", "@tiptap/extension-underline": "^2.0.0-beta.7",
"@tiptap/starter-kit": "^2.0.0-beta.37", "@tiptap/starter-kit": "^2.0.0-beta.37",
"@tiptap/vue-2": "^2.0.0-beta.21", "@tiptap/vue-2": "^2.0.0-beta.21",
"@vue/apollo-option": "^4.0.0-alpha.11",
"apollo-absinthe-upload-link": "^1.5.0", "apollo-absinthe-upload-link": "^1.5.0",
"blurhash": "^1.1.3", "blurhash": "^1.1.3",
"buefy": "^0.9.0", "buefy": "^0.9.0",
@ -50,7 +51,6 @@
"unfetch": "^4.2.0", "unfetch": "^4.2.0",
"v-tooltip": "^2.1.3", "v-tooltip": "^2.1.3",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-apollo": "^3.0.3",
"vue-class-component": "^7.2.3", "vue-class-component": "^7.2.3",
"vue-i18n": "^8.14.0", "vue-i18n": "^8.14.0",
"vue-meta": "^2.3.1", "vue-meta": "^2.3.1",

View file

@ -37,7 +37,7 @@ export const possibleTypes = types.reduce((acc, type) => {
export const typePolicies: TypePolicies = { export const typePolicies: TypePolicies = {
Discussion: { Discussion: {
fields: { fields: {
comments: paginatedLimitPagination(), comments: paginatedLimitPagination<IComment>(),
}, },
}, },
Group: { Group: {

View file

@ -32,7 +32,6 @@ $color-black: #000;
.mention { .mention {
background: rgba($color-black, 0.1); background: rgba($color-black, 0.1);
color: rgba($color-black, 0.6);
font-size: 0.9rem; font-size: 0.9rem;
font-weight: bold; font-weight: bold;
border-radius: 5px; border-radius: 5px;

View file

@ -12,7 +12,7 @@
<p> <p>
{{ actor.name || `@${usernameWithDomain(actor)}` }} {{ actor.name || `@${usernameWithDomain(actor)}` }}
</p> </p>
<p class="has-text-grey" v-if="actor.name"> <p class="has-text-grey-dark" v-if="actor.name">
@{{ usernameWithDomain(actor) }} @{{ usernameWithDomain(actor) }}
</p> </p>
<div <div

View file

@ -147,12 +147,7 @@ import RelayMixin from "../../mixins/relay";
import { RELAY_FOLLOWINGS } from "@/graphql/admin"; import { RELAY_FOLLOWINGS } from "@/graphql/admin";
import { Paginate } from "@/types/paginate"; import { Paginate } from "@/types/paginate";
import RouteName from "@/router/name"; import RouteName from "@/router/name";
import { import { ApolloCache, FetchResult, Reference } from "@apollo/client/core";
ApolloCache,
FetchResult,
InMemoryCache,
Reference,
} from "@apollo/client/core";
import gql from "graphql-tag"; import gql from "graphql-tag";
const FOLLOWINGS_PER_PAGE = 10; const FOLLOWINGS_PER_PAGE = 10;
@ -221,7 +216,10 @@ export default class Followings extends Mixins(RelayMixin) {
variables: { variables: {
address: this.newRelayAddress.trim(), // trim to fix copy and paste domain name spaces and tabs address: this.newRelayAddress.trim(), // trim to fix copy and paste domain name spaces and tabs
}, },
update(cache: ApolloCache<InMemoryCache>, { data }: FetchResult) { update(
cache: ApolloCache<{ relayFollowings: Paginate<IFollower> }>,
{ data }: FetchResult
) {
cache.modify({ cache.modify({
fields: { fields: {
relayFollowings( relayFollowings(
@ -274,12 +272,12 @@ export default class Followings extends Mixins(RelayMixin) {
async removeRelay(follower: IFollower): Promise<void> { async removeRelay(follower: IFollower): Promise<void> {
const address = `${follower.targetActor.preferredUsername}@${follower.targetActor.domain}`; const address = `${follower.targetActor.preferredUsername}@${follower.targetActor.domain}`;
try { try {
await this.$apollo.mutate({ await this.$apollo.mutate<{ removeRelay: IFollower }>({
mutation: REMOVE_RELAY, mutation: REMOVE_RELAY,
variables: { variables: {
address, address,
}, },
update(cache: ApolloCache<InMemoryCache>) { update(cache: ApolloCache<{ removeRelay: IFollower }>) {
cache.modify({ cache.modify({
fields: { fields: {
relayFollowings(existingFollowingRefs, { readField }) { relayFollowings(existingFollowingRefs, { readField }) {

View file

@ -67,7 +67,8 @@
<div v-else>{{ $t("[This comment has been deleted]") }}</div> <div v-else>{{ $t("[This comment has been deleted]") }}</div>
<div class="load-replies" v-if="comment.totalReplies"> <div class="load-replies" v-if="comment.totalReplies">
<p v-if="!showReplies" @click="fetchReplies"> <p v-if="!showReplies" @click="fetchReplies">
<b-icon icon="chevron-down" /><span>{{ <b-icon icon="chevron-down" class="reply-btn" />
<span class="reply-btn">{{
$tc("View a reply", comment.totalReplies, { $tc("View a reply", comment.totalReplies, {
totalReplies: comment.totalReplies, totalReplies: comment.totalReplies,
}) })
@ -77,8 +78,8 @@
v-else-if="comment.totalReplies && showReplies" v-else-if="comment.totalReplies && showReplies"
@click="showReplies = false" @click="showReplies = false"
> >
<b-icon icon="chevron-up" /> <b-icon icon="chevron-up" class="reply-btn" />
<span>{{ $t("Hide replies") }}</span> <span class="reply-btn">{{ $t("Hide replies") }}</span>
</p> </p>
</div> </div>
</div> </div>
@ -465,7 +466,7 @@ a.comment-link {
& > p > span { & > p > span {
font-weight: bold; font-weight: bold;
color: $primary; color: $violet-2;
} }
} }

View file

@ -107,11 +107,7 @@ import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
eventUUID: this.event.uuid, eventUUID: this.event.uuid,
}; };
}, },
update(data) { update: (data) => data.event.comments,
return data.event.comments.map(
(comment: IComment) => new CommentModel(comment)
);
},
skip() { skip() {
return !this.event.uuid; return !this.event.uuid;
}, },

View file

@ -57,7 +57,12 @@
<div v-if="!editMode && !comment.deletedAt" class="text-wrapper"> <div v-if="!editMode && !comment.deletedAt" class="text-wrapper">
<div class="description-content" v-html="comment.text"></div> <div class="description-content" v-html="comment.text"></div>
<p <p
v-if="comment.insertedAt.getTime() !== comment.updatedAt.getTime()" v-if="
comment.insertedAt &&
comment.updatedAt &&
new Date(comment.insertedAt).getTime() !==
new Date(comment.updatedAt).getTime()
"
:title="comment.updatedAt | formatDateTimeString" :title="comment.updatedAt | formatDateTimeString"
> >
{{ {{

View file

@ -13,7 +13,8 @@
:small="true" :small="true"
/> />
</div> </div>
<div class="content"> <div class="content-and-actions">
<div class="list-card-content">
<div class="title-wrapper"> <div class="title-wrapper">
<router-link <router-link
:to="{ :to="{
@ -215,6 +216,7 @@
</b-dropdown> </b-dropdown>
</div> </div>
</div> </div>
</div>
</article> </article>
</template> </template>
@ -351,17 +353,40 @@ article.box {
.list-card { .list-card {
display: flex; display: flex;
align-items: center;
padding: 0 6px; padding: 0 6px;
position: relative;
flex-direction: column;
div.date-component {
align-self: flex-start;
padding: 5px;
position: absolute;
top: 0;
left: 0;
margin-top: 1px;
height: 0;
display: flex;
align-items: flex-end;
margin-bottom: 15px;
margin-left: 0rem;
}
.content-and-actions {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
padding-bottom: 1rem;
.actions { .actions {
padding-right: 7.5px; padding-right: 7.5px;
cursor: pointer; cursor: pointer;
} }
div.content { div.list-card-content {
flex: 1; flex: 1;
padding: 5px; padding: 5px;
min-width: 350px;
.participation-actor span, .participation-actor span,
.participant-stats span { .participant-stats span {
@ -376,35 +401,34 @@ article.box {
div.title-wrapper { div.title-wrapper {
display: flex; display: flex;
align-items: center; align-items: center;
padding-top: 5px;
div.date-component {
flex: 0;
margin-right: 16px;
}
a { a {
text-decoration: none; text-decoration: none;
padding-bottom: 5px;
} }
.title { .title {
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 3;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
font-weight: 400; font-weight: 400;
line-height: 1em; line-height: 1em;
font-size: 1.6em; font-size: 1.4em;
padding-bottom: 5px; padding-bottom: 5px;
margin: auto 0; margin: auto 0;
} }
} }
} }
} }
}
.identity-header { .identity-header {
background: $yellow-2; background: $yellow-2;
display: flex; display: flex;
padding: 5px; padding: 5px;
padding-left: calc(48px + 15px);
figure { figure {
padding-right: 3px; padding-right: 3px;

View file

@ -97,6 +97,10 @@ export default class GroupMemberCard extends Vue {
& > div:last-child { & > div:last-child {
cursor: pointer; cursor: pointer;
} }
.media-content {
overflow: hidden;
}
} }
.identity-header { .identity-header {

View file

@ -56,6 +56,7 @@
tag="a" tag="a"
href="https://mediation.koena.net/framasoft/mobilizon/" href="https://mediation.koena.net/framasoft/mobilizon/"
target="_blank" target="_blank"
rel="noopener"
> >
<img <img
src="/img/koena-a11y.svg" src="/img/koena-a11y.svg"
@ -69,12 +70,18 @@
<search-field @navbar-search="mobileNavbarActive = false" /> <search-field @navbar-search="mobileNavbarActive = false" />
</b-navbar-item> </b-navbar-item>
<b-navbar-dropdown v-if="currentActor.id && currentUser.isLoggedIn" right> <b-navbar-dropdown
v-if="currentActor.id && currentUser.isLoggedIn"
right
collapsible
>
<template <template
slot="label" slot="label"
v-if="currentActor" v-if="currentActor"
class="navbar-dropdown-profile" class="navbar-dropdown-profile"
> >
<div class="identity-wrapper">
<div>
<figure class="image is-32x32" v-if="currentActor.avatar"> <figure class="image is-32x32" v-if="currentActor.avatar">
<img <img
class="is-rounded" class="is-rounded"
@ -83,6 +90,14 @@
/> />
</figure> </figure>
<b-icon v-else icon="account-circle" /> <b-icon v-else icon="account-circle" />
</div>
<div class="media-content is-hidden-desktop">
<span>{{ displayName(currentActor) }}</span>
<span class="has-text-grey-dark" v-if="currentActor.name"
>@{{ currentActor.preferredUsername }}</span
>
</div>
</div>
</template> </template>
<!-- No identities dropdown if no identities --> <!-- No identities dropdown if no identities -->
@ -103,8 +118,8 @@
</div> </div>
<div class="media-content"> <div class="media-content">
<span>{{ identity.displayName() }}</span> <span>{{ displayName(identity) }}</span>
<span class="has-text-grey" v-if="identity.name" <span class="has-text-grey-dark" v-if="identity.name"
>@{{ identity.preferredUsername }}</span >@{{ identity.preferredUsername }}</span
> >
</div> </div>
@ -169,7 +184,7 @@ import {
IDENTITIES, IDENTITIES,
UPDATE_DEFAULT_ACTOR, UPDATE_DEFAULT_ACTOR,
} from "../graphql/actor"; } from "../graphql/actor";
import { IPerson, Person } from "../types/actor"; import { displayName, IPerson, Person } from "../types/actor";
import { CONFIG } from "../graphql/config"; import { CONFIG } from "../graphql/config";
import { IConfig } from "../types/config.model"; import { IConfig } from "../types/config.model";
import { ICurrentUser, IUser } from "../types/current-user.model"; import { ICurrentUser, IUser } from "../types/current-user.model";
@ -227,6 +242,8 @@ export default class NavBar extends Vue {
mobileNavbarActive = false; mobileNavbarActive = false;
displayName = displayName;
@Watch("currentActor") @Watch("currentActor")
async initializeListOfIdentities(): Promise<void> { async initializeListOfIdentities(): Promise<void> {
if (!this.currentUser.isLoggedIn) return; if (!this.currentUser.isLoggedIn) return;
@ -309,7 +326,7 @@ nav {
cursor: pointer; cursor: pointer;
span { span {
display: inherit; display: flex;
} }
&.is-active { &.is-active {
@ -343,5 +360,14 @@ nav {
padding-top: 0.2rem; padding-top: 0.2rem;
} }
} }
.identity-wrapper {
display: flex;
.media-content span {
display: flex;
color: $violet-2;
}
}
} }
</style> </style>

View file

@ -134,7 +134,7 @@ import { addLocalUnconfirmedAnonymousParticipation } from "@/services/AnonymousP
import { EventJoinOptions, ParticipantRole } from "@/types/enums"; import { EventJoinOptions, ParticipantRole } from "@/types/enums";
import RouteName from "@/router/name"; import RouteName from "@/router/name";
import { IParticipant } from "../../types/participant.model"; import { IParticipant } from "../../types/participant.model";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
@Component({ @Component({
apollo: { apollo: {
@ -197,7 +197,7 @@ export default class ParticipationWithoutAccount extends Vue {
locale: this.$i18n.locale, locale: this.$i18n.locale,
}, },
update: ( update: (
store: ApolloCache<InMemoryCache>, store: ApolloCache<{ joinEvent: IParticipant }>,
{ data: updateData }: FetchResult { data: updateData }: FetchResult
) => { ) => {
if (updateData == null) { if (updateData == null) {

View file

@ -188,7 +188,7 @@ export const GROUP_FIELDS_FRAGMENTS = gql`
`; `;
export const FETCH_GROUP = gql` export const FETCH_GROUP = gql`
query ( query FetchGroup(
$name: String! $name: String!
$afterDateTime: DateTime $afterDateTime: DateTime
$beforeDateTime: DateTime $beforeDateTime: DateTime
@ -212,7 +212,7 @@ export const FETCH_GROUP = gql`
`; `;
export const GET_GROUP = gql` export const GET_GROUP = gql`
query ( query GetGroup(
$id: ID! $id: ID!
$afterDateTime: DateTime $afterDateTime: DateTime
$beforeDateTime: DateTime $beforeDateTime: DateTime

View file

@ -31,7 +31,12 @@ export default class EventMixin extends mixins(Vue) {
actorId, actorId,
token, token,
}, },
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{
leaveEvent: IParticipant;
}>,
{ data }: FetchResult
) => {
if (data == null) return; if (data == null) return;
let participation; let participation;

View file

@ -15,6 +15,8 @@ import {
import { MemberRole } from "@/types/enums"; import { MemberRole } from "@/types/enums";
import { Component, Vue } from "vue-property-decorator"; import { Component, Vue } from "vue-property-decorator";
const now = new Date();
@Component({ @Component({
apollo: { apollo: {
group: { group: {
@ -24,7 +26,7 @@ import { Component, Vue } from "vue-property-decorator";
return { return {
name: this.$route.params.preferredUsername, name: this.$route.params.preferredUsername,
beforeDateTime: null, beforeDateTime: null,
afterDateTime: new Date(), afterDateTime: now,
}; };
}, },
skip() { skip() {

View file

@ -128,7 +128,7 @@ import { MOBILIZON_INSTANCE_HOST } from "../../api/_entrypoint";
import RouteName from "../../router/name"; import RouteName from "../../router/name";
import { changeIdentity } from "../../utils/auth"; import { changeIdentity } from "../../utils/auth";
import identityEditionMixin from "../../mixins/identityEdition"; import identityEditionMixin from "../../mixins/identityEdition";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
@Component({ @Component({
apollo: { apollo: {
@ -171,7 +171,7 @@ export default class Register extends mixins(identityEditionMixin) {
mutation: REGISTER_PERSON, mutation: REGISTER_PERSON,
variables: { email: this.email, ...this.identity }, variables: { email: this.email, ...this.identity },
update: ( update: (
store: ApolloCache<InMemoryCache>, store: ApolloCache<{ registerPerson: IPerson }>,
{ data: localData }: FetchResult { data: localData }: FetchResult
) => { ) => {
if (this.userAlreadyActivated) { if (this.userAlreadyActivated) {

View file

@ -289,7 +289,7 @@ import { usernameWithDomain, IActor } from "../../types/actor/actor.model";
import RouteName from "../../router/name"; import RouteName from "../../router/name";
import ActorCard from "../../components/Account/ActorCard.vue"; import ActorCard from "../../components/Account/ActorCard.vue";
import EmptyContent from "../../components/Utils/EmptyContent.vue"; import EmptyContent from "../../components/Utils/EmptyContent.vue";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
import VueRouter from "vue-router"; import VueRouter from "vue-router";
const { isNavigationFailure, NavigationFailureType } = VueRouter; const { isNavigationFailure, NavigationFailureType } = VueRouter;
@ -427,7 +427,10 @@ export default class AdminGroupProfile extends Vue {
variables: { variables: {
id: this.id, id: this.id,
}, },
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{ suspendProfile: { id: string } }>,
{ data }: FetchResult
) => {
if (data == null) return; if (data == null) return;
const profileId = this.id; const profileId = this.id;

View file

@ -272,7 +272,7 @@ import { usernameWithDomain } from "../../types/actor/actor.model";
import RouteName from "../../router/name"; import RouteName from "../../router/name";
import ActorCard from "../../components/Account/ActorCard.vue"; import ActorCard from "../../components/Account/ActorCard.vue";
import EmptyContent from "../../components/Utils/EmptyContent.vue"; import EmptyContent from "../../components/Utils/EmptyContent.vue";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
import VueRouter from "vue-router"; import VueRouter from "vue-router";
import { MemberRole } from "@/types/enums"; import { MemberRole } from "@/types/enums";
const { isNavigationFailure, NavigationFailureType } = VueRouter; const { isNavigationFailure, NavigationFailureType } = VueRouter;
@ -389,7 +389,10 @@ export default class AdminProfile extends Vue {
variables: { variables: {
id: this.id, id: this.id,
}, },
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{ suspendProfile: { id: string } }>,
{ data }: FetchResult
) => {
if (data == null) return; if (data == null) return;
const profileId = this.id; const profileId = this.id;

View file

@ -127,7 +127,6 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { Component, Prop } from "vue-property-decorator"; import { Component, Prop } from "vue-property-decorator";
import { mixins } from "vue-class-component";
import { import {
GET_DISCUSSION, GET_DISCUSSION,
REPLY_TO_DISCUSSION, REPLY_TO_DISCUSSION,
@ -135,21 +134,22 @@ import {
DELETE_DISCUSSION, DELETE_DISCUSSION,
DISCUSSION_COMMENT_CHANGED, DISCUSSION_COMMENT_CHANGED,
} from "@/graphql/discussion"; } from "@/graphql/discussion";
import { IDiscussion, Discussion } from "@/types/discussions"; import { IDiscussion } from "@/types/discussions";
import { Discussion as DiscussionModel } from "@/types/discussions";
import { usernameWithDomain } from "@/types/actor"; import { usernameWithDomain } from "@/types/actor";
import DiscussionComment from "@/components/Discussion/DiscussionComment.vue"; import DiscussionComment from "@/components/Discussion/DiscussionComment.vue";
import { GraphQLError } from "graphql"; import { GraphQLError } from "graphql";
import { DELETE_COMMENT, UPDATE_COMMENT } from "@/graphql/comment"; import { DELETE_COMMENT, UPDATE_COMMENT } from "@/graphql/comment";
import GroupMixin from "@/mixins/group";
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, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
import { mixins } from "vue-class-component";
import GroupMixin from "@/mixins/group";
@Component({ @Component({
apollo: { apollo: {
discussion: { discussion: {
query: GET_DISCUSSION, query: GET_DISCUSSION,
fetchPolicy: "cache-and-network",
variables() { variables() {
return { return {
slug: this.slug, slug: this.slug,
@ -163,12 +163,11 @@ import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
error({ graphQLErrors }) { error({ graphQLErrors }) {
this.handleErrors(graphQLErrors); this.handleErrors(graphQLErrors);
}, },
update: (data) => new Discussion(data.discussion),
subscribeToMore: { subscribeToMore: {
document: DISCUSSION_COMMENT_CHANGED, document: DISCUSSION_COMMENT_CHANGED,
variables() { variables() {
return { return {
slug: this.slug, slug: this.$route.params.slug,
page: this.page, page: this.page,
limit: this.COMMENTS_PER_PAGE, limit: this.COMMENTS_PER_PAGE,
}; };
@ -180,10 +179,10 @@ import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
const previousDiscussion = previousResult.discussion; const previousDiscussion = previousResult.discussion;
const lastComment = const lastComment =
subscriptionData.data.discussionCommentChanged.lastComment; subscriptionData.data.discussionCommentChanged.lastComment;
const canLoadMore = !previousDiscussion.comments.elements.find( this.hasMoreComments = !previousDiscussion.comments.elements.some(
(comment: IComment) => comment.id === lastComment.id (comment: IComment) => comment.id === lastComment.id
); );
if (canLoadMore) { if (this.hasMoreComments) {
return { return {
discussion: { discussion: {
...previousDiscussion, ...previousDiscussion,
@ -219,10 +218,10 @@ import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core";
}; };
}, },
}) })
export default class discussion extends mixins(GroupMixin) { export default class Discussion extends mixins(GroupMixin) {
@Prop({ type: String, required: true }) slug!: string; @Prop({ type: String, required: true }) slug!: string;
discussion: IDiscussion = new Discussion(); discussion: IDiscussion = new DiscussionModel();
newComment = ""; newComment = "";
@ -261,7 +260,10 @@ export default class discussion extends mixins(GroupMixin) {
commentId: comment.id, commentId: comment.id,
text: comment.text, text: comment.text,
}, },
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{ deleteComment: IComment }>,
{ data }: FetchResult
) => {
if (!data || !data.deleteComment) return; if (!data || !data.deleteComment) return;
const discussionData = store.readQuery<{ const discussionData = store.readQuery<{
discussion: IDiscussion; discussion: IDiscussion;
@ -296,7 +298,10 @@ export default class discussion extends mixins(GroupMixin) {
variables: { variables: {
commentId: comment.id, commentId: comment.id,
}, },
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{ deleteComment: IComment }>,
{ data }: FetchResult
) => {
if (!data || !data.deleteComment) return; if (!data || !data.deleteComment) return;
const discussionData = store.readQuery<{ const discussionData = store.readQuery<{
discussion: IDiscussion; discussion: IDiscussion;
@ -343,7 +348,7 @@ export default class discussion extends mixins(GroupMixin) {
async loadMoreComments(): Promise<void> { async loadMoreComments(): Promise<void> {
if (!this.hasMoreComments) return; if (!this.hasMoreComments) return;
this.page += 1; this.page++;
try { try {
await this.$apollo.queries.discussion.fetchMore({ await this.$apollo.queries.discussion.fetchMore({
// New variables // New variables
@ -352,21 +357,38 @@ 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
.map(({ id }) => id)
.includes(this.discussion?.lastComment?.id);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
} }
async updateDiscussion(): Promise<void> { async updateDiscussion(): Promise<void> {
await this.$apollo.mutate({ await this.$apollo.mutate<{ updateDiscussion: IDiscussion }>({
mutation: UPDATE_DISCUSSION, mutation: UPDATE_DISCUSSION,
variables: { variables: {
discussionId: this.discussion.id, discussionId: this.discussion.id,
title: this.newTitle, title: this.newTitle,
}, },
update: ( update: (
store: ApolloCache<InMemoryCache>, store: ApolloCache<{ updateDiscussion: IDiscussion }>,
{ data }: FetchResult<{ updateDiscussion: IDiscussion }> { data }: FetchResult<{ updateDiscussion: IDiscussion }>
) => { ) => {
const discussionData = store.readQuery<{ const discussionData = store.readQuery<{

View file

@ -485,7 +485,7 @@ import RouteName from "../../router/name";
import "intersection-observer"; import "intersection-observer";
import { CONFIG } from "../../graphql/config"; import { CONFIG } from "../../graphql/config";
import { IConfig } from "../../types/config.model"; import { IConfig } from "../../types/config.model";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10; const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10;
@ -684,11 +684,11 @@ export default class EditEvent extends Vue {
const variables = await this.buildVariables(); const variables = await this.buildVariables();
try { try {
const { data } = await this.$apollo.mutate({ const { data } = await this.$apollo.mutate<{ createEvent: IEvent }>({
mutation: CREATE_EVENT, mutation: CREATE_EVENT,
variables, variables,
update: ( update: (
store: ApolloCache<InMemoryCache>, store: ApolloCache<{ createEvent: IEvent }>,
{ data: updatedData }: FetchResult { data: updatedData }: FetchResult
) => this.postCreateOrUpdate(store, updatedData?.createEvent), ) => this.postCreateOrUpdate(store, updatedData?.createEvent),
refetchQueries: ({ data: updatedData }: FetchResult) => refetchQueries: ({ data: updatedData }: FetchResult) =>
@ -703,10 +703,12 @@ export default class EditEvent extends Vue {
position: "is-bottom-right", position: "is-bottom-right",
duration: 5000, duration: 5000,
}); });
if (data?.createEvent) {
await this.$router.push({ await this.$router.push({
name: "Event", name: "Event",
params: { uuid: data.createEvent.uuid }, params: { uuid: data.createEvent.uuid },
}); });
}
} catch (err) { } catch (err) {
this.saving = false; this.saving = false;
console.error(err); console.error(err);
@ -719,11 +721,11 @@ export default class EditEvent extends Vue {
const variables = await this.buildVariables(); const variables = await this.buildVariables();
try { try {
await this.$apollo.mutate({ await this.$apollo.mutate<{ updateEvent: IEvent }>({
mutation: EDIT_EVENT, mutation: EDIT_EVENT,
variables, variables,
update: ( update: (
store: ApolloCache<InMemoryCache>, store: ApolloCache<{ updateEvent: IEvent }>,
{ data: updatedData }: FetchResult { data: updatedData }: FetchResult
) => this.postCreateOrUpdate(store, updatedData?.updateEvent), ) => this.postCreateOrUpdate(store, updatedData?.updateEvent),
refetchQueries: ({ data }: FetchResult) => refetchQueries: ({ data }: FetchResult) =>

View file

@ -315,7 +315,9 @@
> >
{{ physicalAddress.poiInfos.name }} {{ physicalAddress.poiInfos.name }}
</p> </p>
<p>{{ physicalAddress.poiInfos.alternativeName }}</p> <p class="has-text-grey-dark">
{{ physicalAddress.poiInfos.alternativeName }}
</p>
</address> </address>
</div> </div>
<span <span
@ -663,7 +665,7 @@ import EventBanner from "../../components/Event/EventBanner.vue";
import ActorCard from "../../components/Account/ActorCard.vue"; import ActorCard from "../../components/Account/ActorCard.vue";
import PopoverActorCard from "../../components/Account/PopoverActorCard.vue"; import PopoverActorCard from "../../components/Account/PopoverActorCard.vue";
import { IParticipant } from "../../types/participant.model"; import { IParticipant } from "../../types/participant.model";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
// noinspection TypeScriptValidateTypes // noinspection TypeScriptValidateTypes
@Component({ @Component({
@ -1001,7 +1003,12 @@ export default class Event extends EventMixin {
actorId: identity.id, actorId: identity.id,
message, message,
}, },
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{
joinEvent: IParticipant;
}>,
{ data }: FetchResult
) => {
if (data == null) return; if (data == null) return;
const participationCachedData = store.readQuery<{ person: IPerson }>({ const participationCachedData = store.readQuery<{ person: IPerson }>({
@ -1419,7 +1426,6 @@ div.sidebar {
} }
:not(.addressDescription) { :not(.addressDescription) {
color: rgba(46, 62, 72, 0.6);
flex: 1; flex: 1;
min-width: 100%; min-width: 100%;
} }

View file

@ -41,6 +41,7 @@
v-if="isCurrentActorAGroupModerator" v-if="isCurrentActorAGroupModerator"
:to="{ :to="{
name: RouteName.CREATE_EVENT, name: RouteName.CREATE_EVENT,
query: { actorId: group.id },
}" }"
class="button is-primary" class="button is-primary"
>{{ $t("+ Create an event") }}</router-link >{{ $t("+ Create an event") }}</router-link
@ -88,17 +89,16 @@ import { mixins } from "vue-class-component";
import RouteName from "@/router/name"; import RouteName from "@/router/name";
import Subtitle from "@/components/Utils/Subtitle.vue"; import Subtitle from "@/components/Utils/Subtitle.vue";
import EventListViewCard from "@/components/Event/EventListViewCard.vue"; import EventListViewCard from "@/components/Event/EventListViewCard.vue";
import { CURRENT_ACTOR_CLIENT, PERSON_MEMBERSHIPS } from "@/graphql/actor"; import { PERSON_MEMBERSHIPS } from "@/graphql/actor";
import GroupMixin from "@/mixins/group"; import GroupMixin from "@/mixins/group";
import { IMember } from "@/types/actor/member.model"; import { IMember } from "@/types/actor/member.model";
import { FETCH_GROUP_EVENTS } from "@/graphql/event"; import { FETCH_GROUP_EVENTS } from "@/graphql/event";
import { IGroup, IPerson, usernameWithDomain } from "../../types/actor"; import { usernameWithDomain } from "../../types/actor";
const EVENTS_PAGE_LIMIT = 10; const EVENTS_PAGE_LIMIT = 10;
@Component({ @Component({
apollo: { apollo: {
currentActor: CURRENT_ACTOR_CLIENT,
memberships: { memberships: {
query: PERSON_MEMBERSHIPS, query: PERSON_MEMBERSHIPS,
fetchPolicy: "cache-and-network", fetchPolicy: "cache-and-network",
@ -141,12 +141,8 @@ const EVENTS_PAGE_LIMIT = 10;
}, },
}) })
export default class GroupEvents extends mixins(GroupMixin) { export default class GroupEvents extends mixins(GroupMixin) {
group!: IGroup;
memberships!: IMember[]; memberships!: IMember[];
currentActor!: IPerson;
eventsPage = 1; eventsPage = 1;
usernameWithDomain = usernameWithDomain; usernameWithDomain = usernameWithDomain;

View file

@ -67,7 +67,7 @@
</subtitle> </subtitle>
<transition-group name="list" tag="p"> <transition-group name="list" tag="p">
<div v-for="month in monthlyPastParticipations" :key="month[0]"> <div v-for="month in monthlyPastParticipations" :key="month[0]">
<span>{{ month[0] }}</span> <span class="past-month">{{ month[0] }}</span>
<EventListCard <EventListCard
v-for="participation in month[1]" v-for="participation in month[1]"
:key="participation.id" :key="participation.id"
@ -304,8 +304,24 @@ main > .container {
} }
section { section {
.upcoming-month { .upcoming-month,
.past-month {
text-transform: capitalize; text-transform: capitalize;
display: inline-block;
position: relative;
font-size: 1.3rem;
&::after {
background: $orange-3;
position: absolute;
left: 0;
right: 0;
top: 100%;
content: "";
width: calc(100% + 30px);
height: 3px;
max-width: 150px;
}
} }
} }

View file

@ -608,7 +608,7 @@ export default class Home extends Vue {
main > div > .container { main > div > .container {
background: $white; background: $white;
padding: 1rem 1.5rem 3rem; padding: 1rem 0.5rem 3rem;
} }
.search-autocomplete { .search-autocomplete {

View file

@ -302,7 +302,7 @@ import { IComment } from "@/types/comment.model";
import { ActorType, ReportStatusEnum } from "@/types/enums"; import { ActorType, ReportStatusEnum } from "@/types/enums";
import RouteName from "../../router/name"; import RouteName from "../../router/name";
import { GraphQLError } from "graphql"; import { GraphQLError } from "graphql";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
@Component({ @Component({
apollo: { apollo: {
@ -360,7 +360,10 @@ export default class Report extends Vue {
reportId: this.report.id, reportId: this.report.id,
content: this.noteContent, content: this.noteContent,
}, },
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{ createReportNote: IReportNote }>,
{ data }: FetchResult
) => {
if (data == null) return; if (data == null) return;
const cachedData = store.readQuery<{ report: IReport }>({ const cachedData = store.readQuery<{ report: IReport }>({
query: REPORT, query: REPORT,
@ -460,13 +463,16 @@ export default class Report extends Vue {
async updateReport(status: ReportStatusEnum): Promise<void> { async updateReport(status: ReportStatusEnum): Promise<void> {
try { try {
await this.$apollo.mutate({ await this.$apollo.mutate<{ updateReportStatus: IReport }>({
mutation: UPDATE_REPORT, mutation: UPDATE_REPORT,
variables: { variables: {
reportId: this.report.id, reportId: this.report.id,
status, status,
}, },
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{ updateReportStatus: IReport }>,
{ data }: FetchResult
) => {
if (data == null) return; if (data == null) return;
const reportCachedData = store.readQuery<{ report: IReport }>({ const reportCachedData = store.readQuery<{ report: IReport }>({
query: REPORT, query: REPORT,

View file

@ -15,12 +15,12 @@
>{{ post.attributedTo.name }}</router-link >{{ post.attributedTo.name }}</router-link
> >
</i18n> </i18n>
<p class="published" v-if="!post.draft"> <p class="published has-text-grey-dark" v-if="!post.draft">
{{ post.publishAt | formatDateTimeString }} {{ post.publishAt | formatDateTimeString }}
</p> </p>
<small <small
v-if="post.visibility === PostVisibility.PRIVATE" v-if="post.visibility === PostVisibility.PRIVATE"
class="has-text-grey" class="has-text-grey-dark"
> >
<b-icon icon="lock" size="is-small" /> <b-icon icon="lock" size="is-small" />
{{ {{
@ -68,7 +68,7 @@ import { CURRENT_ACTOR_CLIENT, PERSON_MEMBERSHIPS } from "../../graphql/actor";
import { FETCH_POST } from "../../graphql/post"; import { FETCH_POST } from "../../graphql/post";
import { IPost } from "../../types/post.model"; import { IPost } from "../../types/post.model";
import { IPerson, usernameWithDomain } from "../../types/actor"; import { usernameWithDomain } from "../../types/actor";
import RouteName from "../../router/name"; import RouteName from "../../router/name";
import Tag from "../../components/Tag.vue"; import Tag from "../../components/Tag.vue";
@ -126,8 +126,6 @@ export default class Post extends mixins(GroupMixin) {
memberships!: IMember[]; memberships!: IMember[];
currentActor!: IPerson;
RouteName = RouteName; RouteName = RouteName;
usernameWithDomain = usernameWithDomain; usernameWithDomain = usernameWithDomain;
@ -171,7 +169,6 @@ article {
.published { .published {
margin-top: 1rem; margin-top: 1rem;
color: rgba(0, 0, 0, 0.5);
} }
&::after { &::after {

View file

@ -249,7 +249,7 @@ import { CONFIG } from "../../graphql/config";
import { IConfig } from "../../types/config.model"; import { IConfig } from "../../types/config.model";
import ResourceMixin from "../../mixins/resource"; import ResourceMixin from "../../mixins/resource";
import ResourceSelector from "../../components/Resource/ResourceSelector.vue"; import ResourceSelector from "../../components/Resource/ResourceSelector.vue";
import { ApolloCache, FetchResult, InMemoryCache } from "@apollo/client/core"; import { ApolloCache, FetchResult } from "@apollo/client/core";
@Component({ @Component({
components: { FolderItem, ResourceItem, Draggable, ResourceSelector }, components: { FolderItem, ResourceItem, Draggable, ResourceSelector },
@ -560,7 +560,10 @@ export default class Resources extends Mixins(ResourceMixin) {
path: resource.path, path: resource.path,
}, },
refetchQueries: () => this.postRefreshQueries(), refetchQueries: () => this.postRefreshQueries(),
update: (store: ApolloCache<InMemoryCache>, { data }: FetchResult) => { update: (
store: ApolloCache<{ updateResource: IResource }>,
{ data }: FetchResult
) => {
if (!data || data.updateResource == null || parentPath == null) if (!data || data.updateResource == null || parentPath == null)
return; return;
if (!this.resource.actor) return; if (!this.resource.actor) return;

View file

@ -1,5 +1,5 @@
import Vue from "vue"; import Vue from "vue";
import VueApollo from "vue-apollo"; import VueApollo from "@vue/apollo-option";
import { onError } from "@apollo/client/link/error"; import { onError } from "@apollo/client/link/error";
import { createLink } from "apollo-absinthe-upload-link"; import { createLink } from "apollo-absinthe-upload-link";
import { import {

View file

@ -6,7 +6,7 @@ import {
MockApolloClient, MockApolloClient,
RequestHandler, RequestHandler,
} from "mock-apollo-client"; } from "mock-apollo-client";
import VueApollo from "vue-apollo"; import VueApollo from "@vue/apollo-option";
import { import {
COMMENTS_THREADS_WITH_REPLIES, COMMENTS_THREADS_WITH_REPLIES,
CREATE_COMMENT_FROM_EVENT, CREATE_COMMENT_FROM_EVENT,

View file

@ -10,7 +10,7 @@ import {
RequestHandler, RequestHandler,
} from "mock-apollo-client"; } from "mock-apollo-client";
import { CONFIG } from "@/graphql/config"; import { CONFIG } from "@/graphql/config";
import VueApollo from "vue-apollo"; import VueApollo from "@vue/apollo-option";
import { configMock } from "../../mocks/config"; import { configMock } from "../../mocks/config";
import { InMemoryCache } from "@apollo/client/cache"; import { InMemoryCache } from "@apollo/client/cache";
import { defaultResolvers } from "../../common"; import { defaultResolvers } from "../../common";

View file

@ -14,7 +14,7 @@ import {
RequestHandler, RequestHandler,
} from "mock-apollo-client"; } from "mock-apollo-client";
import { CONFIG } from "@/graphql/config"; import { CONFIG } from "@/graphql/config";
import VueApollo from "vue-apollo"; import VueApollo from "@vue/apollo-option";
import { FETCH_EVENT_BASIC, JOIN_EVENT } from "@/graphql/event"; import { FETCH_EVENT_BASIC, JOIN_EVENT } from "@/graphql/event";
import { IEvent } from "@/types/event.model"; import { IEvent } from "@/types/event.model";
import { i18n } from "@/utils/i18n"; import { i18n } from "@/utils/i18n";

View file

@ -3,7 +3,7 @@ import PasswordReset from "@/views/User/PasswordReset.vue";
import Buefy from "buefy"; import Buefy from "buefy";
import { createMockClient, RequestHandler } from "mock-apollo-client"; import { createMockClient, RequestHandler } from "mock-apollo-client";
import { RESET_PASSWORD } from "@/graphql/auth"; import { RESET_PASSWORD } from "@/graphql/auth";
import VueApollo from "vue-apollo"; import VueApollo from "@vue/apollo-option";
import { resetPasswordResponseMock } from "../../mocks/auth"; import { resetPasswordResponseMock } from "../../mocks/auth";
import RouteName from "@/router/name"; import RouteName from "@/router/name";
import flushPromises from "flush-promises"; import flushPromises from "flush-promises";

View file

@ -6,7 +6,7 @@ import {
MockApolloClient, MockApolloClient,
RequestHandler, RequestHandler,
} from "mock-apollo-client"; } from "mock-apollo-client";
import VueApollo from "vue-apollo"; import VueApollo from "@vue/apollo-option";
import buildCurrentUserResolver from "@/apollo/user"; import buildCurrentUserResolver from "@/apollo/user";
import { configMock } from "../../mocks/config"; import { configMock } from "../../mocks/config";
import { i18n } from "@/utils/i18n"; import { i18n } from "@/utils/i18n";

View file

@ -5,7 +5,7 @@ import {
MockApolloClient, MockApolloClient,
RequestHandler, RequestHandler,
} from "mock-apollo-client"; } from "mock-apollo-client";
import VueApollo from "vue-apollo"; import VueApollo from "@vue/apollo-option";
import { CONFIG } from "@/graphql/config"; import { CONFIG } from "@/graphql/config";
import { USER_SETTINGS } from "@/graphql/user"; import { USER_SETTINGS } from "@/graphql/user";
import buildCurrentUserResolver from "@/apollo/user"; import buildCurrentUserResolver from "@/apollo/user";

View file

@ -2313,6 +2313,13 @@
"@typescript-eslint/types" "4.26.0" "@typescript-eslint/types" "4.26.0"
eslint-visitor-keys "^2.0.0" eslint-visitor-keys "^2.0.0"
"@vue/apollo-option@^4.0.0-alpha.11":
version "4.0.0-alpha.11"
resolved "https://registry.yarnpkg.com/@vue/apollo-option/-/apollo-option-4.0.0-alpha.11.tgz#b4ecac2d1ac40271cb7f20683fb8e4c85974329a"
integrity sha512-IU458Y2cH/eo3RYXyoEoozyRxEgUz/BLC96DQAQKiEc7hFkE6I0g/VZu4tVIP0Od1/ivezdGaAPEVPA2AxE1ug==
dependencies:
throttle-debounce "^2.3.0"
"@vue/babel-helper-vue-jsx-merge-props@^1.2.1": "@vue/babel-helper-vue-jsx-merge-props@^1.2.1":
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.2.1.tgz#31624a7a505fb14da1d58023725a4c5f270e6a81" resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.2.1.tgz#31624a7a505fb14da1d58023725a4c5f270e6a81"
@ -10642,7 +10649,7 @@ throat@^5.0.0:
resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
throttle-debounce@^2.1.0: throttle-debounce@^2.3.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2" resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2"
integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ== integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==
@ -11131,15 +11138,6 @@ verror@1.10.0:
core-util-is "1.0.2" core-util-is "1.0.2"
extsprintf "^1.2.0" extsprintf "^1.2.0"
vue-apollo@^3.0.3:
version "3.0.7"
resolved "https://registry.yarnpkg.com/vue-apollo/-/vue-apollo-3.0.7.tgz#97a031d45641faa4888a6d5a7f71c40834359704"
integrity sha512-EUfIn4cJmoflnDJiSNP8gH4fofIEzd0I2AWnd9nhHB8mddmzIfgSNjIRihDcRB10wypYG1OG0GcU335CFgZRfA==
dependencies:
chalk "^2.4.2"
serialize-javascript "^4.0.0"
throttle-debounce "^2.1.0"
vue-class-component@^7.2.3: vue-class-component@^7.2.3:
version "7.2.6" version "7.2.6"
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.2.6.tgz#8471e037b8e4762f5a464686e19e5afc708502e4" resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.2.6.tgz#8471e037b8e4762f5a464686e19e5afc708502e4"

View file

@ -162,9 +162,7 @@ defmodule Mobilizon.Mixfile do
{:sweet_xml, "~> 0.6.6"}, {:sweet_xml, "~> 0.6.6"},
{:web_push_encryption, {:web_push_encryption,
git: "https://github.com/tcitworld/elixir-web-push-encryption", branch: "otp-24"}, git: "https://github.com/tcitworld/elixir-web-push-encryption", branch: "otp-24"},
{:eblurhash, {:eblurhash, "~> 1.2"},
git: "https://github.com/zotonic/eblurhash",
ref: "04a0b76eadf4de1be17726f39b6313b88708fd12"},
# Dev and test dependencies # Dev and test dependencies
{:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]}, {:phoenix_live_reload, "~> 1.2", only: [:dev, :e2e]},
{:ex_machina, "~> 2.3", only: [:dev, :test]}, {:ex_machina, "~> 2.3", only: [:dev, :test]},

View file

@ -25,7 +25,7 @@
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"}, "earmark": {:hex, :earmark, "1.4.15", "2c7f924bf495ec1f65bd144b355d0949a05a254d0ec561740308a54946a67888", [:mix], [{:earmark_parser, ">= 1.4.13", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "3b1209b85bc9f3586f370f7c363f6533788fb4e51db23aa79565875e7f9999ee"},
"earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"}, "earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"},
"eblurhash": {:git, "https://github.com/zotonic/eblurhash", "04a0b76eadf4de1be17726f39b6313b88708fd12", [ref: "04a0b76eadf4de1be17726f39b6313b88708fd12"]}, "eblurhash": {:hex, :eblurhash, "1.2.0", "ff461979542fcb1bfd428aaba6ee56e544975f6d657aa3dfcf3e314b1d1c2517", [:rebar3], [], "hexpm", "8fa6b740f1630adc0a3e425dbbb4ff92d036e62eb973e7a06676226137a10aa7"},
"ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"}, "ecto": {:hex, :ecto, "3.6.2", "efdf52acfc4ce29249bab5417415bd50abd62db7b0603b8bab0d7b996548c2bc", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "efad6dfb04e6f986b8a3047822b0f826d9affe8e4ebdd2aeedbfcb14fd48884e"},
"ecto_autoslug_field": {:hex, :ecto_autoslug_field, "2.0.1", "2177c1c253f6dd3efd4b56d1cb76104d0a6ef044c6b9a7a0ad6d32665c4111e5", [:mix], [{:ecto, ">= 2.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.2.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm", "a3cc73211f2e75b89a03332183812ebe1ac08be2e25a1df5aa3d1422f92c45c3"}, "ecto_autoslug_field": {:hex, :ecto_autoslug_field, "2.0.1", "2177c1c253f6dd3efd4b56d1cb76104d0a6ef044c6b9a7a0ad6d32665c4111e5", [:mix], [{:ecto, ">= 2.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:slugger, ">= 0.2.0", [hex: :slugger, repo: "hexpm", optional: false]}], "hexpm", "a3cc73211f2e75b89a03332183812ebe1ac08be2e25a1df5aa3d1422f92c45c3"},
"ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"}, "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},