From c7cc3dcdfd2c0962a39e7186852a17dbd09b6a5b Mon Sep 17 00:00:00 2001
From: syuilo
Date: Sat, 18 May 2019 20:36:33 +0900
Subject: ユーザーグループ
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Resolve #3218
---
locales/ja-JP.yml | 48 ++++--
migration/1558103093633-UserGroup.ts | 41 +++++
src/client/app/common/views/components/dialog.vue | 1 +
src/client/app/common/views/components/index.ts | 4 +
.../views/components/messaging-room.form.vue | 16 +-
.../views/components/messaging-room.message.vue | 10 +-
.../app/common/views/components/messaging-room.vue | 56 +++++--
.../app/common/views/components/messaging.vue | 143 ++++++++++++----
src/client/app/common/views/components/ui/hr.vue | 15 ++
.../app/common/views/components/ui/margin.vue | 16 ++
.../common/views/components/user-list-editor.vue | 150 -----------------
.../app/common/views/components/user-lists.vue | 95 -----------
.../app/common/views/components/user-menu.vue | 2 +-
.../app/common/views/deck/deck.column-template.vue | 45 ++++++
.../app/common/views/deck/deck.explore-column.vue | 34 ----
src/client/app/common/views/pages/explore.vue | 4 +
.../app/common/views/pages/follow-requests.vue | 68 ++++++++
src/client/app/common/views/pages/pages.vue | 5 +
.../app/common/views/pages/user-group-editor.vue | 180 +++++++++++++++++++++
src/client/app/common/views/pages/user-groups.vue | 63 ++++++++
.../app/common/views/pages/user-list-editor.vue | 180 +++++++++++++++++++++
src/client/app/common/views/pages/user-lists.vue | 63 ++++++++
src/client/app/desktop/script.ts | 18 ++-
.../views/components/messaging-room-window.vue | 12 +-
.../desktop/views/components/messaging-window.vue | 7 +-
.../components/received-follow-requests-window.vue | 70 --------
.../desktop/views/components/ui.header.account.vue | 33 ++--
.../app/desktop/views/components/ui.sidebar.vue | 2 -
.../desktop/views/components/user-list-window.vue | 24 ---
.../desktop/views/components/user-lists-window.vue | 36 -----
.../app/desktop/views/pages/messaging-room.vue | 28 +++-
src/client/app/desktop/views/widgets/messaging.vue | 7 +-
src/client/app/mobile/script.ts | 31 ++--
src/client/app/mobile/views/components/ui.nav.vue | 2 +-
src/client/app/mobile/views/pages/explore.vue | 28 ----
.../app/mobile/views/pages/messaging-room.vue | 23 ++-
src/client/app/mobile/views/pages/messaging.vue | 5 +-
src/client/app/mobile/views/pages/pages.vue | 29 ----
.../views/pages/received-follow-requests.vue | 69 --------
src/client/app/mobile/views/pages/ui.vue | 38 +++++
src/client/app/mobile/views/pages/user-list.vue | 48 ------
src/client/app/mobile/views/pages/user-lists.vue | 35 ----
src/db/postgre.ts | 4 +
src/models/entities/messaging-message.ts | 24 ++-
src/models/entities/user-group-joining.ts | 41 +++++
src/models/entities/user-group.ts | 46 ++++++
src/models/index.ts | 6 +-
src/models/repositories/messaging-message.ts | 38 ++++-
src/models/repositories/user-group.ts | 61 +++++++
src/models/repositories/user.ts | 35 +++-
src/server/api/common/read-messaging-message.ts | 80 +++++++--
src/server/api/endpoints/messaging/history.ts | 51 ++++--
src/server/api/endpoints/messaging/messages.ts | 105 +++++++++---
.../api/endpoints/messaging/messages/create.ts | 127 +++++++++++----
.../api/endpoints/messaging/messages/delete.ts | 12 +-
.../api/endpoints/messaging/messages/read.ts | 17 +-
src/server/api/endpoints/users/groups/create.ts | 51 ++++++
src/server/api/endpoints/users/groups/delete.ts | 49 ++++++
src/server/api/endpoints/users/groups/joined.ts | 33 ++++
src/server/api/endpoints/users/groups/owned.ts | 33 ++++
src/server/api/endpoints/users/groups/pull.ts | 68 ++++++++
src/server/api/endpoints/users/groups/push.ts | 90 +++++++++++
src/server/api/endpoints/users/groups/show.ts | 53 ++++++
src/server/api/endpoints/users/lists/push.ts | 2 +-
src/server/api/kinds.ts | 2 +
src/server/api/openapi/schemas.ts | 2 +
src/server/api/stream/channels/messaging.ts | 31 +++-
src/services/stream.ts | 6 +
68 files changed, 2005 insertions(+), 846 deletions(-)
create mode 100644 migration/1558103093633-UserGroup.ts
create mode 100644 src/client/app/common/views/components/ui/hr.vue
create mode 100644 src/client/app/common/views/components/ui/margin.vue
delete mode 100644 src/client/app/common/views/components/user-list-editor.vue
delete mode 100644 src/client/app/common/views/components/user-lists.vue
create mode 100644 src/client/app/common/views/deck/deck.column-template.vue
delete mode 100644 src/client/app/common/views/deck/deck.explore-column.vue
create mode 100644 src/client/app/common/views/pages/follow-requests.vue
create mode 100644 src/client/app/common/views/pages/user-group-editor.vue
create mode 100644 src/client/app/common/views/pages/user-groups.vue
create mode 100644 src/client/app/common/views/pages/user-list-editor.vue
create mode 100644 src/client/app/common/views/pages/user-lists.vue
delete mode 100644 src/client/app/desktop/views/components/received-follow-requests-window.vue
delete mode 100644 src/client/app/desktop/views/components/user-list-window.vue
delete mode 100644 src/client/app/desktop/views/components/user-lists-window.vue
delete mode 100644 src/client/app/mobile/views/pages/explore.vue
delete mode 100644 src/client/app/mobile/views/pages/pages.vue
delete mode 100644 src/client/app/mobile/views/pages/received-follow-requests.vue
create mode 100644 src/client/app/mobile/views/pages/ui.vue
delete mode 100644 src/client/app/mobile/views/pages/user-list.vue
delete mode 100644 src/client/app/mobile/views/pages/user-lists.vue
create mode 100644 src/models/entities/user-group-joining.ts
create mode 100644 src/models/entities/user-group.ts
create mode 100644 src/models/repositories/user-group.ts
create mode 100644 src/server/api/endpoints/users/groups/create.ts
create mode 100644 src/server/api/endpoints/users/groups/delete.ts
create mode 100644 src/server/api/endpoints/users/groups/joined.ts
create mode 100644 src/server/api/endpoints/users/groups/owned.ts
create mode 100644 src/server/api/endpoints/users/groups/pull.ts
create mode 100644 src/server/api/endpoints/users/groups/push.ts
create mode 100644 src/server/api/endpoints/users/groups/show.ts
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index dc0692e4b9..437fd39971 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -265,6 +265,7 @@ common:
my-token-regenerated: "あなたのトークンが更新されたのでサインアウトします。"
hide-password: "パスワードを隠す"
show-password: "パスワードを表示する"
+ enter-username: "ユーザー名を入力してください"
do-not-use-in-production: "これは開発ビルドです。本番環境で使用しないでください。"
user-suspended: "このユーザーは凍結されています。"
@@ -480,20 +481,24 @@ common/views/components/messaging.vue:
search-user: "ユーザーを探す"
you: "あなた"
no-history: "履歴はありません"
+ user: "ユーザー"
+ group: "グループ"
+ start-with-user: "ユーザーとトークを開始"
+ start-with-group: "グループとトークを開始"
common/views/components/messaging-room.vue:
- empty: "このユーザーと話したことはありません"
+ not-talked-user: "このユーザーとの会話はありません"
+ not-talked-group: "このグループでの会話はありません"
no-history: "これより過去の履歴はありません"
- resize-form: "ドラッグしてフォームの広さを調整"
new-message: "新しいメッセージがあります"
- only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
+ only-one-file-attached: "メッセージに添付できるファイルはひとつです"
common/views/components/messaging-room.form.vue:
input-message-here: "ここにメッセージを入力"
send: "送信"
attach-from-local: "PCからファイルを添付する"
attach-from-drive: "ドライブからファイルを添付する"
- only-one-file-attached: "メッセージに添付できるのはひとつのファイルのみです"
+ only-one-file-attached: "メッセージに添付できるファイルはひとつです"
common/views/components/messaging-room.message.vue:
is-read: "既読"
@@ -750,11 +755,27 @@ common/views/components/user-list-editor.vue:
remove-user: "このリストから削除"
delete-are-you-sure: "リスト「$1」を削除しますか?"
deleted: "削除しました"
+ add-user: "ユーザーを追加"
+
+common/views/components/user-group-editor.vue:
+ users: "メンバー"
+ rename: "グループ名を変更"
+ delete: "グループを削除"
+ remove-user: "このグループから削除"
+ delete-are-you-sure: "グループ「$1」を削除しますか?"
+ deleted: "削除しました"
+ add-user: "メンバーを追加"
common/views/components/user-lists.vue:
+ user-lists: "リスト"
create-list: "リストを作成"
list-name: "リスト名"
+common/views/components/user-groups.vue:
+ user-groups: "グループ"
+ create-group: "グループを作成"
+ group-name: "グループ名"
+
common/views/widgets/broadcast.vue:
fetching: "確認中"
no-broadcasts: "お知らせはありません"
@@ -827,6 +848,11 @@ common/views/pages/follow.vue:
follow-processing: "フォロー処理中"
follow-request: "フォロー申請"
+common/views/pages/follow-requests.vue:
+ received-follow-requests: "フォロー申請"
+ accept: "承認"
+ reject: "拒否"
+
desktop:
banner-crop-title: "バナーとして表示する部分を選択"
banner: "バナー"
@@ -1139,6 +1165,7 @@ desktop/views/components/ui.header.vue:
desktop/views/components/ui.header.account.vue:
profile: "プロフィール"
lists: "リスト"
+ groups: "グループ"
follow-requests: "フォロー申請"
admin: "管理"
@@ -1154,14 +1181,6 @@ desktop/views/components/ui.header.post.vue:
desktop/views/components/ui.header.search.vue:
placeholder: "検索"
-desktop/views/components/received-follow-requests-window.vue:
- title: "フォロー申請"
- accept: "承認"
- reject: "拒否"
-
-desktop/views/components/user-lists-window.vue:
- title: "リスト"
-
desktop/views/components/user-preview.vue:
notes: "投稿"
following: "フォロー"
@@ -1749,11 +1768,6 @@ mobile/views/pages/widgets/activity.vue:
mobile/views/pages/share.vue:
share-with: "{name}で共有"
-mobile/views/pages/received-follow-requests.vue:
- title: "フォロー申請"
- accept: "承認"
- reject: "拒否"
-
mobile/views/pages/note.vue:
title: "投稿"
prev: "前の投稿"
diff --git a/migration/1558103093633-UserGroup.ts b/migration/1558103093633-UserGroup.ts
new file mode 100644
index 0000000000..04783b8dfa
--- /dev/null
+++ b/migration/1558103093633-UserGroup.ts
@@ -0,0 +1,41 @@
+import {MigrationInterface, QueryRunner} from "typeorm";
+
+export class UserGroup1558103093633 implements MigrationInterface {
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`CREATE TABLE "user_group" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "name" character varying(256) NOT NULL, "userId" character varying(32) NOT NULL, "isPrivate" boolean NOT NULL DEFAULT false, CONSTRAINT "PK_3c29fba6fe013ec8724378ce7c9" PRIMARY KEY ("id"))`);
+ await queryRunner.query(`CREATE INDEX "IDX_20e30aa35180e317e133d75316" ON "user_group" ("createdAt") `);
+ await queryRunner.query(`CREATE INDEX "IDX_3d6b372788ab01be58853003c9" ON "user_group" ("userId") `);
+ await queryRunner.query(`CREATE TABLE "user_group_joining" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "userGroupId" character varying(32) NOT NULL, CONSTRAINT "PK_15f2425885253c5507e1599cfe7" PRIMARY KEY ("id"))`);
+ await queryRunner.query(`CREATE INDEX "IDX_f3a1b4bd0c7cabba958a0c0b23" ON "user_group_joining" ("userId") `);
+ await queryRunner.query(`CREATE INDEX "IDX_67dc758bc0566985d1b3d39986" ON "user_group_joining" ("userGroupId") `);
+ await queryRunner.query(`ALTER TABLE "messaging_message" ADD "groupId" character varying(32)`);
+ await queryRunner.query(`ALTER TABLE "messaging_message" ADD "reads" character varying(32) array NOT NULL DEFAULT '{}'::varchar[]`);
+ await queryRunner.query(`ALTER TABLE "messaging_message" ALTER COLUMN "recipientId" DROP NOT NULL`);
+ await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."recipientId" IS 'The recipient user ID.'`);
+ await queryRunner.query(`CREATE INDEX "IDX_2c4be03b446884f9e9c502135b" ON "messaging_message" ("groupId") `);
+ await queryRunner.query(`ALTER TABLE "messaging_message" ADD CONSTRAINT "FK_2c4be03b446884f9e9c502135be" FOREIGN KEY ("groupId") REFERENCES "user_group"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
+ await queryRunner.query(`ALTER TABLE "user_group" ADD CONSTRAINT "FK_3d6b372788ab01be58853003c93" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
+ await queryRunner.query(`ALTER TABLE "user_group_joining" ADD CONSTRAINT "FK_f3a1b4bd0c7cabba958a0c0b231" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
+ await queryRunner.query(`ALTER TABLE "user_group_joining" ADD CONSTRAINT "FK_67dc758bc0566985d1b3d399865" FOREIGN KEY ("userGroupId") REFERENCES "user_group"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`ALTER TABLE "user_group_joining" DROP CONSTRAINT "FK_67dc758bc0566985d1b3d399865"`);
+ await queryRunner.query(`ALTER TABLE "user_group_joining" DROP CONSTRAINT "FK_f3a1b4bd0c7cabba958a0c0b231"`);
+ await queryRunner.query(`ALTER TABLE "user_group" DROP CONSTRAINT "FK_3d6b372788ab01be58853003c93"`);
+ await queryRunner.query(`ALTER TABLE "messaging_message" DROP CONSTRAINT "FK_2c4be03b446884f9e9c502135be"`);
+ await queryRunner.query(`DROP INDEX "IDX_2c4be03b446884f9e9c502135b"`);
+ await queryRunner.query(`COMMENT ON COLUMN "messaging_message"."recipientId" IS ''`);
+ await queryRunner.query(`ALTER TABLE "messaging_message" ALTER COLUMN "recipientId" SET NOT NULL`);
+ await queryRunner.query(`ALTER TABLE "messaging_message" DROP COLUMN "reads"`);
+ await queryRunner.query(`ALTER TABLE "messaging_message" DROP COLUMN "groupId"`);
+ await queryRunner.query(`DROP INDEX "IDX_67dc758bc0566985d1b3d39986"`);
+ await queryRunner.query(`DROP INDEX "IDX_f3a1b4bd0c7cabba958a0c0b23"`);
+ await queryRunner.query(`DROP TABLE "user_group_joining"`);
+ await queryRunner.query(`DROP INDEX "IDX_3d6b372788ab01be58853003c9"`);
+ await queryRunner.query(`DROP INDEX "IDX_20e30aa35180e317e133d75316"`);
+ await queryRunner.query(`DROP TABLE "user_group"`);
+ }
+
+}
diff --git a/src/client/app/common/views/components/dialog.vue b/src/client/app/common/views/components/dialog.vue
index f22e0174b3..9f38031d62 100644
--- a/src/client/app/common/views/components/dialog.vue
+++ b/src/client/app/common/views/components/dialog.vue
@@ -18,6 +18,7 @@
+ {{ $t('@.enter-username') }}
@
diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts
index f4d40f9b1a..174fa36c00 100644
--- a/src/client/app/common/views/components/index.ts
+++ b/src/client/app/common/views/components/index.ts
@@ -44,6 +44,8 @@ import uiSwitch from './ui/switch.vue';
import uiRadio from './ui/radio.vue';
import uiSelect from './ui/select.vue';
import uiInfo from './ui/info.vue';
+import uiMargin from './ui/margin.vue';
+import uiHr from './ui/hr.vue';
import formButton from './ui/form/button.vue';
import formRadio from './ui/form/radio.vue';
@@ -91,5 +93,7 @@ Vue.component('ui-switch', uiSwitch);
Vue.component('ui-radio', uiRadio);
Vue.component('ui-select', uiSelect);
Vue.component('ui-info', uiInfo);
+Vue.component('ui-margin', uiMargin);
+Vue.component('ui-hr', uiHr);
Vue.component('form-button', formButton);
Vue.component('form-radio', formRadio);
diff --git a/src/client/app/common/views/components/messaging-room.form.vue b/src/client/app/common/views/components/messaging-room.form.vue
index ee6c312bce..1dfb0589e4 100644
--- a/src/client/app/common/views/components/messaging-room.form.vue
+++ b/src/client/app/common/views/components/messaging-room.form.vue
@@ -33,7 +33,16 @@ import * as autosize from 'autosize';
export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.form.vue'),
- props: ['user'],
+ props: {
+ user: {
+ type: Object,
+ requird: false,
+ },
+ group: {
+ type: Object,
+ requird: false,
+ },
+ },
data() {
return {
text: null,
@@ -43,7 +52,7 @@ export default Vue.extend({
},
computed: {
draftId(): string {
- return this.user.id;
+ return this.user ? 'user:' + this.user.id : 'group:' + this.group.id;
},
canSend(): boolean {
return (this.text != null && this.text != '') || this.file != null;
@@ -159,7 +168,8 @@ export default Vue.extend({
send() {
this.sending = true;
this.$root.api('messaging/messages/create', {
- userId: this.user.id,
+ userId: this.user ? this.user.id : undefined,
+ groupId: this.group ? this.group.id : undefined,
text: this.text ? this.text : undefined,
fileId: this.file ? this.file.id : undefined
}).then(message => {
diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue
index 908533e0cc..aff89c2573 100644
--- a/src/client/app/common/views/components/messaging-room.message.vue
+++ b/src/client/app/common/views/components/messaging-room.message.vue
@@ -23,7 +23,12 @@
@@ -42,6 +47,9 @@ export default Vue.extend({
props: {
message: {
required: true
+ },
+ isGroup: {
+ required: false
}
},
computed: {
diff --git a/src/client/app/common/views/components/messaging-room.vue b/src/client/app/common/views/components/messaging-room.vue
index a8980e068f..658dc93f64 100644
--- a/src/client/app/common/views/components/messaging-room.vue
+++ b/src/client/app/common/views/components/messaging-room.vue
@@ -4,14 +4,14 @@
@drop.prevent.stop="onDrop"
>
-
{{ $t('@.loading') }}
-
{{ $t('empty') }}
+
{{ $t('@.loading') }}
+
{{ user ? $t('not-talked-user') : $t('not-talked-group') }}
{{ $t('no-history') }}
-
+
{{ _messages[i + 1]._datetext }}
@@ -23,7 +23,7 @@
-
+
@@ -34,17 +34,30 @@ import i18n from '../../../i18n';
import XMessage from './messaging-room.message.vue';
import XForm from './messaging-room.form.vue';
import { url } from '../../../config';
-import { faArrowCircleDown } from '@fortawesome/free-solid-svg-icons';
-import { faFlag } from '@fortawesome/free-regular-svg-icons';
+import { faArrowCircleDown, faFlag } from '@fortawesome/free-solid-svg-icons';
export default Vue.extend({
i18n: i18n('common/views/components/messaging-room.vue'),
+
components: {
XMessage,
XForm
},
- props: ['user', 'isNaked'],
+ props: {
+ user: {
+ type: Object,
+ requird: false,
+ },
+ group: {
+ type: Object,
+ requird: false,
+ },
+ isNaked: {
+ type: Boolean,
+ requird: false,
+ },
+ },
data() {
return {
@@ -76,7 +89,10 @@ export default Vue.extend({
},
mounted() {
- this.connection = this.$root.stream.connectToChannel('messaging', { otherparty: this.user.id });
+ this.connection = this.$root.stream.connectToChannel('messaging', {
+ otherparty: this.user ? this.user.id : undefined,
+ group: this.group ? this.group.id : undefined,
+ });
this.connection.on('message', this.onMessage);
this.connection.on('read', this.onRead);
@@ -147,7 +163,8 @@ export default Vue.extend({
const max = this.existMoreMessages ? 20 : 10;
this.$root.api('messaging/messages', {
- userId: this.user.id,
+ userId: this.user ? this.user.id : undefined,
+ groupId: this.group ? this.group.id : undefined,
limit: max + 1,
untilId: this.existMoreMessages ? this.messages[0].id : undefined
}).then(messages => {
@@ -199,12 +216,21 @@ export default Vue.extend({
}
},
- onRead(ids) {
- if (!Array.isArray(ids)) ids = [ids];
- for (const id of ids) {
- if (this.messages.some(x => x.id == id)) {
- const exist = this.messages.map(x => x.id).indexOf(id);
- this.messages[exist].isRead = true;
+ onRead(x) {
+ if (this.user) {
+ if (!Array.isArray(x)) x = [x];
+ for (const id of x) {
+ if (this.messages.some(x => x.id == id)) {
+ const exist = this.messages.map(x => x.id).indexOf(id);
+ this.messages[exist].isRead = true;
+ }
+ }
+ } else if (this.group) {
+ for (const id of x.ids) {
+ if (this.messages.some(x => x.id == id)) {
+ const exist = this.messages.map(x => x.id).indexOf(id);
+ this.messages[exist].reads.push(x.userId);
+ }
}
}
},
diff --git a/src/client/app/common/views/components/messaging.vue b/src/client/app/common/views/components/messaging.vue
index f884a599d7..01d7a5a798 100644
--- a/src/client/app/common/views/components/messaging.vue
+++ b/src/client/app/common/views/components/messaging.vue
@@ -21,36 +21,62 @@
+
+
diff --git a/src/client/app/common/views/components/ui/margin.vue b/src/client/app/common/views/components/ui/margin.vue
new file mode 100644
index 0000000000..508116f070
--- /dev/null
+++ b/src/client/app/common/views/components/ui/margin.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/client/app/common/views/components/user-list-editor.vue b/src/client/app/common/views/components/user-list-editor.vue
deleted file mode 100644
index 86024c4da3..0000000000
--- a/src/client/app/common/views/components/user-list-editor.vue
+++ /dev/null
@@ -1,150 +0,0 @@
-
-
-
- {{ list.name }}
-
-
- {{ $t('rename') }}
- {{ $t('delete') }}
-
-
-
-
- {{ $t('users') }}
-
-
-
-
-
-
-
-
-
diff --git a/src/client/app/common/views/components/user-lists.vue b/src/client/app/common/views/components/user-lists.vue
deleted file mode 100644
index 699251b313..0000000000
--- a/src/client/app/common/views/components/user-lists.vue
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/client/app/common/views/components/user-menu.vue b/src/client/app/common/views/components/user-menu.vue
index 7cbffa9f9a..532dcf35c2 100644
--- a/src/client/app/common/views/components/user-menu.vue
+++ b/src/client/app/common/views/components/user-menu.vue
@@ -27,7 +27,7 @@ export default Vue.extend({
text: this.$t('push-to-list'),
action: this.pushList
}] as any;
-
+
if (this.$store.getters.isSignedIn && this.$store.state.i.id != this.user.id) {
menu = menu.concat([null, {
icon: this.user.isMuted ? ['fas', 'eye'] : ['far', 'eye-slash'],
diff --git a/src/client/app/common/views/deck/deck.column-template.vue b/src/client/app/common/views/deck/deck.column-template.vue
new file mode 100644
index 0000000000..09583de4b2
--- /dev/null
+++ b/src/client/app/common/views/deck/deck.column-template.vue
@@ -0,0 +1,45 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
diff --git a/src/client/app/common/views/deck/deck.explore-column.vue b/src/client/app/common/views/deck/deck.explore-column.vue
deleted file mode 100644
index 53db677b37..0000000000
--- a/src/client/app/common/views/deck/deck.explore-column.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
- {{ $t('@.explore') }}
-
-
-
-
-
-
-
-
-
diff --git a/src/client/app/common/views/pages/explore.vue b/src/client/app/common/views/pages/explore.vue
index d0e98035f8..bf0d7ab574 100644
--- a/src/client/app/common/views/pages/explore.vue
+++ b/src/client/app/common/views/pages/explore.vue
@@ -116,6 +116,10 @@ export default Vue.extend({
},
created() {
+ this.$emit('init', {
+ title: this.$t('@.explore'),
+ icon: faHashtag
+ });
this.$root.api('hashtags/list', {
sort: '+attachedLocalUsers',
attachedToLocalUserOnly: true,
diff --git a/src/client/app/common/views/pages/follow-requests.vue b/src/client/app/common/views/pages/follow-requests.vue
new file mode 100644
index 0000000000..860efefd93
--- /dev/null
+++ b/src/client/app/common/views/pages/follow-requests.vue
@@ -0,0 +1,68 @@
+
+
+
+ {{ $t('received-follow-requests') }}
+
+
+
+
+
+
+
+
diff --git a/src/client/app/common/views/pages/pages.vue b/src/client/app/common/views/pages/pages.vue
index 751ea72374..d658728a19 100644
--- a/src/client/app/common/views/pages/pages.vue
+++ b/src/client/app/common/views/pages/pages.vue
@@ -50,6 +50,11 @@ export default Vue.extend({
},
created() {
this.fetch();
+
+ this.$emit('init', {
+ title: this.$t('@.pages'),
+ icon: faStickyNote
+ });
},
methods: {
async fetch() {
diff --git a/src/client/app/common/views/pages/user-group-editor.vue b/src/client/app/common/views/pages/user-group-editor.vue
new file mode 100644
index 0000000000..c658d0c6ff
--- /dev/null
+++ b/src/client/app/common/views/pages/user-group-editor.vue
@@ -0,0 +1,180 @@
+
+
+
+ {{ group.name }}
+
+
+
+ {{ $t('rename') }}
+ {{ $t('delete') }}
+
+
+
+
+
+ {{ $t('users') }}
+
+
+
+ {{ $t('add-user') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/client/app/common/views/pages/user-groups.vue b/src/client/app/common/views/pages/user-groups.vue
new file mode 100644
index 0000000000..336772799b
--- /dev/null
+++ b/src/client/app/common/views/pages/user-groups.vue
@@ -0,0 +1,63 @@
+
+
+ {{ $t('user-groups') }}
+
+ {{ $t('create-group') }}
+
+
+
+
+ {{ group.name }}
+
+
+
+
+
+
+
+
diff --git a/src/client/app/common/views/pages/user-list-editor.vue b/src/client/app/common/views/pages/user-list-editor.vue
new file mode 100644
index 0000000000..6b2fd75f85
--- /dev/null
+++ b/src/client/app/common/views/pages/user-list-editor.vue
@@ -0,0 +1,180 @@
+
+
+
+ {{ list.name }}
+
+
+
+ {{ $t('rename') }}
+ {{ $t('delete') }}
+
+
+
+
+
+ {{ $t('users') }}
+
+
+
+ {{ $t('add-user') }}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/client/app/common/views/pages/user-lists.vue b/src/client/app/common/views/pages/user-lists.vue
new file mode 100644
index 0000000000..4c09eca6ce
--- /dev/null
+++ b/src/client/app/common/views/pages/user-lists.vue
@@ -0,0 +1,63 @@
+
+
+ {{ $t('user-lists') }}
+
+ {{ $t('create-list') }}
+
+
+
+
+ {{ list.name }}
+
+
+
+
+
+
+
+
diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts
index 464f7d3ce9..c6479f477c 100644
--- a/src/client/app/desktop/script.ts
+++ b/src/client/app/desktop/script.ts
@@ -22,6 +22,7 @@ import MkShare from '../common/views/pages/share.vue';
import MkFollow from '../common/views/pages/follow.vue';
import MkNotFound from '../common/views/pages/not-found.vue';
import MkSettings from './views/pages/settings.vue';
+import DeckColumn from '../common/views/deck/deck.column-template.vue';
import Ctx from './views/components/context-menu.vue';
import PostFormWindow from './views/components/post-form-window.vue';
@@ -138,9 +139,14 @@ init(async (launch, os) => {
{ path: '/search', component: () => import('../common/views/deck/deck.search-column.vue').then(m => m.default) },
{ path: '/tags/:tag', name: 'tag', component: () => import('../common/views/deck/deck.hashtag-column.vue').then(m => m.default) },
{ path: '/featured', name: 'featured', component: () => import('../common/views/deck/deck.featured-column.vue').then(m => m.default) },
- { path: '/explore', name: 'explore', component: () => import('../common/views/deck/deck.explore-column.vue').then(m => m.default) },
- { path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('../common/views/deck/deck.explore-column.vue').then(m => m.default) },
- { path: '/i/favorites', component: () => import('../common/views/deck/deck.favorites-column.vue').then(m => m.default) }
+ { path: '/explore', name: 'explore', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default) }) },
+ { path: '/explore/tags/:tag', name: 'explore-tag', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/explore.vue').then(m => m.default), tag: route.params.tag }) },
+ { path: '/i/favorites', component: () => import('../common/views/deck/deck.favorites-column.vue').then(m => m.default) },
+ { path: '/i/pages', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/pages.vue').then(m => m.default) }) },
+ { path: '/i/lists', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) }) },
+ { path: '/i/lists/:listId', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default), listId: route.params.listId }) },
+ { path: '/i/groups', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) }) },
+ { path: '/i/groups/:groupId', component: DeckColumn, props: route => ({ component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default), groupId: route.params.groupId }) },
]}
: { path: '/', component: MkHome, children: [
{ path: '', name: 'index', component: MkHomeTimeline },
@@ -157,11 +163,17 @@ init(async (launch, os) => {
{ path: '/explore/tags/:tag', name: 'explore-tag', props: true, component: () => import('../common/views/pages/explore.vue').then(m => m.default) },
{ path: '/i/favorites', component: () => import('./views/home/favorites.vue').then(m => m.default) },
{ path: '/i/pages', component: () => import('../common/views/pages/pages.vue').then(m => m.default) },
+ { path: '/i/lists', component: () => import('../common/views/pages/user-lists.vue').then(m => m.default) },
+ { path: '/i/lists/:listId', props: true, component: () => import('../common/views/pages/user-list-editor.vue').then(m => m.default) },
+ { path: '/i/groups', component: () => import('../common/views/pages/user-groups.vue').then(m => m.default) },
+ { path: '/i/groups/:groupId', props: true, component: () => import('../common/views/pages/user-group-editor.vue').then(m => m.default) },
+ { path: '/i/follow-requests', component: () => import('../common/views/pages/follow-requests.vue').then(m => m.default) },
]},
{ path: '/@:user/pages/:page', props: true, component: () => import('./views/pages/page.vue').then(m => m.default) },
{ path: '/@:user/pages/:pageName/view-source', props: true, component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
{ path: '/i/pages/new', component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
{ path: '/i/pages/edit/:pageId', props: true, component: () => import('./views/pages/page-editor.vue').then(m => m.default) },
+ { path: '/i/messaging/group/:group', component: MkMessagingRoom },
{ path: '/i/messaging/:user', component: MkMessagingRoom },
{ path: '/i/drive', component: MkDrive },
{ path: '/i/drive/folder/:folder', component: MkDrive },
diff --git a/src/client/app/desktop/views/components/messaging-room-window.vue b/src/client/app/desktop/views/components/messaging-room-window.vue
index 00cd423cd2..6c1708b59f 100644
--- a/src/client/app/desktop/views/components/messaging-room-window.vue
+++ b/src/client/app/desktop/views/components/messaging-room-window.vue
@@ -1,7 +1,7 @@
- {{ $t('@.messaging') }}:
-
+ {{ $t('@.messaging') }}: {{ group.name }}
+
@@ -16,10 +16,14 @@ export default Vue.extend({
components: {
XMessagingRoom: () => import('../../../common/views/components/messaging-room.vue').then(m => m.default)
},
- props: ['user'],
+ props: ['user', 'group'],
computed: {
popout(): string {
- return `${url}/i/messaging/${getAcct(this.user)}`;
+ if (this.user) {
+ return `${url}/i/messaging/${getAcct(this.user)}`;
+ } else if (this.group) {
+ return `${url}/i/messaging/group/${this.group.id}`;
+ }
}
}
});
diff --git a/src/client/app/desktop/views/components/messaging-window.vue b/src/client/app/desktop/views/components/messaging-window.vue
index 1572c40669..7cec9484d6 100644
--- a/src/client/app/desktop/views/components/messaging-window.vue
+++ b/src/client/app/desktop/views/components/messaging-window.vue
@@ -1,7 +1,7 @@
{{ $t('@.messaging') }}
-
+
@@ -20,6 +20,11 @@ export default Vue.extend({
this.$root.new(MkMessagingRoomWindow, {
user: user
});
+ },
+ navigateGroup(group) {
+ this.$root.new(MkMessagingRoomWindow, {
+ group: group
+ });
}
}
});
diff --git a/src/client/app/desktop/views/components/received-follow-requests-window.vue b/src/client/app/desktop/views/components/received-follow-requests-window.vue
deleted file mode 100644
index f86b6b0d59..0000000000
--- a/src/client/app/desktop/views/components/received-follow-requests-window.vue
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
- {{ $t('title') }}
-
-
-
-
-
-
-
-
diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue
index 9b87e0c29f..c00c6b9c64 100644
--- a/src/client/app/desktop/views/components/ui.header.account.vue
+++ b/src/client/app/desktop/views/components/ui.header.account.vue
@@ -28,12 +28,19 @@
-
-
+
+
{{ $t('lists') }}
-
+
+
+
+
+
+ {{ $t('groups') }}
+
+
@@ -42,12 +49,12 @@
-
-
+
+
{{ $t('follow-requests') }}{{ $store.state.i.pendingReceivedFollowRequestsCount }}
-
+