From 2da92fcd134712273384006a25e051d8593a4472 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Tue, 6 Sep 2022 19:25:03 +0000 Subject: [PATCH] editing (#158) Co-authored-by: Sean King Co-authored-by: Tusooa Zhu Co-authored-by: FloatingGhost Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/158 --- CONTRIBUTORS.md | 2 + src/App.js | 5 ++ src/App.vue | 2 + src/boot/after_store.js | 1 + src/components/attachment/attachment.js | 3 + src/components/conversation/conversation.js | 16 +++- .../edit_status_modal/edit_status_modal.js | 75 ++++++++++++++++ .../edit_status_modal/edit_status_modal.vue | 48 +++++++++++ src/components/extra_buttons/extra_buttons.js | 31 ++++++- .../extra_buttons/extra_buttons.vue | 22 +++++ .../post_status_form/post_status_form.js | 51 ++++++++--- .../post_status_form/post_status_form.vue | 18 ++++ src/components/status/status.js | 6 ++ src/components/status/status.scss | 3 +- src/components/status/status.vue | 24 ++++++ .../status_history_modal.js | 60 +++++++++++++ .../status_history_modal.vue | 46 ++++++++++ src/i18n/en.json | 7 ++ src/main.js | 6 +- src/modules/api.js | 7 ++ src/modules/editStatus.js | 25 ++++++ src/modules/statusHistory.js | 25 ++++++ src/modules/statuses.js | 9 ++ src/services/api/api.service.js | 85 ++++++++++++++++++- .../entity_normalizer.service.js | 16 ++++ .../status_poster/status_poster.service.js | 42 +++++++++ 26 files changed, 616 insertions(+), 19 deletions(-) create mode 100644 src/components/edit_status_modal/edit_status_modal.js create mode 100644 src/components/edit_status_modal/edit_status_modal.vue create mode 100644 src/components/status_history_modal/status_history_modal.js create mode 100644 src/components/status_history_modal/status_history_modal.vue create mode 100644 src/modules/editStatus.js create mode 100644 src/modules/statusHistory.js diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index f666a4ef..bfc41ac4 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -10,3 +10,5 @@ Contributors of this project. - shpuld (shpuld@shitposter.club): CSS and styling - Vincent Guth (https://unsplash.com/photos/XrwVIFy6rTw): Background images. - hj (hj@shigusegubu.club): Code +- Sean King (seanking@freespeechextremist.com): Code +- Tusooa Zhu (tusooa@kazv.moe): Code diff --git a/src/App.js b/src/App.js index 4304787f..3690b944 100644 --- a/src/App.js +++ b/src/App.js @@ -10,7 +10,9 @@ import MobilePostStatusButton from './components/mobile_post_status_button/mobil import MobileNav from './components/mobile_nav/mobile_nav.vue' import DesktopNav from './components/desktop_nav/desktop_nav.vue' import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue' +import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue' import PostStatusModal from './components/post_status_modal/post_status_modal.vue' +import StatusHistoryModal from './components/status_history_modal/status_history_modal.vue' import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue' import { windowWidth, windowHeight } from './services/window_utils/window_utils' import { mapGetters } from 'vuex' @@ -33,6 +35,8 @@ export default { SettingsModal, UserReportingModal, PostStatusModal, + EditStatusModal, + StatusHistoryModal, GlobalNoticeList }, data: () => ({ @@ -83,6 +87,7 @@ export default { return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile' }, showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }, + editingAvailable () { return this.$store.state.instance.editingAvailable }, layoutType () { return this.$store.state.interface.layoutType }, privateMode () { return this.$store.state.instance.private }, reverseLayout () { diff --git a/src/App.vue b/src/App.vue index ed4f318e..e1c0f5dc 100644 --- a/src/App.vue +++ b/src/App.vue @@ -58,6 +58,8 @@ + + diff --git a/src/boot/after_store.js b/src/boot/after_store.js index d7c549d6..c12c70f1 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -273,6 +273,7 @@ const getNodeInfo = async ({ store }) => { store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') }) store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') }) store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') }) + store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') }) store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits }) store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled }) store.dispatch('setInstanceOption', { name: 'translationEnabled', value: features.includes('akkoma:machine_translation') }) diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js index 5450f7a1..0568c6e2 100644 --- a/src/components/attachment/attachment.js +++ b/src/components/attachment/attachment.js @@ -132,6 +132,9 @@ const Attachment = { ...mapGetters(['mergedConfig']) }, watch: { + 'attachment.description' (newVal) { + this.localDescription = newVal + }, localDescription (newVal) { this.onEdit(newVal) } diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js index 2ef2977a..f8df9eb5 100644 --- a/src/components/conversation/conversation.js +++ b/src/components/conversation/conversation.js @@ -1,6 +1,8 @@ import { reduce, filter, findIndex, clone, get } from 'lodash' import Status from '../status/status.vue' import ThreadTree from '../thread_tree/thread_tree.vue' +import { WSConnectionStatus } from '../../services/api/api.service.js' +import { mapGetters, mapState } from 'vuex' import { library } from '@fortawesome/fontawesome-svg-core' import { @@ -77,6 +79,9 @@ const conversation = { const maxDepth = this.$store.getters.mergedConfig.maxDepthInThread - 2 return maxDepth >= 1 ? maxDepth : 1 }, + streamingEnabled () { + return this.mergedConfig.useStreamingApi && this.mastoUserSocketStatus === WSConnectionStatus.JOINED + }, displayStyle () { return this.$store.getters.mergedConfig.conversationDisplay }, @@ -339,7 +344,11 @@ const conversation = { }, maybeHighlight () { return this.isExpanded ? this.highlight : null - } + }, + ...mapGetters(['mergedConfig']), + ...mapState({ + mastoUserSocketStatus: state => state.api.mastoUserSocketStatus + }) }, components: { Status, @@ -395,6 +404,11 @@ const conversation = { setHighlight (id) { if (!id) return this.highlight = id + + if (!this.streamingEnabled) { + this.$store.dispatch('fetchStatus', id) + } + this.$store.dispatch('fetchFavsAndRepeats', id) this.$store.dispatch('fetchEmojiReactionsBy', id) }, diff --git a/src/components/edit_status_modal/edit_status_modal.js b/src/components/edit_status_modal/edit_status_modal.js new file mode 100644 index 00000000..75adfea7 --- /dev/null +++ b/src/components/edit_status_modal/edit_status_modal.js @@ -0,0 +1,75 @@ +import PostStatusForm from '../post_status_form/post_status_form.vue' +import Modal from '../modal/modal.vue' +import statusPosterService from '../../services/status_poster/status_poster.service.js' +import get from 'lodash/get' + +const EditStatusModal = { + components: { + PostStatusForm, + Modal + }, + data () { + return { + resettingForm: false + } + }, + computed: { + isLoggedIn () { + return !!this.$store.state.users.currentUser + }, + modalActivated () { + return this.$store.state.editStatus.modalActivated + }, + isFormVisible () { + return this.isLoggedIn && !this.resettingForm && this.modalActivated + }, + params () { + return this.$store.state.editStatus.params || {} + } + }, + watch: { + params (newVal, oldVal) { + if (get(newVal, 'statusId') !== get(oldVal, 'statusId')) { + this.resettingForm = true + this.$nextTick(() => { + this.resettingForm = false + }) + } + }, + isFormVisible (val) { + if (val) { + this.$nextTick(() => this.$el && this.$el.querySelector('textarea').focus()) + } + } + }, + methods: { + doEditStatus ({ status, spoilerText, sensitive, media, contentType, poll }) { + const params = { + store: this.$store, + statusId: this.$store.state.editStatus.params.statusId, + status, + spoilerText, + sensitive, + poll, + media, + contentType + } + + return statusPosterService.editStatus(params) + .then((data) => { + return data + }) + .catch((err) => { + console.error('Error editing status', err) + return { + error: err.message + } + }) + }, + closeModal () { + this.$store.dispatch('closeEditStatusModal') + } + } +} + +export default EditStatusModal diff --git a/src/components/edit_status_modal/edit_status_modal.vue b/src/components/edit_status_modal/edit_status_modal.vue new file mode 100644 index 00000000..00dde7de --- /dev/null +++ b/src/components/edit_status_modal/edit_status_modal.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js index 042a96a1..f24e261b 100644 --- a/src/components/extra_buttons/extra_buttons.js +++ b/src/components/extra_buttons/extra_buttons.js @@ -7,7 +7,8 @@ import { faEyeSlash, faThumbtack, faShareAlt, - faExternalLinkAlt + faExternalLinkAlt, + faHistory } from '@fortawesome/free-solid-svg-icons' import { faBookmark as faBookmarkReg, @@ -22,7 +23,8 @@ library.add( faThumbtack, faShareAlt, faExternalLinkAlt, - faFlag + faFlag, + faHistory ) const ExtraButtons = { @@ -101,6 +103,25 @@ const ExtraButtons = { }, reportStatus () { this.$store.dispatch('openUserReportingModal', { userId: this.status.user.id, statusIds: [this.status.id] }) + }, + editStatus () { + this.$store.dispatch('fetchStatusSource', { id: this.status.id }) + .then(data => this.$store.dispatch('openEditStatusModal', { + statusId: this.status.id, + subject: data.spoiler_text, + statusText: data.text, + statusIsSensitive: this.status.nsfw, + statusPoll: this.status.poll, + statusFiles: [...this.status.attachments], + visibility: this.status.visibility, + statusContentType: data.content_type + })) + }, + showStatusHistory () { + const originalStatus = { ...this.status } + const stripFieldsList = ['attachments', 'created_at', 'emojis', 'text', 'raw_html', 'nsfw', 'poll', 'summary', 'summary_raw_html'] + stripFieldsList.forEach(p => delete originalStatus[p]) + this.$store.dispatch('openStatusHistoryModal', originalStatus) } }, computed: { @@ -134,7 +155,11 @@ const ExtraButtons = { }, shouldConfirmDelete () { return this.$store.getters.mergedConfig.modalOnDelete - } + }, + isEdited () { + return this.status.edited_at !== null + }, + editingAvailable () { return this.$store.state.instance.editingAvailable } } } diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index b1cbe8dc..a15f0bf2 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -73,6 +73,28 @@ icon="bookmark" />{{ $t("status.unbookmark") }} + +