diff --git a/CHANGELOG.md b/CHANGELOG.md index b2b0b1dda..00100e6f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,10 @@ npm run migrate 11.24.0 (2019/07/05) -------------------- -注意: このアップデート後に、`node built/tools/accept-migration Init 1000000000000`してください。 +### 注意 +- このアップデート後に、`node built/tools/accept-migration Init 1000000000000`してください。 +- プロセスを起動(もしくは再起動)する前に[マイグレーション](#migration)の手順を実行してください + ### ✨Improvements * WebAuthnサポート diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 894122b04..ea427b2c0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -220,8 +220,7 @@ const user = await Users.findOne(userId).then(ensure); ### Migration作成方法 ``` -npm i -g ts-node -ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前 +npx ts-node ./node_modules/typeorm/cli.js migration:generate -n 変更の名前 ``` 作成されたスクリプトは不必要な変更を含むため除去してください。 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 9df3b0e27..bf23e4470 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -967,7 +967,7 @@ desktop/views/components/drive.file.vue: unmark-as-sensitive: "閲覧注意を解除" copy-url: "URLをコピー" download: "ダウンロード" - else-files: "その他..." + else-files: "その他" set-as-avatar: "アイコンに設定" set-as-banner: "バナーに設定" open-in-app: "アプリで開く" @@ -978,15 +978,20 @@ desktop/views/components/drive.file.vue: copied-url-to-clipboard: "URLをクリップボードにコピーしました" desktop/views/components/drive.folder.vue: + upload-folder: "既定アップロード先" unable-to-process: "操作を完了できません" circular-reference-detected: "移動先のフォルダーは、移動するフォルダーのサブフォルダーです。" unhandled-error: "不明なエラー" + unable-to-delete: "削除できません" + has-child-files-or-folders: "このフォルダは空でないため、削除できません。" contextmenu: move-to-this-folder: "このフォルダへ移動" show-in-new-window: "新しいウィンドウで表示" rename: "名前を変更" rename-folder: "フォルダ名の変更" input-new-folder-name: "新しいフォルダ名を入力してください" + else-folders: "その他" + set-as-upload-folder: "既定アップロード先に設定" desktop/views/components/drive.vue: search: "検索" @@ -1150,6 +1155,9 @@ common/views/components/drive-settings.vue: max: "容量" in-use: "使用中" stats: "統計" + default-upload-folder: "既定のアップロード先フォルダ" + default-upload-folder-name: "フォルダ" + change-default-upload-folder: "フォルダを変更" common/views/components/mute-and-block.vue: mute-and-block: "ミュートとブロック" @@ -1916,6 +1924,7 @@ deck/deck.user-column.vue: activity: "アクティビティ" timeline: "タイムライン" pinned-notes: "ピン留めされた投稿" + pinned-page: "ピン留めされたページ" docs: edit-this-page-on-github: "間違いや改善点を見つけましたか?" @@ -1955,6 +1964,8 @@ pages: are-you-sure-delete: "このページを削除しますか?" page-deleted: "ページを削除しました" edit-this-page: "このページを編集" + pin-this-page: "ピン留め" + unpin-this-page: "ピン留め解除" view-source: "ソースを表示" view-page: "ページを見る" like: "いいね" @@ -1973,6 +1984,7 @@ pages: url: "ページURL" summary: "ページの要約" align-center: "中央寄せ" + hide-title-when-pinned: "ピン留めされているときにタイトルを非表示" font: "フォント" fontSerif: "セリフ" fontSansSerif: "サンセリフ" @@ -2045,6 +2057,8 @@ pages: _pushEvent: event: "イベント名" message: "押したときに表示するメッセージ" + variable: "送信する変数" + no-variable: "なし" script: categories: diff --git a/migration/1562444565093-PinnedPage.ts b/migration/1562444565093-PinnedPage.ts new file mode 100644 index 000000000..4bdee2274 --- /dev/null +++ b/migration/1562444565093-PinnedPage.ts @@ -0,0 +1,17 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class PinnedPage1562444565093 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_profile" ADD "pinnedPageId" character varying(32)`); + await queryRunner.query(`ALTER TABLE "user_profile" ADD CONSTRAINT "UQ_6dc44f1ceb65b1e72bacef2ca27" UNIQUE ("pinnedPageId")`); + await queryRunner.query(`ALTER TABLE "user_profile" ADD CONSTRAINT "FK_6dc44f1ceb65b1e72bacef2ca27" FOREIGN KEY ("pinnedPageId") REFERENCES "page"("id") ON DELETE SET NULL ON UPDATE NO ACTION`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "user_profile" DROP CONSTRAINT "FK_6dc44f1ceb65b1e72bacef2ca27"`); + await queryRunner.query(`ALTER TABLE "user_profile" DROP CONSTRAINT "UQ_6dc44f1ceb65b1e72bacef2ca27"`); + await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "pinnedPageId"`); + } + +} diff --git a/migration/1562448332510-PageTitleHideOption.ts b/migration/1562448332510-PageTitleHideOption.ts new file mode 100644 index 000000000..acc9b7e26 --- /dev/null +++ b/migration/1562448332510-PageTitleHideOption.ts @@ -0,0 +1,13 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class PageTitleHideOption1562448332510 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "page" ADD "hideTitleWhenPinned" boolean NOT NULL DEFAULT false`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "hideTitleWhenPinned"`); + } + +} diff --git a/src/client/app/common/scripts/post-form.ts b/src/client/app/common/scripts/post-form.ts index 85a578484..1d93b4c26 100644 --- a/src/client/app/common/scripts/post-form.ts +++ b/src/client/app/common/scripts/post-form.ts @@ -151,9 +151,16 @@ export default (opts) => ({ // 公開以外へのリプライ時は元の公開範囲を引き継ぐ if (this.reply && ['home', 'followers', 'specified'].includes(this.reply.visibility)) { this.visibility = this.reply.visibility; + if (this.reply.visibility === 'specified') { + this.$root.api('users/show', { + userIds: this.reply.visibleUserIds.filter(uid => uid !== this.$store.state.i.id && uid !== this.reply.userId) + }).then(users => { + this.visibleUsers.push(...users); + }); + } } - if (this.reply) { + if (this.reply && this.reply.userId !== this.$store.state.i.id) { this.$root.api('users/show', { userId: this.reply.userId }).then(user => { this.visibleUsers.push(user); }); @@ -238,7 +245,7 @@ export default (opts) => ({ }, upload(file) { - (this.$refs.uploader as any).upload(file); + (this.$refs.uploader as any).upload(file, this.$store.state.settings.uploadFolder); }, onChangeUploadings(uploads) { 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 1dfb0589e..74e30d29e 100644 --- a/src/client/app/common/views/components/messaging-room.form.vue +++ b/src/client/app/common/views/components/messaging-room.form.vue @@ -158,7 +158,7 @@ export default Vue.extend({ }, upload(file) { - (this.$refs.uploader as any).upload(file); + (this.$refs.uploader as any).upload(file, this.$store.state.settings.uploadFolder); }, onUploaded(file) { diff --git a/src/client/app/common/views/pages/page/page.block.vue b/src/client/app/common/views/components/page/page.block.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.block.vue rename to src/client/app/common/views/components/page/page.block.vue diff --git a/src/client/app/common/views/pages/page/page.button.vue b/src/client/app/common/views/components/page/page.button.vue similarity index 88% rename from src/client/app/common/views/pages/page/page.button.vue rename to src/client/app/common/views/components/page/page.button.vue index d3f030762..87112aca0 100644 --- a/src/client/app/common/views/pages/page/page.button.vue +++ b/src/client/app/common/views/components/page/page.button.vue @@ -30,7 +30,10 @@ export default Vue.extend({ } else if (this.value.action === 'pushEvent') { this.$root.api('page-push', { pageId: this.script.page.id, - event: this.value.event + event: this.value.event, + ...(this.value.var ? { + var: this.script.vars[this.value.var] + } : {}) }); this.$root.dialog({ @@ -46,7 +49,7 @@ export default Vue.extend({ diff --git a/src/client/app/common/views/pages/page/page.counter.vue b/src/client/app/common/views/components/page/page.counter.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.counter.vue rename to src/client/app/common/views/components/page/page.counter.vue diff --git a/src/client/app/common/views/pages/page/page.if.vue b/src/client/app/common/views/components/page/page.if.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.if.vue rename to src/client/app/common/views/components/page/page.if.vue diff --git a/src/client/app/common/views/pages/page/page.image.vue b/src/client/app/common/views/components/page/page.image.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.image.vue rename to src/client/app/common/views/components/page/page.image.vue diff --git a/src/client/app/common/views/pages/page/page.number-input.vue b/src/client/app/common/views/components/page/page.number-input.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.number-input.vue rename to src/client/app/common/views/components/page/page.number-input.vue diff --git a/src/client/app/common/views/pages/page/page.post.vue b/src/client/app/common/views/components/page/page.post.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.post.vue rename to src/client/app/common/views/components/page/page.post.vue diff --git a/src/client/app/common/views/pages/page/page.section.vue b/src/client/app/common/views/components/page/page.section.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.section.vue rename to src/client/app/common/views/components/page/page.section.vue diff --git a/src/client/app/common/views/pages/page/page.switch.vue b/src/client/app/common/views/components/page/page.switch.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.switch.vue rename to src/client/app/common/views/components/page/page.switch.vue diff --git a/src/client/app/common/views/pages/page/page.text-input.vue b/src/client/app/common/views/components/page/page.text-input.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.text-input.vue rename to src/client/app/common/views/components/page/page.text-input.vue diff --git a/src/client/app/common/views/pages/page/page.text.vue b/src/client/app/common/views/components/page/page.text.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.text.vue rename to src/client/app/common/views/components/page/page.text.vue diff --git a/src/client/app/common/views/pages/page/page.textarea-input.vue b/src/client/app/common/views/components/page/page.textarea-input.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.textarea-input.vue rename to src/client/app/common/views/components/page/page.textarea-input.vue diff --git a/src/client/app/common/views/pages/page/page.textarea.vue b/src/client/app/common/views/components/page/page.textarea.vue similarity index 100% rename from src/client/app/common/views/pages/page/page.textarea.vue rename to src/client/app/common/views/components/page/page.textarea.vue diff --git a/src/client/app/common/views/pages/page/page.vue b/src/client/app/common/views/components/page/page.vue similarity index 72% rename from src/client/app/common/views/pages/page/page.vue rename to src/client/app/common/views/components/page/page.vue index a93d5316d..99e627fd8 100644 --- a/src/client/app/common/views/pages/page/page.vue +++ b/src/client/app/common/views/components/page/page.vue @@ -1,6 +1,6 @@ @@ -26,7 +32,8 @@ export default Vue.extend({ return { fetching: true, usage: null, - capacity: null + capacity: null, + uploadFolderName: null }; }, @@ -40,10 +47,25 @@ export default Vue.extend({ l: 0.5 }) }; - } + }, + + uploadFolder: { + get() { return this.$store.state.settings.uploadFolder; }, + set(value) { this.$store.dispatch('settings/set', { key: 'uploadFolder', value }); } + }, }, mounted() { + if (this.uploadFolder == null) { + this.uploadFolderName = this.$t('@._settings.root'); + } else { + this.$root.api('drive/folders/show', { + folderId: this.uploadFolder + }).then(folder => { + this.uploadFolderName = folder.name; + }); + } + this.$root.api('drive').then(info => { this.capacity = info.capacity; this.usage = info.usage; @@ -89,6 +111,9 @@ export default Vue.extend({ height: 150, zoom: { enabled: false + }, + toolbar: { + show: false } }, plotOptions: { @@ -152,6 +177,13 @@ export default Vue.extend({ chart.render(); }); + }, + + chooseUploadFolder() { + this.$chooseDriveFolder().then(folder => { + this.uploadFolder = folder ? folder.id : null; + this.uploadFolderName = folder ? folder.name : this.$t('@._settings.root'); + }) } } }); diff --git a/src/client/app/common/views/deck/deck.notification.vue b/src/client/app/common/views/deck/deck.notification.vue index 522f9b0d3..e1d966900 100644 --- a/src/client/app/common/views/deck/deck.notification.vue +++ b/src/client/app/common/views/deck/deck.notification.vue @@ -12,7 +12,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -74,7 +74,7 @@ - + diff --git a/src/client/app/common/views/deck/deck.page-column.vue b/src/client/app/common/views/deck/deck.page-column.vue new file mode 100644 index 000000000..0ef391a51 --- /dev/null +++ b/src/client/app/common/views/deck/deck.page-column.vue @@ -0,0 +1,69 @@ + + + diff --git a/src/client/app/common/views/deck/deck.user-column.home.vue b/src/client/app/common/views/deck/deck.user-column.home.vue index 56b117a7d..9fb50a667 100644 --- a/src/client/app/common/views/deck/deck.user-column.home.vue +++ b/src/client/app/common/views/deck/deck.user-column.home.vue @@ -1,5 +1,11 @@ @@ -73,6 +76,14 @@ export default Vue.extend({ text: this.$t('@.delete'), icon: ['far', 'trash-alt'], action: this.deleteFolder + }, null, { + type: 'nest', + text: this.$t('contextmenu.else-folders'), + menu: [{ + type: 'item', + text: this.$t('contextmenu.set-as-upload-folder'), + action: this.setAsUploadFolder + }] }], { closed: () => { this.isContextmenuShowing = false; @@ -213,8 +224,37 @@ export default Vue.extend({ deleteFolder() { this.$root.api('drive/folders/delete', { folderId: this.folder.id + }).then(() => { + if (this.$store.state.settings.uploadFolder === this.folder.id) { + this.$store.dispatch('settings/set', { + key: 'uploadFolder', + value: null + }); + } + }).catch(err => { + switch(err.id) { + case 'b0fc8a17-963c-405d-bfbc-859a487295e1': + this.$root.dialog({ + type: 'error', + title: this.$t('unable-to-delete'), + text: this.$t('has-child-files-or-folders') + }); + break; + default: + this.$root.dialog({ + type: 'error', + text: this.$t('unable-to-delete') + }); + } }); - } + }, + + setAsUploadFolder() { + this.$store.dispatch('settings/set', { + key: 'uploadFolder', + value: this.folder.id + }); + }, } }); @@ -264,4 +304,10 @@ export default Vue.extend({ margin-left 2px text-align left + > .upload + margin 4px 4px + font-size 0.8em + text-align right + color var(--desktopDriveFolderFg) + diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue index aa8b02399..b25f122e0 100644 --- a/src/client/app/desktop/views/components/notifications.vue +++ b/src/client/app/desktop/views/components/notifications.vue @@ -24,7 +24,7 @@

- + @@ -40,7 +40,7 @@

- + @@ -118,7 +118,7 @@

- + diff --git a/src/client/app/desktop/views/home/user/user.home.vue b/src/client/app/desktop/views/home/user/user.home.vue index ec533efd3..c47e0a077 100644 --- a/src/client/app/desktop/views/home/user/user.home.vue +++ b/src/client/app/desktop/views/home/user/user.home.vue @@ -1,5 +1,6 @@