Refactor media upload
Use Upload Media logic from Pleroma Backend changes for picture upload Move AS <-> Model conversion to separate module Front changes Downgrade apollo-client: https://github.com/Akryum/vue-apollo/issues/577 Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -91,6 +91,7 @@ export default class App extends Vue {
|
||||
@import "~buefy/src/scss/components/form";
|
||||
@import "~buefy/src/scss/components/modal";
|
||||
@import "~buefy/src/scss/components/tag";
|
||||
@import "~buefy/src/scss/components/upload";
|
||||
@import "~buefy/src/scss/utils/_all";
|
||||
|
||||
.router-enter-active,
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
<li v-for="identity in identities" :key="identity.id">
|
||||
<div class="media identity" v-bind:class="{ 'is-current-identity': isCurrentIdentity(identity) }">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48">
|
||||
<img class="is-rounded" :src="identity.avatarUrl">
|
||||
<figure class="image is-48x48" v-if="identity.avatar">
|
||||
<img class="is-rounded" :src="identity.avatar.url">
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<router-link class="card" :to="{ name: 'Event', params: { uuid: event.uuid } }">
|
||||
<div class="card-image" v-if="!event.image">
|
||||
<figure class="image is-16by9">
|
||||
<div class="tag-container">
|
||||
<div class="tag-container" v-if="event.tags">
|
||||
<b-tag v-for="tag in event.tags.slice(0, 3)" :key="tag.slug" type="is-secondary">{{ tag.title }}</b-tag>
|
||||
</div>
|
||||
<img src="https://picsum.photos/g/400/225/?random">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="card">
|
||||
<div class="card-image" v-if="!group.bannerUrl">
|
||||
<div class="card-image" v-if="!group.banner">
|
||||
<figure class="image is-4by3">
|
||||
<img src="https://picsum.photos/g/400/200/">
|
||||
</figure>
|
||||
|
||||
@@ -40,8 +40,8 @@
|
||||
v-if="currentUser.isLoggedIn && loggedPerson"
|
||||
:to="{ name: 'MyAccount' }"
|
||||
>
|
||||
<figure class="image is-24x24">
|
||||
<img :src="loggedPerson.avatarUrl">
|
||||
<figure class="image is-24x24" v-if="loggedPerson.avatar">
|
||||
<img :src="loggedPerson.avatar.url">
|
||||
</figure>
|
||||
<span>{{ loggedPerson.preferredUsername }}</span>
|
||||
</router-link>
|
||||
|
||||
29
js/src/components/PictureUpload.vue
Normal file
29
js/src/components/PictureUpload.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<b-field class="file">
|
||||
<b-upload v-model="pictureFile" @input="onFileChanged">
|
||||
<a class="button is-primary">
|
||||
<b-icon icon="upload"></b-icon>
|
||||
<span>Click to upload</span>
|
||||
</a>
|
||||
</b-upload>
|
||||
<span class="file-name" v-if="pictureFile">
|
||||
{{ pictureFile.name }}
|
||||
</span>
|
||||
</b-field>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import { IPictureUpload } from '@/types/picture.model';
|
||||
|
||||
@Component
|
||||
export default class PictureUpload extends Vue {
|
||||
picture!: IPictureUpload;
|
||||
pictureFile: File|null = null;
|
||||
|
||||
onFileChanged(file: File) {
|
||||
this.picture = { file, name: file.name, alt: '' };
|
||||
this.$emit('change', this.picture);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -10,8 +10,12 @@ query($name:String!) {
|
||||
summary,
|
||||
preferredUsername,
|
||||
suspended,
|
||||
avatarUrl,
|
||||
bannerUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
banner {
|
||||
url
|
||||
},
|
||||
feedTokens {
|
||||
token
|
||||
},
|
||||
@@ -28,7 +32,9 @@ export const LOGGED_PERSON = gql`
|
||||
query {
|
||||
loggedPerson {
|
||||
id,
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
}
|
||||
}`;
|
||||
@@ -37,7 +43,9 @@ export const LOGGED_PERSON_WITH_GOING_TO_EVENTS = gql`
|
||||
query {
|
||||
loggedPerson {
|
||||
id,
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
goingToEvents {
|
||||
uuid,
|
||||
@@ -56,7 +64,9 @@ query {
|
||||
export const IDENTITIES = gql`
|
||||
query {
|
||||
identities {
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
name
|
||||
}
|
||||
@@ -72,7 +82,9 @@ mutation CreatePerson($preferredUsername: String!) {
|
||||
preferredUsername,
|
||||
name,
|
||||
summary,
|
||||
avatarUrl
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -91,7 +103,9 @@ mutation ($preferredUsername: String!, $name: String!, $summary: String!, $email
|
||||
preferredUsername,
|
||||
name,
|
||||
summary,
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -106,8 +120,12 @@ query($name:String!) {
|
||||
summary,
|
||||
preferredUsername,
|
||||
suspended,
|
||||
avatarUrl,
|
||||
bannerUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
banner {
|
||||
url
|
||||
}
|
||||
organizedEvents {
|
||||
uuid,
|
||||
title,
|
||||
|
||||
@@ -4,7 +4,9 @@ const participantQuery = `
|
||||
role,
|
||||
actor {
|
||||
preferredUsername,
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
name,
|
||||
id
|
||||
}
|
||||
@@ -24,8 +26,10 @@ export const FETCH_EVENT = gql`
|
||||
endsOn,
|
||||
status,
|
||||
visibility,
|
||||
thumbnail,
|
||||
largeImage,
|
||||
picture {
|
||||
id
|
||||
url
|
||||
},
|
||||
publishAt,
|
||||
category,
|
||||
# online_address,
|
||||
@@ -35,19 +39,23 @@ export const FETCH_EVENT = gql`
|
||||
floor,
|
||||
street,
|
||||
locality,
|
||||
postal_code,
|
||||
postalCode,
|
||||
region,
|
||||
country,
|
||||
geom
|
||||
}
|
||||
organizerActor {
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
domain,
|
||||
name,
|
||||
},
|
||||
# attributedTo {
|
||||
# # avatarUrl,
|
||||
# avatar {
|
||||
# url,
|
||||
# }
|
||||
# preferredUsername,
|
||||
# name,
|
||||
# },
|
||||
@@ -66,7 +74,9 @@ export const FETCH_EVENT = gql`
|
||||
description
|
||||
},
|
||||
organizerActor {
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url,
|
||||
},
|
||||
preferredUsername,
|
||||
domain,
|
||||
name,
|
||||
@@ -89,8 +99,10 @@ export const FETCH_EVENTS = gql`
|
||||
endsOn,
|
||||
status,
|
||||
visibility,
|
||||
thumbnail,
|
||||
largeImage,
|
||||
picture {
|
||||
id
|
||||
url
|
||||
},
|
||||
publishAt,
|
||||
# online_address,
|
||||
# phone_address,
|
||||
@@ -99,12 +111,16 @@ export const FETCH_EVENTS = gql`
|
||||
locality
|
||||
}
|
||||
organizerActor {
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
name,
|
||||
},
|
||||
attributedTo {
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
name,
|
||||
},
|
||||
@@ -124,20 +140,31 @@ export const CREATE_EVENT = gql`
|
||||
mutation CreateEvent(
|
||||
$title: String!,
|
||||
$description: String!,
|
||||
$organizerActorId: String!,
|
||||
$organizerActorId: ID!,
|
||||
$category: String!,
|
||||
$beginsOn: DateTime!
|
||||
$beginsOn: DateTime!,
|
||||
$picture_file: Upload,
|
||||
$picture_name: String,
|
||||
) {
|
||||
createEvent(
|
||||
title: $title,
|
||||
description: $description,
|
||||
beginsOn: $beginsOn,
|
||||
organizerActorId: $organizerActorId,
|
||||
category: $category
|
||||
category: $category,
|
||||
picture: {
|
||||
picture: {
|
||||
file: $picture_file,
|
||||
name: $picture_name,
|
||||
}
|
||||
}
|
||||
) {
|
||||
id,
|
||||
uuid,
|
||||
title
|
||||
title,
|
||||
picture {
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -4,14 +4,16 @@ export const LOGGED_PERSON = gql`
|
||||
query {
|
||||
loggedPerson {
|
||||
id,
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
}
|
||||
}`;
|
||||
|
||||
export const CREATE_FEED_TOKEN_ACTOR = gql`
|
||||
mutation createFeedToken($actor_id: Int!) {
|
||||
createFeedToken(actor_id: $actor_id) {
|
||||
createFeedToken(actorId: $actor_id) {
|
||||
token,
|
||||
actor {
|
||||
id
|
||||
|
||||
@@ -23,7 +23,9 @@ query SearchGroups($searchText: String!) {
|
||||
searchGroups(search: $searchText) {
|
||||
total,
|
||||
elements {
|
||||
avatarUrl,
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
domain,
|
||||
preferredUsername,
|
||||
name,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { IPicture } from '@/types/picture.model';
|
||||
|
||||
export interface IActor {
|
||||
id?: string;
|
||||
url: string;
|
||||
@@ -6,13 +8,13 @@ export interface IActor {
|
||||
summary: string;
|
||||
preferredUsername: string;
|
||||
suspended: boolean;
|
||||
avatarUrl: string;
|
||||
bannerUrl: string;
|
||||
avatar: IPicture | null;
|
||||
banner: IPicture | null;
|
||||
}
|
||||
|
||||
export class Actor implements IActor {
|
||||
avatarUrl: string = '';
|
||||
bannerUrl: string = '';
|
||||
avatar: IPicture | null = null;
|
||||
banner: IPicture | null = null;
|
||||
domain: string | null = null;
|
||||
name: string = '';
|
||||
preferredUsername: string = '';
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Actor, IActor } from './actor';
|
||||
import { IAddress } from '@/types/address.model';
|
||||
import { ITag } from '@/types/tag.model';
|
||||
import { IAbstractPicture, IPicture } from '@/types/picture.model';
|
||||
|
||||
export enum EventStatus {
|
||||
TENTATIVE,
|
||||
@@ -62,8 +64,7 @@ export interface IEvent {
|
||||
|
||||
joinOptions: EventJoinOptions;
|
||||
|
||||
thumbnail: string;
|
||||
largeImage: string;
|
||||
picture: IAbstractPicture|null;
|
||||
|
||||
organizerActor: IActor;
|
||||
attributedTo: IActor;
|
||||
@@ -84,12 +85,10 @@ export class EventModel implements IEvent {
|
||||
description: string = '';
|
||||
endsOn: Date = new Date();
|
||||
joinOptions: EventJoinOptions = EventJoinOptions.FREE;
|
||||
largeImage: string = '';
|
||||
local: boolean = true;
|
||||
participants: IParticipant[] = [];
|
||||
publishAt: Date = new Date();
|
||||
status: EventStatus = EventStatus.CONFIRMED;
|
||||
thumbnail: string = '';
|
||||
title: string = '';
|
||||
url: string = '';
|
||||
uuid: string = '';
|
||||
@@ -99,4 +98,5 @@ export class EventModel implements IEvent {
|
||||
relatedEvents: IEvent[] = [];
|
||||
onlineAddress: string = '';
|
||||
phoneAddress: string = '';
|
||||
picture: IAbstractPicture|null = null;
|
||||
}
|
||||
|
||||
16
js/src/types/picture.model.ts
Normal file
16
js/src/types/picture.model.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export interface IAbstractPicture {
|
||||
name;
|
||||
alt;
|
||||
}
|
||||
|
||||
export interface IPicture {
|
||||
url;
|
||||
name;
|
||||
alt;
|
||||
}
|
||||
|
||||
export interface IPictureUpload {
|
||||
file: File;
|
||||
name: String;
|
||||
alt: String|null;
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
<section class="container">
|
||||
<div v-if="person">
|
||||
<div class="header">
|
||||
<figure v-if="person.bannerUrl" class="image is-3by1">
|
||||
<img :src="person.bannerUrl" alt="banner">
|
||||
<figure v-if="person.banner" class="image is-3by1">
|
||||
<img :src="person.banner.url" alt="banner">
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<section class="container">
|
||||
<div v-if="person">
|
||||
<div class="card-image" v-if="person.bannerUrl">
|
||||
<div class="card-image" v-if="person.banner">
|
||||
<figure class="image">
|
||||
<img :src="person.bannerUrl">
|
||||
<img :src="person.banner.url">
|
||||
</figure>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48">
|
||||
<img :src="person.avatarUrl">
|
||||
<figure class="image is-48x48" v-if="person.avatar">
|
||||
<img :src="person.avatar.url">
|
||||
</figure>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
@@ -18,7 +18,6 @@
|
||||
<p class="subtitle">@{{ person.preferredUsername }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<vue-simple-markdown :source="person.summary"></vue-simple-markdown>
|
||||
</div>
|
||||
@@ -58,7 +57,7 @@
|
||||
</a>
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
<a class="button" v-else-if="loggedPerson" @click="createToken">
|
||||
<a class="button" v-if="loggedPerson.id === person.id" @click="createToken">
|
||||
<translate>Create token</translate>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -81,7 +81,7 @@ export default class Register extends Vue {
|
||||
@Prop({ type: String, required: true }) email!: string;
|
||||
@Prop({ type: Boolean, required: false, default: false }) userAlreadyActivated!: boolean;
|
||||
|
||||
host: string = MOBILIZON_INSTANCE_HOST;
|
||||
host?: string = MOBILIZON_INSTANCE_HOST;
|
||||
|
||||
person: IPerson = {
|
||||
preferredUsername: '',
|
||||
@@ -90,8 +90,8 @@ export default class Register extends Vue {
|
||||
id: '',
|
||||
url: '',
|
||||
suspended: false,
|
||||
avatarUrl: '',
|
||||
bannerUrl: '',
|
||||
avatar: null,
|
||||
banner: null,
|
||||
domain: null,
|
||||
feedTokens: [],
|
||||
goingToEvents: [],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<section>
|
||||
<section class="container">
|
||||
<h1 class="title">
|
||||
<translate>Create a new event</translate>
|
||||
</h1>
|
||||
@@ -22,6 +22,8 @@
|
||||
</b-select>
|
||||
</b-field>
|
||||
|
||||
<picture-upload @change="handlePictureUploadChange" />
|
||||
|
||||
<button class="button is-primary">
|
||||
<translate>Create my event</translate>
|
||||
</button>
|
||||
@@ -41,8 +43,11 @@ import {
|
||||
} from '@/types/event.model';
|
||||
import { LOGGED_PERSON } from '@/graphql/actor';
|
||||
import { IPerson, Person } from '@/types/actor';
|
||||
import PictureUpload from '@/components/PictureUpload.vue';
|
||||
import { IPictureUpload } from '@/types/picture.model';
|
||||
|
||||
@Component({
|
||||
components: { PictureUpload },
|
||||
apollo: {
|
||||
loggedPerson: {
|
||||
query: LOGGED_PERSON,
|
||||
@@ -55,6 +60,8 @@ export default class CreateEvent extends Vue {
|
||||
loggedPerson: IPerson = new Person();
|
||||
categories: string[] = Object.keys(Category);
|
||||
event: IEvent = new EventModel();
|
||||
pictureFile?: File;
|
||||
pictureName?: String;
|
||||
|
||||
createEvent(e: Event) {
|
||||
e.preventDefault();
|
||||
@@ -62,15 +69,18 @@ export default class CreateEvent extends Vue {
|
||||
this.event.attributedTo = this.loggedPerson;
|
||||
|
||||
if (this.event.uuid === '') {
|
||||
console.log('event', this.event);
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: CREATE_EVENT,
|
||||
variables: {
|
||||
title: this.event.title,
|
||||
description: this.event.description,
|
||||
beginsOn: this.event.beginsOn,
|
||||
beginsOn: this.event.beginsOn.toISOString(),
|
||||
category: this.event.category,
|
||||
organizerActorId: this.event.organizerActor.id,
|
||||
picture_file: this.pictureFile,
|
||||
picture_name: this.pictureName,
|
||||
},
|
||||
})
|
||||
.then(data => {
|
||||
@@ -100,6 +110,12 @@ export default class CreateEvent extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
handlePictureUploadChange(picture: IPictureUpload) {
|
||||
console.log('picture upload change', picture);
|
||||
this.pictureFile = picture.file;
|
||||
this.pictureName = picture.name;
|
||||
}
|
||||
|
||||
// getAddressData(addressData) {
|
||||
// if (addressData !== null) {
|
||||
// this.event.address = {
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
<b-loading :active.sync="$apollo.loading"></b-loading>
|
||||
<div v-if="event">
|
||||
<div class="header-picture container">
|
||||
<figure class="image is-3by1">
|
||||
<figure class="image is-3by1" v-if="event.picture">
|
||||
<img :src="event.picture.url">
|
||||
</figure>
|
||||
<figure class="image is-3by1" v-else>
|
||||
<img src="https://picsum.photos/600/200/">
|
||||
</figure>
|
||||
</div>
|
||||
@@ -95,10 +98,10 @@
|
||||
<translate
|
||||
:translate-params="{name: event.organizerActor.name ? event.organizerActor.name : event.organizerActor.preferredUsername}"
|
||||
v-if="event.organizerActor">By %{ name }</translate>
|
||||
<figure v-if="event.organizerActor.avatarUrl" class="image is-48x48">
|
||||
<figure v-if="event.organizerActor.avatar" class="image is-48x48">
|
||||
<img
|
||||
class="is-rounded"
|
||||
:src="event.organizerActor.avatarUrl"
|
||||
:src="event.organizerActor.avatar.url"
|
||||
:alt="$gettextInterpolate('%{actor}\'s avatar', {actor: event.organizerActor.preferredUsername})" />
|
||||
</figure>
|
||||
</router-link>
|
||||
@@ -185,8 +188,8 @@
|
||||
<!-- >-->
|
||||
<!-- <div>-->
|
||||
<!-- <figure>-->
|
||||
<!-- <img v-if="!participant.actor.avatarUrl" src="https://picsum.photos/125/125/">-->
|
||||
<!-- <img v-else :src="participant.actor.avatarUrl">-->
|
||||
<!-- <img v-if="!participant.actor.avatar.url" src="https://picsum.photos/125/125/">-->
|
||||
<!-- <img v-else :src="participant.actor.avatar.url">-->
|
||||
<!-- </figure>-->
|
||||
<!-- <span>{{ participant.actor.preferredUsername }}</span>-->
|
||||
<!-- </div>-->
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<section class="container">
|
||||
<div v-if="group">
|
||||
<div class="card-image" v-if="group.bannerUrl">
|
||||
<div class="card-image" v-if="group.banner.url">
|
||||
<figure class="image">
|
||||
<img :src="group.bannerUrl">
|
||||
<img :src="group.banner.url">
|
||||
</figure>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48">
|
||||
<img :src="group.avatarUrl">
|
||||
<img :src="group.avatar.url">
|
||||
</figure>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
|
||||
Reference in New Issue
Block a user