From 93a87b56460393033ee672d31e8da12d57739395 Mon Sep 17 00:00:00 2001 From: newt Date: Tue, 22 Feb 2022 13:27:12 +0000 Subject: [PATCH 0001/1092] Add status check. --- src/services/entity_normalizer/entity_normalizer.service.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index f219c161f..bd7f7ea5c 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -380,7 +380,9 @@ export const parseNotification = (data) => { if (masto) { output.type = mastoDict[data.type] || data.type output.seen = data.pleroma.is_seen - output.status = isStatusNotification(output.type) ? parseStatus(data.status) : null + // TODO: null check should be a temporary fix, I guess. + // Investigate why backend does this. + output.status = isStatusNotification(output.type) && data.status !== null ? parseStatus(data.status) : null output.action = output.status // TODO: Refactor, this is unneeded output.target = output.type !== 'move' ? null From 1bf256b34b020622718d4dcdcae4153a6f75e060 Mon Sep 17 00:00:00 2001 From: Xnuk Shuman Date: Tue, 20 Dec 2022 02:03:35 +0900 Subject: [PATCH 0002/1092] use normal checkbox component label in announcement --- src/components/announcement_editor/announcement_editor.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/announcement_editor/announcement_editor.vue b/src/components/announcement_editor/announcement_editor.vue index 0f29f9f70..32b05bb20 100644 --- a/src/components/announcement_editor/announcement_editor.vue +++ b/src/components/announcement_editor/announcement_editor.vue @@ -32,8 +32,9 @@ id="announcement-all-day" v-model="announcement.allDay" :disabled="disabled" - /> - + > + {{ $t('announcements.all_day_prompt') }} + From f8a0cd2dd3e298b2a771d786033a7c29df8dcbfc Mon Sep 17 00:00:00 2001 From: Xnuk Shuman Date: Tue, 20 Dec 2022 02:34:11 +0900 Subject: [PATCH 0003/1092] vertical centering the checkbox --- src/components/checkbox/checkbox.vue | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue index b6768d67f..d7839e822 100644 --- a/src/components/checkbox/checkbox.vue +++ b/src/components/checkbox/checkbox.vue @@ -39,20 +39,23 @@ export default { display: inline-block; min-height: 1.2em; + & > * { + vertical-align: middle; + } + &-indicator { + display: inline-block; position: relative; - padding-left: 1.2em; + width: 1.2em; + height: 1.2em; } &-indicator::before { position: absolute; - right: 0; - top: 0; + inset: 0; display: block; content: '✓'; transition: color 200ms; - width: 1.1em; - height: 1.1em; border-radius: $fallback--checkboxRadius; border-radius: var(--checkboxRadius, $fallback--checkboxRadius); box-shadow: 0px 0px 2px black inset; From 7d90c594fe9530e8f483c6912ffcb80319934a8c Mon Sep 17 00:00:00 2001 From: tusooa Date: Fri, 6 Jan 2023 13:52:49 -0500 Subject: [PATCH 0004/1092] Make in-reply-to i18n-friendly --- src/components/status/status.vue | 83 ++++++++++++++++++-------------- src/i18n/en.json | 2 + 2 files changed, 50 insertions(+), 35 deletions(-) diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 82eb7ac61..2a3946101 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -257,44 +257,57 @@ v-if="isReply" class="glued-label reply-glued-label" > - - - + + - - {{ $t('status.reply_to') }} - - + + {{ $t('status.reply_to') }} + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index 1ee1147ad..e98b1d4c5 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -853,6 +853,8 @@ "unbookmark": "Unbookmark", "delete_confirm": "Do you really want to delete this status?", "reply_to": "Reply to", + "reply_to_with_icon": "{icon} {replyTo}", + "reply_to_with_arg": "{replyToWithIcon} {user}", "mentions": "Mentions", "replies_list": "Replies:", "replies_list_with_others": "Replies (+{numReplies} other): | Replies (+{numReplies} others):", From 5b56b6b9fdd9ad82a8f1c24d03024be0e7902c80 Mon Sep 17 00:00:00 2001 From: tusooa Date: Tue, 17 Jan 2023 19:55:16 -0500 Subject: [PATCH 0005/1092] Populate user card on receiving chats --- src/modules/chats.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/chats.js b/src/modules/chats.js index f28c26039..0f1540db2 100644 --- a/src/modules/chats.js +++ b/src/modules/chats.js @@ -65,6 +65,7 @@ const chats = { const newChatMessageSideEffects = (chat) => { maybeShowChatNotification(store, chat) } + commit('addNewUsers', chats.map(k => k.account).filter(k => k)) commit('addNewChats', { dispatch, chats, rootGetters, newChatMessageSideEffects }) }, updateChat ({ commit }, { chat }) { From d1876503bc560b9c62d03e219021593cb954fcf4 Mon Sep 17 00:00:00 2001 From: tusooa Date: Fri, 20 Jan 2023 12:33:19 -0500 Subject: [PATCH 0006/1092] Display delete status errors --- src/i18n/en.json | 1 + src/modules/statuses.js | 14 ++++++++++++-- src/services/api/api.service.js | 5 +++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/i18n/en.json b/src/i18n/en.json index 1ee1147ad..5e653ad8c 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -844,6 +844,7 @@ "favorites": "Favorites", "repeats": "Repeats", "delete": "Delete status", + "delete_error": "Error deleting status: {0}", "edit": "Edit status", "edited_at": "(last edited {time})", "pin": "Pin on profile", diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 77dd7e1c2..93a4a957c 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -615,9 +615,19 @@ const statuses = { fetchStatusHistory ({ rootState, dispatch }, status) { return apiService.fetchStatusHistory({ status }) }, - deleteStatus ({ rootState, commit }, status) { - commit('setDeleted', { status }) + deleteStatus ({ rootState, commit, dispatch }, status) { apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials }) + .then((_) => { + commit('setDeleted', { status }) + }) + .catch((e) => { + dispatch('pushGlobalNotice', { + level: 'error', + messageKey: 'status.delete_error', + messageArgs: [e.message], + timeout: 5000 + }) + }) }, deleteStatusById ({ rootState, commit }, id) { const status = rootState.statuses.allStatusesObject[id] diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index af12265e8..609f6790a 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -923,8 +923,9 @@ const editStatus = ({ } const deleteStatus = ({ id, credentials }) => { - return fetch(MASTODON_DELETE_URL(id), { - headers: authHeaders(credentials), + return promisedRequest({ + url: MASTODON_DELETE_URL(id), + credentials, method: 'DELETE' }) } From ebf3a2de30e071abd1e76e9992e8d94d6cdfa32a Mon Sep 17 00:00:00 2001 From: Pleroma Renovate Bot Date: Fri, 27 Jan 2023 09:08:52 +0000 Subject: [PATCH 0007/1092] Update dependency cropperjs to v1.5.13 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 557672ea6..8d2833ae6 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "body-scroll-lock": "3.1.5", "chromatism": "3.0.0", "click-outside-vue3": "4.0.1", - "cropperjs": "1.5.12", + "cropperjs": "1.5.13", "escape-html": "1.0.3", "js-cookie": "3.0.1", "localforage": "1.10.0", diff --git a/yarn.lock b/yarn.lock index 85a8155f3..a2393ba1b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3268,10 +3268,10 @@ cosmiconfig@^7.1.0: path-type "^4.0.0" yaml "^1.10.0" -cropperjs@1.5.12: - version "1.5.12" - resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.12.tgz#d9c0db2bfb8c0d769d51739e8f916bbc44e10f50" - integrity sha512-re7UdjE5UnwdrovyhNzZ6gathI4Rs3KGCBSc8HCIjUo5hO42CtzyblmWLj6QWVw7huHyDMfpKxhiO2II77nhDw== +cropperjs@1.5.13: + version "1.5.13" + resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.5.13.tgz#eb1682f01d17c70ed5244317091d745c9a249ef8" + integrity sha512-by7jKAo73y5/Do0K6sxdTKHgndY0NMjG2bEdgeJxycbcmHuCiMXqw8sxy5C5Y5WTOTcDGmbT7Sr5CgKOXR06OA== cross-spawn@7.0.3, cross-spawn@^7.0.2: version "7.0.3" From 1506d2421d9a16867c5d3f39fbbc650952c2849a Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 28 Jan 2023 21:44:24 -0500 Subject: [PATCH 0008/1092] Get rid of * --- src/components/checkbox/checkbox.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue index cbebe5789..6c23d9e48 100644 --- a/src/components/checkbox/checkbox.vue +++ b/src/components/checkbox/checkbox.vue @@ -39,7 +39,7 @@ export default { display: inline-block; min-height: 1.2em; - & > * { + .checkbox-indicator, .label { vertical-align: middle; } From f7daaead6f16d87aef5a6a26fa8f8cfe7f7caf10 Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 28 Jan 2023 21:54:08 -0500 Subject: [PATCH 0009/1092] Fix stylelint --- src/components/checkbox/checkbox.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue index 6c23d9e48..32c8f79cd 100644 --- a/src/components/checkbox/checkbox.vue +++ b/src/components/checkbox/checkbox.vue @@ -39,7 +39,8 @@ export default { display: inline-block; min-height: 1.2em; - .checkbox-indicator, .label { + &-indicator, + & .label { vertical-align: middle; } From 796a006a99cd2ee7dcf7ea4e8e54e8c0ea68bb25 Mon Sep 17 00:00:00 2001 From: Pleroma Renovate Bot Date: Sun, 29 Jan 2023 09:08:07 +0000 Subject: [PATCH 0010/1092] Update dependency qrcode to v1.5.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index df15f5775..a9c07814c 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "parse-link-header": "2.0.0", "phoenix": "1.6.2", "punycode.js": "2.3.0", - "qrcode": "1.5.0", + "qrcode": "1.5.1", "querystring-es3": "0.2.1", "url": "0.11.0", "utf8": "3.0.0", diff --git a/yarn.lock b/yarn.lock index 5693c2aea..fe85b5ea4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7341,10 +7341,10 @@ qjobs@^1.2.0: resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== -qrcode@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b" - integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ== +qrcode@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.1.tgz#0103f97317409f7bc91772ef30793a54cd59f0cb" + integrity sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg== dependencies: dijkstrajs "^1.0.1" encode-utf8 "^1.0.3" From 0dd343f2d40939900d12f8c42c5c7d4d6be97f63 Mon Sep 17 00:00:00 2001 From: Brian Underwood Date: Tue, 7 Feb 2023 21:48:57 +0100 Subject: [PATCH 0011/1092] Specs for the gallery component --- test/unit/specs/components/gallery.spec.js | 276 +++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 test/unit/specs/components/gallery.spec.js diff --git a/test/unit/specs/components/gallery.spec.js b/test/unit/specs/components/gallery.spec.js new file mode 100644 index 000000000..108e2b6bf --- /dev/null +++ b/test/unit/specs/components/gallery.spec.js @@ -0,0 +1,276 @@ +import Gallery from 'src/components/gallery/gallery.vue' + +describe.only('Gallery', () => { + let local + + it('attachments is falsey', () => { + local = { attachments: false } + expect(Gallery.computed.rows.call(local)).to.eql([]) + + local = { attachments: null } + expect(Gallery.computed.rows.call(local)).to.eql([]) + + local = { attachments: undefined } + expect(Gallery.computed.rows.call(local)).to.eql([]) + }) + + it('no attachments', () => { + local = { attachments: [] } + expect(Gallery.computed.rows.call(local)).to.eql([]) + }) + + it('one audio attachment', () => { + local = { + attachments: [ + { mimetype: 'audio/mpeg' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + }) + + it('one image attachment', () => { + local = { + attachments: [ + { mimetype: 'image/png' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/png' }] } + ]) + }) + + it('one audio attachment and one image attachment', () => { + local = { + attachments: [ + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }] } + ]) + }) + + it('has "size" key set to "hide"', () => { + let local + local = { + attachments: [ + { mimetype: 'audio/mpeg' } + ], + size: 'hide' + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { minimal: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' } + ], + size: 'hide' + } + + // When defining `size: hide`, the `items` aren't + // grouped and `audio` isn't set + expect(Gallery.computed.rows.call(local)).to.eql([ + { minimal: true, items: [{ mimetype: 'image/jpg' }] }, + { minimal: true, items: [{ mimetype: 'image/png' }] }, + { minimal: true, items: [{ mimetype: 'image/jpg' }] }, + { minimal: true, items: [{ mimetype: 'audio/mpeg' }] }, + { minimal: true, items: [{ mimetype: 'image/png' }] }, + { minimal: true, items: [{ mimetype: 'audio/mpeg' }] }, + { minimal: true, items: [{ mimetype: 'image/jpg' }] }, + { minimal: true, items: [{ mimetype: 'image/png' }] }, + { minimal: true, items: [{ mimetype: 'image/jpg' }] } + ]) + }) + + // types other than image or audio should be `minimal` + it('non-image/audio', () => { + let local + local = { + attachments: [ + { mimetype: 'plain/text' } + ] + } + expect(Gallery.computed.rows.call(local)).to.eql([ + { minimal: true, items: [{ mimetype: 'plain/text' }] } + ]) + + // No grouping of non-image/audio items + local = { + attachments: [ + { mimetype: 'plain/text' }, + { mimetype: 'plain/text' }, + { mimetype: 'plain/text' } + ] + } + expect(Gallery.computed.rows.call(local)).to.eql([ + { minimal: true, items: [{ mimetype: 'plain/text' }] }, + { minimal: true, items: [{ mimetype: 'plain/text' }] }, + { minimal: true, items: [{ mimetype: 'plain/text' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/png' }, + { mimetype: 'plain/text' }, + { mimetype: 'image/jpg' }, + { mimetype: 'audio/mpeg' } + ] + } + // NOTE / TODO: When defining `size: hide`, the `items` aren't + // grouped and `audio` isn't set + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/png' }] }, + { minimal: true, items: [{ mimetype: 'plain/text' }] }, + { items: [{ mimetype: 'image/jpg' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + }) + + it('mixed attachments', () => { + local = { + attachments: [ + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }, { mimetype: 'image/jpg' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'audio/mpeg' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }] }, + { items: [{ mimetype: 'image/jpg' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' } + ] + } + + // Group by three-per-row, unless there's one dangling, then stick it on the end of the last row + // https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1785#note_98514 + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }] }, + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }] } + ]) + + local = { + attachments: [ + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' } + ] + } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/jpg' }] }, + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }, { mimetype: 'image/png' }] }, + { items: [{ mimetype: 'image/jpg' }, { mimetype: 'image/png' }] } + ]) + }) + + it('does not do grouping when grid is set', () => { + const attachments = [ + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'image/jpg' } + ] + + local = { grid: true, attachments } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { grid: true, items: attachments } + ]) + }) + + it('limit is set', () => { + const attachments = [ + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/png' }, + { mimetype: 'image/jpg' }, + { mimetype: 'audio/mpeg' }, + { mimetype: 'image/jpg' } + ] + + let local + local = { attachments, limit: 2 } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }] } + ]) + + local = { attachments, limit: 3 } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }, { mimetype: 'image/jpg' }] } + ]) + + local = { attachments, limit: 4 } + + expect(Gallery.computed.rows.call(local)).to.eql([ + { audio: true, items: [{ mimetype: 'audio/mpeg' }] }, + { items: [{ mimetype: 'image/png' }, { mimetype: 'image/jpg' }] }, + { audio: true, items: [{ mimetype: 'audio/mpeg' }] } + ]) + }) +}) From e516eee479cf6e943b6fc43d0a9d18793c141ba0 Mon Sep 17 00:00:00 2001 From: tusooa Date: Tue, 21 Feb 2023 00:39:16 -0500 Subject: [PATCH 0012/1092] Make block & mute lists able to load more --- src/components/list/list.vue | 6 ++- .../tabs/mutes_and_blocks_tab.js | 7 +++- src/hocs/with_load_more/with_load_more.jsx | 2 +- src/modules/users.js | 38 ++++++++++++++++--- src/services/api/api.service.js | 16 ++++++-- 5 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/components/list/list.vue b/src/components/list/list.vue index f17766b47..a3562c5d7 100644 --- a/src/components/list/list.vue +++ b/src/components/list/list.vue @@ -1,9 +1,13 @@ diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js index 3da559fe2..8aa5f54b5 100644 --- a/src/components/settings_modal/helpers/choice_setting.js +++ b/src/components/settings_modal/helpers/choice_setting.js @@ -1,51 +1,20 @@ -import { get, set } from 'lodash' import Select from 'src/components/select/select.vue' import ModifiedIndicator from './modified_indicator.vue' -import ServerSideIndicator from './server_side_indicator.vue' +import ProfileSettingIndicator from './profile_setting_indicator.vue' +import Setting from './setting.js' + export default { components: { Select, ModifiedIndicator, - ServerSideIndicator + ProfileSettingIndicator }, - props: [ - 'path', - 'disabled', - 'options', - 'expert' - ], - computed: { - pathDefault () { - const [firstSegment, ...rest] = this.path.split('.') - return [firstSegment + 'DefaultValue', ...rest].join('.') - }, - state () { - const value = get(this.$parent, this.path) - if (value === undefined) { - return this.defaultState - } else { - return value - } - }, - defaultState () { - return get(this.$parent, this.pathDefault) - }, - isServerSide () { - return this.path.startsWith('serverSide_') - }, - isChanged () { - return !this.path.startsWith('serverSide_') && this.state !== this.defaultState - }, - matchesExpertLevel () { - return (this.expert || 0) <= this.$parent.expertLevel - } - }, - methods: { - update (e) { - set(this.$parent, this.path, e) - }, - reset () { - set(this.$parent, this.path, this.defaultState) + ...Setting, + props: { + ...Setting.props, + options: { + type: Array, + required: true } } } diff --git a/src/components/settings_modal/helpers/choice_setting.vue b/src/components/settings_modal/helpers/choice_setting.vue index 8fdbb5d34..4c4cdefec 100644 --- a/src/components/settings_modal/helpers/choice_setting.vue +++ b/src/components/settings_modal/helpers/choice_setting.vue @@ -23,7 +23,7 @@ :changed="isChanged" :onclick="reset" /> - + diff --git a/src/components/settings_modal/helpers/integer_setting.js b/src/components/settings_modal/helpers/integer_setting.js index e64d0cee2..0f29f11aa 100644 --- a/src/components/settings_modal/helpers/integer_setting.js +++ b/src/components/settings_modal/helpers/integer_setting.js @@ -1,44 +1,15 @@ -import { get, set } from 'lodash' import ModifiedIndicator from './modified_indicator.vue' +import Setting from './setting.js' + export default { components: { ModifiedIndicator }, - props: { - path: String, - disabled: Boolean, - min: Number, - expert: [Number, String] - }, - computed: { - pathDefault () { - const [firstSegment, ...rest] = this.path.split('.') - return [firstSegment + 'DefaultValue', ...rest].join('.') - }, - state () { - const value = get(this.$parent, this.path) - if (value === undefined) { - return this.defaultState - } else { - return value - } - }, - defaultState () { - return get(this.$parent, this.pathDefault) - }, - isChanged () { - return this.state !== this.defaultState - }, - matchesExpertLevel () { - return (this.expert || 0) <= this.$parent.expertLevel - } - }, + ...Setting, methods: { + ...Setting.methods, update (e) { - set(this.$parent, this.path, parseInt(e.target.value)) - }, - reset () { - set(this.$parent, this.path, this.defaultState) + this.configSink(this.path, parseInt(e.target.value)) } } } diff --git a/src/components/settings_modal/helpers/server_side_indicator.vue b/src/components/settings_modal/helpers/profile_setting_indicator.vue similarity index 81% rename from src/components/settings_modal/helpers/server_side_indicator.vue rename to src/components/settings_modal/helpers/profile_setting_indicator.vue index bf181959f..d160781b1 100644 --- a/src/components/settings_modal/helpers/server_side_indicator.vue +++ b/src/components/settings_modal/helpers/profile_setting_indicator.vue @@ -1,7 +1,7 @@ @@ -33,17 +33,17 @@ library.add( export default { components: { Popover }, - props: ['serverSide'] + props: ['isProfile'] } diff --git a/src/components/admin_modal/admin_modal_content.js b/src/components/admin_modal/admin_modal_content.js new file mode 100644 index 000000000..897cc163f --- /dev/null +++ b/src/components/admin_modal/admin_modal_content.js @@ -0,0 +1,88 @@ +import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' + +import DataImportExportTab from './tabs/data_import_export_tab.vue' +import MutesAndBlocksTab from './tabs/mutes_and_blocks_tab.vue' +import NotificationsTab from './tabs/notifications_tab.vue' +import FilteringTab from './tabs/filtering_tab.vue' +import SecurityTab from './tabs/security_tab/security_tab.vue' +import ProfileTab from './tabs/profile_tab.vue' +import GeneralTab from './tabs/general_tab.vue' +import VersionTab from './tabs/version_tab.vue' +import ThemeTab from './tabs/theme_tab/theme_tab.vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faWrench, + faUser, + faFilter, + faPaintBrush, + faBell, + faDownload, + faEyeSlash, + faInfo +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faWrench, + faUser, + faFilter, + faPaintBrush, + faBell, + faDownload, + faEyeSlash, + faInfo +) + +const AdminModalContent = { + components: { + TabSwitcher, + + DataImportExportTab, + MutesAndBlocksTab, + NotificationsTab, + FilteringTab, + SecurityTab, + ProfileTab, + GeneralTab, + VersionTab, + ThemeTab + }, + computed: { + isLoggedIn () { + return !!this.$store.state.users.currentUser + }, + open () { + return this.$store.state.interface.AdminModalState !== 'hidden' + }, + bodyLock () { + return this.$store.state.interface.AdminModalState === 'visible' + } + }, + methods: { + onOpen () { + const targetTab = this.$store.state.interface.AdminModalTargetTab + // We're being told to open in specific tab + if (targetTab) { + const tabIndex = this.$refs.tabSwitcher.$slots.default().findIndex(elm => { + return elm.props && elm.props['data-tab-name'] === targetTab + }) + if (tabIndex >= 0) { + this.$refs.tabSwitcher.setTab(tabIndex) + } + } + // Clear the state of target tab, so that next time Admin is opened + // it doesn't force it. + this.$store.dispatch('clearAdminModalTargetTab') + } + }, + mounted () { + this.onOpen() + }, + watch: { + open: function (value) { + if (value) this.onOpen() + } + } +} + +export default AdminModalContent diff --git a/src/components/admin_modal/admin_modal_content.scss b/src/components/admin_modal/admin_modal_content.scss new file mode 100644 index 000000000..2db7b2f86 --- /dev/null +++ b/src/components/admin_modal/admin_modal_content.scss @@ -0,0 +1,56 @@ +@import "src/variables"; + +.admin_tab-switcher { + height: 100%; + + .setting-item { + border-bottom: 2px solid var(--fg, $fallback--fg); + margin: 1em 1em 1.4em; + padding-bottom: 1.4em; + + > div, + > label { + display: block; + margin-bottom: 0.5em; + + &:last-child { + margin-bottom: 0; + } + } + + .select-multiple { + display: flex; + + .option-list { + margin: 0; + padding-left: 0.5em; + } + } + + &:last-child { + border-bottom: none; + padding-bottom: 0; + margin-bottom: 1em; + } + + select { + min-width: 10em; + } + + textarea { + width: 100%; + max-width: 100%; + height: 100px; + } + + .unavailable, + .unavailable svg { + color: var(--cRed, $fallback--cRed); + color: $fallback--cRed; + } + + .number-input { + max-width: 6em; + } + } +} diff --git a/src/components/admin_modal/tabs/general_tab.js b/src/components/admin_modal/tabs/general_tab.js new file mode 100644 index 000000000..8c166f19a --- /dev/null +++ b/src/components/admin_modal/tabs/general_tab.js @@ -0,0 +1,33 @@ +import BooleanSetting from '../settings_modal/helpers/boolean_setting.vue' +import ChoiceSetting from '../settings_modal/helpers/choice_setting.vue' +import IntegerSetting from '../settings_modal/helpers/integer_setting.vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { + faGlobe +} from '@fortawesome/free-solid-svg-icons' + +library.add( + faGlobe +) + +const GeneralTab = { + components: { + BooleanSetting, + ChoiceSetting, + IntegerSetting, + }, + computed: { + mergedConfig () { + console.log(this.$store.state) + return this.$store.state + } + }, + methods: { + changeDefaultScope (value) { + this.$store.dispatch('setProfileOption', { name: 'defaultScope', value }) + } + } +} + +export default GeneralTab diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js index 745b1a815..f6a2e2947 100644 --- a/src/components/desktop_nav/desktop_nav.js +++ b/src/components/desktop_nav/desktop_nav.js @@ -107,7 +107,10 @@ export default { this.searchBarHidden = hidden }, openSettingsModal () { - this.$store.dispatch('openSettingsModal') + this.$store.dispatch('openSettingsModal', 'user') + }, + openAdminModal () { + this.$store.dispatch('openSettingsModal', 'admin') } } } diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue index dc8bbfd38..49382f8ee 100644 --- a/src/components/desktop_nav/desktop_nav.vue +++ b/src/components/desktop_nav/desktop_nav.vue @@ -48,20 +48,19 @@ icon="cog" /> - - +
- + +
diff --git a/src/components/settings_modal/helpers/choice_setting.js b/src/components/settings_modal/helpers/choice_setting.js index a3c3bf443..3ff81bc90 100644 --- a/src/components/settings_modal/helpers/choice_setting.js +++ b/src/components/settings_modal/helpers/choice_setting.js @@ -11,7 +11,32 @@ export default { ...Setting.props, options: { type: Array, - required: true + required: false + }, + optionLabelMap: { + type: Object, + required: false, + default: {} + } + }, + computed: { + ...Setting.computed, + realOptions () { + if (this.source === 'admin') { + console.log(this.backendDescriptionSuggestions) + return this.backendDescriptionSuggestions.map(x => ({ + key: x, + value: x, + label: this.optionLabelMap[x] || x + })) + } + return this.options + } + }, + methods: { + ...Setting.methods, + getValue (e) { + return e } } } diff --git a/src/components/settings_modal/helpers/choice_setting.vue b/src/components/settings_modal/helpers/choice_setting.vue index 4c4cdefec..55f9a62ca 100644 --- a/src/components/settings_modal/helpers/choice_setting.vue +++ b/src/components/settings_modal/helpers/choice_setting.vue @@ -3,15 +3,20 @@ v-if="matchesExpertLevel" class="ChoiceSetting" > - + + {{ ' ' }} + + +

+ {{ backendDescriptionDescription + ' ' }} +

diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js index 8c7074a57..a6d35fb98 100644 --- a/src/components/settings_modal/helpers/setting.js +++ b/src/components/settings_modal/helpers/setting.js @@ -13,7 +13,7 @@ export default { }, props: { path: { - type: String, + type: [String, Array], required: true }, disabled: { @@ -21,7 +21,7 @@ export default { default: false }, parentPath: { - type: String + type: [String, Array] }, parentInvert: { type: Boolean, @@ -68,6 +68,9 @@ export default { backendDescriptionDescription () { return this.backendDescription?.description }, + backendDescriptionSuggestions () { + return this.backendDescription?.suggestions + }, shouldBeDisabled () { const parentValue = this.parentPath !== undefined ? get(this.configSource, this.parentPath) : null return this.disabled || (parentValue !== null ? (this.parentInvert ? parentValue : !parentValue) : false) diff --git a/src/components/settings_modal/helpers/shared_computed_object.js b/src/components/settings_modal/helpers/shared_computed_object.js index 912999ce7..d02db542a 100644 --- a/src/components/settings_modal/helpers/shared_computed_object.js +++ b/src/components/settings_modal/helpers/shared_computed_object.js @@ -7,6 +7,9 @@ const SharedComputedObject = () => ({ }, mergedConfig () { return this.$store.getters.mergedConfig + }, + adminConfig () { + return this.$store.state.adminSettings.config } }) diff --git a/src/modules/adminSettings.js b/src/modules/adminSettings.js index 44a4d409e..a84fadbf9 100644 --- a/src/modules/adminSettings.js +++ b/src/modules/adminSettings.js @@ -29,7 +29,7 @@ const adminSettingsStorage = { const config = state.config || {} const modifiedPaths = state.modifiedPaths || new Set() backendDbConfig.configs.forEach(c => { - const path = c.group + '.' + c.key + const path = [c.group, c.key] if (c.db) { c.db.forEach(x => modifiedPaths.add(path + '.' + x)) } @@ -44,16 +44,16 @@ const adminSettingsStorage = { } set(config, path, convert(c.value)) }) - console.log(config[':pleroma'][':welcome']) + console.log(config[':pleroma']) commit('updateAdminSettings', { config, modifiedPaths }) }, setInstanceAdminDescriptions ({ state, commit, dispatch }, { backendDescriptions }) { const convert = ({ children, description, label, key = '', group, suggestions }, path, acc) => { - const newPath = group ? group + '.' + key : key + const newPath = group ? [group, key] : [key] const obj = { description, label, suggestions } if (Array.isArray(children)) { children.forEach(c => { - convert(c, '.' + newPath, obj) + convert(c, newPath, obj) }) } set(acc, newPath, obj) @@ -61,12 +61,13 @@ const adminSettingsStorage = { const descriptions = {} backendDescriptions.forEach(d => convert(d, '', descriptions)) + console.log(descriptions[':pleroma']['Pleroma.Captcha']) commit('updateAdminDescriptions', { descriptions }) }, pushAdminSetting ({ rootState, state, commit, dispatch }, { path, value }) { - const [group, key, ...rest] = path.split(/\./g) + const [group, key, ...rest] = Array.isArray(path) ? path : path.split(/\./g) const clone = {} // not actually cloning the entire thing to avoid excessive writes - set(clone, rest.join('.'), value) + set(clone, rest, value) // TODO cleanup paths in modifiedPaths const convert = (value) => { From 9a97e0d196c879e41dcb8bda8bd8128a039bacdc Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 21 Mar 2023 10:26:25 +0200 Subject: [PATCH 0025/1092] modal update, initial localization --- .../admin_tabs/instance_tab.vue | 10 +++---- .../settings_modal/admin_tabs/limits_tab.vue | 24 +++++++++-------- .../settings_modal/settings_modal.vue | 15 ++++++++++- .../settings_modal_admin_content.js | 4 +-- .../settings_modal_admin_content.vue | 6 ++--- src/i18n/en.json | 27 +++++++++++++++++++ 6 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/components/settings_modal/admin_tabs/instance_tab.vue b/src/components/settings_modal/admin_tabs/instance_tab.vue index ff784287c..411982cc9 100644 --- a/src/components/settings_modal/admin_tabs/instance_tab.vue +++ b/src/components/settings_modal/admin_tabs/instance_tab.vue @@ -1,7 +1,7 @@ diff --git a/src/components/settings_modal/helpers/draft_buttons.vue b/src/components/settings_modal/helpers/draft_buttons.vue index 53ddc9b4a..9e972b14c 100644 --- a/src/components/settings_modal/helpers/draft_buttons.vue +++ b/src/components/settings_modal/helpers/draft_buttons.vue @@ -5,13 +5,13 @@ class="DraftButtons" > diff --git a/src/components/settings_modal/helpers/group_setting.js b/src/components/settings_modal/helpers/group_setting.js index 12a490007..23a2a2025 100644 --- a/src/components/settings_modal/helpers/group_setting.js +++ b/src/components/settings_modal/helpers/group_setting.js @@ -7,7 +7,6 @@ export default { computed: { ...Setting.computed, isDirty () { - console.log(this.state, this.draft) return !isEqual(this.state, this.draft) } } diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js index d2e1a6f43..4f0be448c 100644 --- a/src/components/settings_modal/helpers/setting.js +++ b/src/components/settings_modal/helpers/setting.js @@ -61,7 +61,7 @@ export default { // TODO allow passing shared draft object? get () { if (this.realSource === 'admin') { - return get(this.$store.state.adminSettings.draft, this.path) + return get(this.$store.state.adminSettings.draft, this.canonPath) } else { return this.localDraft } @@ -75,7 +75,7 @@ export default { } }, state () { - const value = get(this.configSource, this.path) + const value = get(this.configSource, this.canonPath) if (value === undefined) { return this.defaultState } else { diff --git a/src/components/settings_modal/helpers/shared_computed_object.js b/src/components/settings_modal/helpers/shared_computed_object.js index d02db542a..bb3d36ac4 100644 --- a/src/components/settings_modal/helpers/shared_computed_object.js +++ b/src/components/settings_modal/helpers/shared_computed_object.js @@ -10,6 +10,9 @@ const SharedComputedObject = () => ({ }, adminConfig () { return this.$store.state.adminSettings.config + }, + adminDraft () { + return this.$store.state.adminSettings.draft } }) diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss index 98de736bf..49ef83e01 100644 --- a/src/components/settings_modal/settings_modal.scss +++ b/src/components/settings_modal/settings_modal.scss @@ -43,6 +43,9 @@ .btn { min-height: 2em; + } + + .btn:not(.dropdown-button) { padding: 0 2em; } } diff --git a/src/components/settings_modal/settings_modal_admin_content.js b/src/components/settings_modal/settings_modal_admin_content.js index b7c0de576..f94721ec7 100644 --- a/src/components/settings_modal/settings_modal_admin_content.js +++ b/src/components/settings_modal/settings_modal_admin_content.js @@ -51,6 +51,9 @@ const SettingsModalAdminContent = { adminDbLoaded () { return this.$store.state.adminSettings.loaded }, + adminDescriptionsLoaded () { + return this.$store.state.adminSettings.descriptions !== null + }, noDb () { return this.$store.state.adminSettings.dbConfigEnabled === false } diff --git a/src/components/settings_modal/settings_modal_admin_content.vue b/src/components/settings_modal/settings_modal_admin_content.vue index ae670a909..a7a2ac9ad 100644 --- a/src/components/settings_modal/settings_modal_admin_content.vue +++ b/src/components/settings_modal/settings_modal_admin_content.vue @@ -1,5 +1,6 @@