From 5a3ea38bbfef209bc11d7fc5eb125d9ed2611c1c Mon Sep 17 00:00:00 2001 From: MeiMei <30769358+mei23@users.noreply.github.com> Date: Mon, 20 May 2019 13:34:51 +0900 Subject: [PATCH 01/24] Fix: Delete is not deliver (#4950) * Fix: Delete is not deliver * fix --- src/services/note/delete.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/services/note/delete.ts b/src/services/note/delete.ts index c03c742ee1..95776f7287 100644 --- a/src/services/note/delete.ts +++ b/src/services/note/delete.ts @@ -8,7 +8,6 @@ import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc'; import { User } from '../../models/entities/user'; import { Note } from '../../models/entities/note'; import { Notes, Users, Followings, Instances } from '../../models'; -import { Not } from 'typeorm'; import { notesChart, perUserNotesChart, instanceChart } from '../chart'; /** @@ -38,13 +37,21 @@ export default async function(user: User, note: Note, quiet = false) { if (Users.isLocalUser(user)) { const content = renderActivity(renderDelete(renderTombstone(`${config.url}/notes/${note.id}`), user)); - const followings = await Followings.find({ - followeeId: user.id, - followerHost: Not(null) + const queue: string[] = []; + + const followers = await Followings.find({ + followeeId: note.userId }); - for (const following of followings) { - deliver(user, content, following.followerInbox); + for (const following of followers) { + if (Followings.isRemoteFollower(following)) { + const inbox = following.followerSharedInbox || following.followerInbox; + if (!queue.includes(inbox)) queue.push(inbox); + } + } + + for (const inbox of queue) { + deliver(user as any, content, inbox); } } //#endregion From e7dd5e155d212188de9fbef70e6694b433530559 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 May 2019 21:44:16 +0900 Subject: [PATCH 02/24] Fix bugs Use Not(IsNull()) --- CONTRIBUTING.md | 14 ++++++++++++++ .../users/get-frequently-replied-users.ts | 4 ++-- src/services/chart/charts/classes/drive.ts | 4 ++-- src/services/chart/charts/classes/notes.ts | 4 ++-- .../chart/charts/classes/per-user-following.ts | 6 +++--- src/services/chart/charts/classes/users.ts | 4 ++-- src/tools/clean-remote-files.ts | 4 ++-- 7 files changed, 27 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ace822c63e..b01e5e6dd8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -128,6 +128,20 @@ query.andWhere(new Brackets(qb => { })); ``` +### Not `null` in TypeORM +```ts +const foo = await Foos.findOne({ + bar: Not(null) +}); +``` +のようなクエリ(`bar`が`null`ではない)は期待通りに動作しない。 +次のようにします: +```ts +const foo = await Foos.findOne({ + bar: Not(IsNull()) +}); +``` + ### `null` in SQL SQLを発行する際、パラメータが`null`になる可能性のある場合はSQL文を出し分けなければならない 例えば diff --git a/src/server/api/endpoints/users/get-frequently-replied-users.ts b/src/server/api/endpoints/users/get-frequently-replied-users.ts index 420936c089..24d1bd194c 100644 --- a/src/server/api/endpoints/users/get-frequently-replied-users.ts +++ b/src/server/api/endpoints/users/get-frequently-replied-users.ts @@ -4,7 +4,7 @@ import define from '../../define'; import { maximum } from '../../../../prelude/array'; import { ApiError } from '../../error'; import { getUser } from '../../common/getters'; -import { Not, In } from 'typeorm'; +import { Not, In, IsNull } from 'typeorm'; import { Notes, Users } from '../../../../models'; import { types, bool } from '../../../../misc/schema'; @@ -58,7 +58,7 @@ export default define(meta, async (ps, me) => { const recentNotes = await Notes.find({ where: { userId: user.id, - replyId: Not(null) + replyId: Not(IsNull()) }, order: { id: -1 diff --git a/src/services/chart/charts/classes/drive.ts b/src/services/chart/charts/classes/drive.ts index ae52df19ac..c3bcacb7df 100644 --- a/src/services/chart/charts/classes/drive.ts +++ b/src/services/chart/charts/classes/drive.ts @@ -2,7 +2,7 @@ import autobind from 'autobind-decorator'; import Chart, { Obj, DeepPartial } from '../../core'; import { SchemaType } from '../../../../misc/schema'; import { DriveFiles } from '../../../../models'; -import { Not } from 'typeorm'; +import { Not, IsNull } from 'typeorm'; import { DriveFile } from '../../../../models/entities/drive-file'; import { name, schema } from '../schemas/drive'; @@ -31,7 +31,7 @@ export default class DriveChart extends Chart { protected async fetchActual(): Promise> { const [localCount, remoteCount, localSize, remoteSize] = await Promise.all([ DriveFiles.count({ userHost: null }), - DriveFiles.count({ userHost: Not(null) }), + DriveFiles.count({ userHost: Not(IsNull()) }), DriveFiles.clacDriveUsageOfLocal(), DriveFiles.clacDriveUsageOfRemote() ]); diff --git a/src/services/chart/charts/classes/notes.ts b/src/services/chart/charts/classes/notes.ts index 85ccf000d8..815061c445 100644 --- a/src/services/chart/charts/classes/notes.ts +++ b/src/services/chart/charts/classes/notes.ts @@ -2,7 +2,7 @@ import autobind from 'autobind-decorator'; import Chart, { Obj, DeepPartial } from '../../core'; import { SchemaType } from '../../../../misc/schema'; import { Notes } from '../../../../models'; -import { Not } from 'typeorm'; +import { Not, IsNull } from 'typeorm'; import { Note } from '../../../../models/entities/note'; import { name, schema } from '../schemas/notes'; @@ -29,7 +29,7 @@ export default class NotesChart extends Chart { protected async fetchActual(): Promise> { const [localCount, remoteCount] = await Promise.all([ Notes.count({ userHost: null }), - Notes.count({ userHost: Not(null) }) + Notes.count({ userHost: Not(IsNull()) }) ]); return { diff --git a/src/services/chart/charts/classes/per-user-following.ts b/src/services/chart/charts/classes/per-user-following.ts index f3809a7c94..8295c0cb0d 100644 --- a/src/services/chart/charts/classes/per-user-following.ts +++ b/src/services/chart/charts/classes/per-user-following.ts @@ -2,7 +2,7 @@ import autobind from 'autobind-decorator'; import Chart, { Obj, DeepPartial } from '../../core'; import { SchemaType } from '../../../../misc/schema'; import { Followings, Users } from '../../../../models'; -import { Not } from 'typeorm'; +import { Not, IsNull } from 'typeorm'; import { User } from '../../../../models/entities/user'; import { name, schema } from '../schemas/per-user-following'; @@ -45,8 +45,8 @@ export default class PerUserFollowingChart extends Chart { ] = await Promise.all([ Followings.count({ followerId: group, followeeHost: null }), Followings.count({ followeeId: group, followerHost: null }), - Followings.count({ followerId: group, followeeHost: Not(null) }), - Followings.count({ followeeId: group, followerHost: Not(null) }) + Followings.count({ followerId: group, followeeHost: Not(IsNull()) }), + Followings.count({ followeeId: group, followerHost: Not(IsNull()) }) ]); return { diff --git a/src/services/chart/charts/classes/users.ts b/src/services/chart/charts/classes/users.ts index eec30de8dc..47e4caa1b7 100644 --- a/src/services/chart/charts/classes/users.ts +++ b/src/services/chart/charts/classes/users.ts @@ -2,7 +2,7 @@ import autobind from 'autobind-decorator'; import Chart, { Obj, DeepPartial } from '../../core'; import { SchemaType } from '../../../../misc/schema'; import { Users } from '../../../../models'; -import { Not } from 'typeorm'; +import { Not, IsNull } from 'typeorm'; import { User } from '../../../../models/entities/user'; import { name, schema } from '../schemas/users'; @@ -29,7 +29,7 @@ export default class UsersChart extends Chart { protected async fetchActual(): Promise> { const [localCount, remoteCount] = await Promise.all([ Users.count({ host: null }), - Users.count({ host: Not(null) }) + Users.count({ host: Not(IsNull()) }) ]); return { diff --git a/src/tools/clean-remote-files.ts b/src/tools/clean-remote-files.ts index e722552e14..633a6fc04d 100644 --- a/src/tools/clean-remote-files.ts +++ b/src/tools/clean-remote-files.ts @@ -1,14 +1,14 @@ import * as promiseLimit from 'promise-limit'; import del from '../services/drive/delete-file'; import { DriveFiles } from '../models'; -import { Not } from 'typeorm'; +import { Not, IsNull } from 'typeorm'; import { DriveFile } from '../models/entities/drive-file'; import { ensure } from '../prelude/ensure'; const limit = promiseLimit(16); DriveFiles.find({ - userHost: Not(null) + userHost: Not(IsNull()) }).then(async files => { console.log(`there is ${files.length} files`); From a78b048720800973925b89455237de5c51bd780c Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 May 2019 22:01:32 +0900 Subject: [PATCH 03/24] Improve API doc --- src/models/repositories/note-favorite.ts | 31 ++++++++++++++++++++++++ src/server/api/endpoints/i/favorites.ts | 13 +++++++++- src/server/api/openapi/schemas.ts | 4 ++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/models/repositories/note-favorite.ts b/src/models/repositories/note-favorite.ts index b5875802fb..01064f3065 100644 --- a/src/models/repositories/note-favorite.ts +++ b/src/models/repositories/note-favorite.ts @@ -2,6 +2,7 @@ import { EntityRepository, Repository } from 'typeorm'; import { NoteFavorite } from '../entities/note-favorite'; import { Notes } from '..'; import { ensure } from '../../prelude/ensure'; +import { types, bool } from '../../misc/schema'; @EntityRepository(NoteFavorite) export class NoteFavoriteRepository extends Repository { @@ -26,3 +27,33 @@ export class NoteFavoriteRepository extends Repository { return Promise.all(favorites.map(x => this.pack(x, me))); } } + +export const packedNoteFavoriteSchema = { + type: types.object, + optional: bool.false, nullable: bool.false, + properties: { + id: { + type: types.string, + optional: bool.false, nullable: bool.false, + format: 'id', + description: 'The unique identifier for this favorite.', + example: 'xxxxxxxxxx', + }, + createdAt: { + type: types.string, + optional: bool.false, nullable: bool.false, + format: 'date-time', + description: 'The date that the favorite was created.' + }, + note: { + type: types.object, + optional: bool.false, nullable: bool.false, + ref: 'Note', + }, + noteId: { + type: types.string, + optional: bool.false, nullable: bool.false, + format: 'id', + }, + }, +}; diff --git a/src/server/api/endpoints/i/favorites.ts b/src/server/api/endpoints/i/favorites.ts index aad706545a..d1e90dd15c 100644 --- a/src/server/api/endpoints/i/favorites.ts +++ b/src/server/api/endpoints/i/favorites.ts @@ -3,6 +3,7 @@ import { ID } from '../../../../misc/cafy-id'; import define from '../../define'; import { NoteFavorites } from '../../../../models'; import { makePaginationQuery } from '../../common/make-pagination-query'; +import { types, bool } from '../../../../misc/schema'; export const meta = { desc: { @@ -29,7 +30,17 @@ export const meta = { untilId: { validator: $.optional.type(ID), }, - } + }, + + res: { + type: types.array, + optional: bool.false, nullable: bool.false, + items: { + type: types.object, + optional: bool.false, nullable: bool.false, + ref: 'NoteFavorite', + } + }, }; export default define(meta, async (ps, user) => { diff --git a/src/server/api/openapi/schemas.ts b/src/server/api/openapi/schemas.ts index 32f69bdef3..0a49607f05 100644 --- a/src/server/api/openapi/schemas.ts +++ b/src/server/api/openapi/schemas.ts @@ -14,6 +14,7 @@ import { packedNoteReactionSchema } from '../../../models/repositories/note-reac import { packedHashtagSchema } from '../../../models/repositories/hashtag'; import { packedPageSchema } from '../../../models/repositories/page'; import { packedUserGroupSchema } from '../../../models/repositories/user-group'; +import { packedNoteFavoriteSchema } from '../../../models/repositories/note-favorite'; export function convertSchemaToOpenApiSchema(schema: Schema) { const res: any = schema; @@ -71,13 +72,14 @@ export const schemas = { App: convertSchemaToOpenApiSchema(packedAppSchema), MessagingMessage: convertSchemaToOpenApiSchema(packedMessagingMessageSchema), Note: convertSchemaToOpenApiSchema(packedNoteSchema), + NoteReaction: convertSchemaToOpenApiSchema(packedNoteReactionSchema), + NoteFavorite: convertSchemaToOpenApiSchema(packedNoteFavoriteSchema), Notification: convertSchemaToOpenApiSchema(packedNotificationSchema), DriveFile: convertSchemaToOpenApiSchema(packedDriveFileSchema), DriveFolder: convertSchemaToOpenApiSchema(packedDriveFolderSchema), Following: convertSchemaToOpenApiSchema(packedFollowingSchema), Muting: convertSchemaToOpenApiSchema(packedMutingSchema), Blocking: convertSchemaToOpenApiSchema(packedBlockingSchema), - NoteReaction: convertSchemaToOpenApiSchema(packedNoteReactionSchema), Hashtag: convertSchemaToOpenApiSchema(packedHashtagSchema), Page: convertSchemaToOpenApiSchema(packedPageSchema), }; From 262d5ead516557c50326e387520ef316882063b1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 20 May 2019 22:59:10 +0900 Subject: [PATCH 04/24] Clean up --- src/client/app/common/views/components/nav.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/app/common/views/components/nav.vue b/src/client/app/common/views/components/nav.vue index da26fd1b8e..41b65604de 100644 --- a/src/client/app/common/views/components/nav.vue +++ b/src/client/app/common/views/components/nav.vue @@ -29,7 +29,7 @@ export default Vue.extend({ ToSUrl: null } }, - + mounted() { this.$root.getMeta(true).then(meta => { this.repositoryUrl = meta.repositoryUrl; From 5511b6e0136ee3f585527d0371268556265811b7 Mon Sep 17 00:00:00 2001 From: syuilo Date: Tue, 21 May 2019 03:07:11 +0900 Subject: [PATCH 05/24] Refactoring --- .../app/common/scripts/note-subscriber.ts | 2 - src/client/app/common/scripts/paging.ts | 169 ++++++++++++++++ .../app/common/views/components/user-list.vue | 63 ++---- .../app/common/views/deck/deck.direct.vue | 33 +--- .../views/deck/deck.favorites-column.vue | 58 ------ .../views/deck/deck.featured-column.vue | 46 ----- .../app/common/views/deck/deck.hashtag-tl.vue | 38 ++-- .../app/common/views/deck/deck.list-tl.vue | 38 ++-- .../app/common/views/deck/deck.mentions.vue | 34 ++-- .../app/common/views/deck/deck.notes.vue | 139 +++----------- .../common/views/deck/deck.notification.vue | 17 +- .../common/views/deck/deck.search-column.vue | 27 +-- src/client/app/common/views/deck/deck.tl.vue | 38 ++-- .../views/deck/deck.user-column.home.vue | 49 ++--- src/client/app/common/views/pages/explore.vue | 67 +++---- .../app/common/views/pages/favorites.vue | 44 +++++ .../app/common/views/pages/featured.vue | 44 +++++ .../app/common/views/pages/followers.vue | 29 +-- .../app/common/views/pages/following.vue | 29 +-- src/client/app/desktop/script.ts | 8 +- .../desktop/views/components/detail-notes.vue | 56 ++++++ .../app/desktop/views/components/notes.vue | 180 +++++------------ .../views/components/user-list-timeline.vue | 37 ++-- .../app/desktop/views/home/favorites.vue | 83 -------- .../app/desktop/views/home/featured.vue | 55 ------ src/client/app/desktop/views/home/search.vue | 27 +-- src/client/app/desktop/views/home/tag.vue | 27 +-- .../app/desktop/views/home/timeline.core.vue | 33 +--- .../desktop/views/home/user/user.timeline.vue | 41 ++-- src/client/app/mobile/script.ts | 8 +- .../mobile/views/components/detail-notes.vue | 52 +++++ .../app/mobile/views/components/notes.vue | 181 ++++-------------- .../mobile/views/components/notification.vue | 17 +- .../mobile/views/components/notifications.vue | 85 ++------ .../views/components/user-list-timeline.vue | 39 ++-- .../mobile/views/components/user-timeline.vue | 35 +--- .../app/mobile/views/pages/favorites.vue | 86 --------- .../app/mobile/views/pages/featured.vue | 61 ------ .../app/mobile/views/pages/home.timeline.vue | 33 +--- src/client/app/mobile/views/pages/search.vue | 37 ++-- src/client/app/mobile/views/pages/tag.vue | 27 +-- 41 files changed, 764 insertions(+), 1408 deletions(-) create mode 100644 src/client/app/common/scripts/paging.ts delete mode 100644 src/client/app/common/views/deck/deck.favorites-column.vue delete mode 100644 src/client/app/common/views/deck/deck.featured-column.vue create mode 100644 src/client/app/common/views/pages/favorites.vue create mode 100644 src/client/app/common/views/pages/featured.vue create mode 100644 src/client/app/desktop/views/components/detail-notes.vue delete mode 100644 src/client/app/desktop/views/home/favorites.vue delete mode 100644 src/client/app/desktop/views/home/featured.vue create mode 100644 src/client/app/mobile/views/components/detail-notes.vue delete mode 100644 src/client/app/mobile/views/pages/favorites.vue delete mode 100644 src/client/app/mobile/views/pages/featured.vue diff --git a/src/client/app/common/scripts/note-subscriber.ts b/src/client/app/common/scripts/note-subscriber.ts index d881fe01ce..5b31a9f9d0 100644 --- a/src/client/app/common/scripts/note-subscriber.ts +++ b/src/client/app/common/scripts/note-subscriber.ts @@ -144,8 +144,6 @@ export default prop => ({ break; } } - - this.$emit(`update:${prop}`, this.$_ns_note_); }, } }); diff --git a/src/client/app/common/scripts/paging.ts b/src/client/app/common/scripts/paging.ts new file mode 100644 index 0000000000..458ee7e5ca --- /dev/null +++ b/src/client/app/common/scripts/paging.ts @@ -0,0 +1,169 @@ +import Vue from 'vue'; + +export default (opts) => ({ + data() { + return { + items: [], + queue: [], + fetching: true, + moreFetching: false, + inited: false, + more: false + }; + }, + + computed: { + empty(): boolean { + return this.items.length == 0 && !this.fetching && this.inited; + }, + + error(): boolean { + return !this.fetching && !this.inited; + } + }, + + watch: { + queue(x) { + if (opts.onQueueChanged) opts.onQueueChanged(this, x); + }, + + pagination() { + this.init(); + } + }, + + created() { + opts.displayLimit = opts.displayLimit || 30; + this.init(); + }, + + mounted() { + if (opts.captureWindowScroll) { + this.isScrollTop = () => { + return window.scrollY <= 8; + }; + + window.addEventListener('scroll', this.onWindowScroll, { passive: true }); + } + }, + + beforeDestroy() { + if (opts.captureWindowScroll) { + window.removeEventListener('scroll', this.onWindowScroll); + } + }, + + methods: { + updateItem(i, item) { + Vue.set((this as any).items, i, item); + }, + + reload() { + this.queue = []; + this.items = []; + this.init(); + }, + + async init() { + this.fetching = true; + let params = typeof this.pagination.params === 'function' ? this.pagination.params(true) : this.pagination.params; + if (params && params.then) params = await params; + await this.$root.api(this.pagination.endpoint, { + limit: (this.pagination.limit || 10) + 1, + ...params + }).then(x => { + if (x.length == (this.pagination.limit || 10) + 1) { + x.pop(); + this.items = x; + this.more = true; + } else { + this.items = x; + this.more = false; + } + this.inited = true; + this.fetching = false; + }, e => { + this.fetching = false; + }); + }, + + async fetchMore() { + if (!this.more || this.moreFetching || this.items.length === 0) return; + this.moreFetching = true; + let params = typeof this.pagination.params === 'function' ? this.pagination.params(false) : this.pagination.params; + if (params && params.then) params = await params; + await this.$root.api(this.pagination.endpoint, { + limit: (this.pagination.limit || 10) + 1, + untilId: this.items[this.items.length - 1].id, + ...params + }).then(x => { + if (x.length == (this.pagination.limit || 10) + 1) { + x.pop(); + this.items = this.items.concat(x); + this.more = true; + } else { + this.items = this.items.concat(x); + this.more = false; + } + this.moreFetching = false; + }, e => { + this.moreFetching = false; + }); + }, + + prepend(item, silent = false) { + if (opts.onPrepend) { + const cancel = opts.onPrepend(this, item, silent); + if (cancel) return; + } + + if (this.isScrollTop()) { + // Prepend the item + this.items.unshift(item); + + // オーバーフローしたら古い投稿は捨てる + if (this.items.length >= opts.displayLimit) { + this.items = this.items.slice(0, opts.displayLimit); + this.more = true; + } + } else { + this.queue.push(item); + } + }, + + append(item) { + this.items.push(item); + }, + + releaseQueue() { + for (const n of this.queue) { + this.prepend(n, true); + } + this.queue = []; + }, + + onWindowScroll() { + if (this.isScrollTop()) { + this.onTop(); + } + + if (this.$store.state.settings.fetchOnScroll) { + // 親要素が display none だったら弾く + // https://github.com/syuilo/misskey/issues/1569 + // http://d.hatena.ne.jp/favril/20091105/1257403319 + if (this.$el.offsetHeight == 0) return; + + const current = window.scrollY + window.innerHeight; + if (current > document.body.offsetHeight - 8) this.onBottom(); + } + }, + + onTop() { + this.releaseQueue(); + }, + + onBottom() { + this.fetchMore(); + } + } +}); diff --git a/src/client/app/common/views/components/user-list.vue b/src/client/app/common/views/components/user-list.vue index 6761886b09..d6cf750016 100644 --- a/src/client/app/common/views/components/user-list.vue +++ b/src/client/app/common/views/components/user-list.vue @@ -2,13 +2,13 @@ - +
-
+

{{ $t('no-users') }}

-
+
@@ -21,8 +21,8 @@
-
@@ -31,60 +31,31 @@ diff --git a/src/client/app/common/views/deck/deck.featured-column.vue b/src/client/app/common/views/deck/deck.featured-column.vue deleted file mode 100644 index d2c44e74ce..0000000000 --- a/src/client/app/common/views/deck/deck.featured-column.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/src/client/app/common/views/deck/deck.hashtag-tl.vue b/src/client/app/common/views/deck/deck.hashtag-tl.vue index 6f89f6a23d..94d2efc430 100644 --- a/src/client/app/common/views/deck/deck.hashtag-tl.vue +++ b/src/client/app/common/views/deck/deck.hashtag-tl.vue @@ -1,13 +1,11 @@ diff --git a/src/client/app/common/views/deck/deck.notification.vue b/src/client/app/common/views/deck/deck.notification.vue index 3ced7b7e23..8a21bedb91 100644 --- a/src/client/app/common/views/deck/deck.notification.vue +++ b/src/client/app/common/views/deck/deck.notification.vue @@ -81,15 +81,15 @@
@@ -105,17 +105,6 @@ export default Vue.extend({ getNoteSummary }; }, - methods: { - onNoteUpdated(note) { - switch (this.notification.type) { - case 'quote': - case 'reply': - case 'mention': - Vue.set(this.notification, 'note', note); - break; - } - } - } }); diff --git a/src/client/app/common/views/deck/deck.search-column.vue b/src/client/app/common/views/deck/deck.search-column.vue index 17ee2ef454..a2d1142fbe 100644 --- a/src/client/app/common/views/deck/deck.search-column.vue +++ b/src/client/app/common/views/deck/deck.search-column.vue @@ -5,7 +5,7 @@
- +
@@ -16,8 +16,6 @@ import XColumn from './deck.column.vue'; import XNotes from './deck.notes.vue'; import { genSearchQuery } from '../../../common/scripts/gen-search-query'; -const limit = 20; - export default Vue.extend({ components: { XColumn, @@ -26,24 +24,11 @@ export default Vue.extend({ data() { return { - makePromise: async cursor => this.$root.api('notes/search', { - limit: limit + 1, - offset: cursor ? cursor : undefined, - ...(await genSearchQuery(this, this.q)) - }).then(notes => { - if (notes.length == limit + 1) { - notes.pop(); - return { - notes: notes, - cursor: cursor ? cursor + limit : limit - }; - } else { - return { - notes: notes, - more: false - }; - } - }) + pagination: { + endpoint: 'notes/search', + limit: 20, + params: () => genSearchQuery(this, this.q) + } }; }, diff --git a/src/client/app/common/views/deck/deck.tl.vue b/src/client/app/common/views/deck/deck.tl.vue index 9284f06ee1..e6c716070a 100644 --- a/src/client/app/common/views/deck/deck.tl.vue +++ b/src/client/app/common/views/deck/deck.tl.vue @@ -6,7 +6,7 @@

{{ $t('disabled-timeline.description') }}

- + diff --git a/src/client/app/common/views/pages/featured.vue b/src/client/app/common/views/pages/featured.vue new file mode 100644 index 0000000000..42c97e09fc --- /dev/null +++ b/src/client/app/common/views/pages/featured.vue @@ -0,0 +1,44 @@ + + + diff --git a/src/client/app/common/views/pages/followers.vue b/src/client/app/common/views/pages/followers.vue index 1d68d71e80..b546e69ae3 100644 --- a/src/client/app/common/views/pages/followers.vue +++ b/src/client/app/common/views/pages/followers.vue @@ -1,7 +1,5 @@ + + diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue index b051ff51cf..cb8b9c3ce3 100644 --- a/src/client/app/desktop/views/components/notes.vue +++ b/src/client/app/desktop/views/components/notes.vue @@ -4,9 +4,9 @@
-
{{ $t('@.no-notes') }}
+
{{ $t('@.no-notes') }}
- +