diff --git a/docs/HACKING.md b/docs/HACKING.md
index 7f2964b4..a5c49113 100644
--- a/docs/HACKING.md
+++ b/docs/HACKING.md
@@ -25,7 +25,17 @@ This could be a bit trickier, you basically need steps 1-4 from *develop build*
### Replacing your instance's frontend with custom FE build
-This is the most easiest way to use and test FE build: you just need to copy or symlink contents of `dist` folder into backend's [static directory](../backend/configuration/static_dir.md), by default it is located in `instance/static`, or in `/var/lib/pleroma/static` for OTP release installations, create it if it doesn't exist already. Be aware that running `yarn build` wipes the contents of `dist` folder.
+#### New way (via AdminFE, a bit janky but works)
+
+In backend's [static directory](../backend/configuration/static_dir.md) there should be a folder called `frontends` if you installed any frontends from AdminFE before, otherwise you can create it yourself (ensuring correct permissions). Backend will serve given frontend from path `frontends/{frontend}/{reference}`, where `{frontend}` is name of frontend (`pleroma-fe`) and `{reference}` is version. You could make a production build, move `dist` folder into `frontends/pleroma-fe` and rename it into something like `myCustomVersion`. To actually make backend serve this frontend by default, in AdminFE you'll need to set name/reference in Settings -> Frontend -> Frontends -> Primary.
+
+You could also install from a zip file (i.e. CI build) but AdminFE UI is a bit buggy and lacking, so this approach is not recommended.
+
+Take note that frontend management is in early development and currently there's no way for user to change frontend or version for themselves, primary frontend becomes default frontend for all users and visitors.
+
+#### Old way (replaces everything, hard to maintain, not recommended)
+
+Copy or symlink contents of `dist` folder into backend's [static directory](../backend/configuration/static_dir.md), by default it is located in `instance/static`, or in `/var/lib/pleroma/static` for OTP release installations, create it if it doesn't exist already. Be aware that running `yarn build` wipes the contents of `dist` folder, and this could remove emojis, other frontends etc. and therefore this approach is not recommended.
### Running production build locally or on a separate server
diff --git a/index.html b/index.html
index 4af84a59..a02939f7 100644
--- a/index.html
+++ b/index.html
@@ -9,6 +9,7 @@
To use Pleroma, please enable JavaScript.
+
diff --git a/package.json b/package.json
index 897fda4a..557672ea 100644
--- a/package.json
+++ b/package.json
@@ -72,13 +72,13 @@
"css-loader": "6.7.3",
"css-minimizer-webpack-plugin": "4.2.2",
"custom-event-polyfill": "1.0.7",
- "eslint": "8.31.0",
+ "eslint": "8.32.0",
"eslint-config-standard": "17.0.0",
"eslint-formatter-friendly": "7.0.0",
- "eslint-plugin-import": "2.26.0",
+ "eslint-plugin-import": "2.27.5",
"eslint-plugin-n": "15.6.1",
"eslint-plugin-promise": "6.1.1",
- "eslint-plugin-vue": "9.8.0",
+ "eslint-plugin-vue": "9.9.0",
"eslint-webpack-plugin": "3.2.0",
"eventsource-polyfill": "0.9.6",
"express": "4.18.2",
diff --git a/src/App.vue b/src/App.vue
index 23a388a6..fe214ce7 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -71,7 +71,6 @@
-
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 1fa9dd2a..d2e7f488 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -60,6 +60,8 @@ const getInstanceConfig = async ({ store }) => {
store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit })
store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required })
+ store.dispatch('setInstanceOption', { name: 'birthdayRequired', value: !!data.pleroma.metadata.birthday_required })
+ store.dispatch('setInstanceOption', { name: 'birthdayMinAge', value: data.pleroma.metadata.birthday_min_age || 0 })
if (vapidPublicKey) {
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })
diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js
index c23407f9..acd93e06 100644
--- a/src/components/account_actions/account_actions.js
+++ b/src/components/account_actions/account_actions.js
@@ -2,6 +2,7 @@ import { mapState } from 'vuex'
import ProgressButton from '../progress_button/progress_button.vue'
import Popover from '../popover/popover.vue'
import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue'
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faEllipsisV
@@ -16,14 +17,30 @@ const AccountActions = {
'user', 'relationship'
],
data () {
- return { }
+ return {
+ showingConfirmBlock: false,
+ showingConfirmRemoveFollower: false
+ }
},
components: {
ProgressButton,
Popover,
- UserListMenu
+ UserListMenu,
+ ConfirmModal
},
methods: {
+ showConfirmBlock () {
+ this.showingConfirmBlock = true
+ },
+ hideConfirmBlock () {
+ this.showingConfirmBlock = false
+ },
+ showConfirmRemoveUserFromFollowers () {
+ this.showingConfirmRemoveFollower = true
+ },
+ hideConfirmRemoveUserFromFollowers () {
+ this.showingConfirmRemoveFollower = false
+ },
showRepeats () {
this.$store.dispatch('showReblogs', this.user.id)
},
@@ -31,13 +48,29 @@ const AccountActions = {
this.$store.dispatch('hideReblogs', this.user.id)
},
blockUser () {
+ if (!this.shouldConfirmBlock) {
+ this.doBlockUser()
+ } else {
+ this.showConfirmBlock()
+ }
+ },
+ doBlockUser () {
this.$store.dispatch('blockUser', this.user.id)
+ this.hideConfirmBlock()
},
unblockUser () {
this.$store.dispatch('unblockUser', this.user.id)
},
removeUserFromFollowers () {
+ if (!this.shouldConfirmRemoveUserFromFollowers) {
+ this.doRemoveUserFromFollowers()
+ } else {
+ this.showConfirmRemoveUserFromFollowers()
+ }
+ },
+ doRemoveUserFromFollowers () {
this.$store.dispatch('removeUserFromFollowers', this.user.id)
+ this.hideConfirmRemoveUserFromFollowers()
},
reportUser () {
this.$store.dispatch('openUserReportingModal', { userId: this.user.id })
@@ -50,6 +83,12 @@ const AccountActions = {
}
},
computed: {
+ shouldConfirmBlock () {
+ return this.$store.getters.mergedConfig.modalOnBlock
+ },
+ shouldConfirmRemoveUserFromFollowers () {
+ return this.$store.getters.mergedConfig.modalOnRemoveUserFromFollowers
+ },
...mapState({
pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable
})
diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue
index 973a5935..ce19291a 100644
--- a/src/components/account_actions/account_actions.vue
+++ b/src/components/account_actions/account_actions.vue
@@ -74,6 +74,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/confirm_modal/confirm_modal.js b/src/components/confirm_modal/confirm_modal.js
new file mode 100644
index 00000000..96ddc118
--- /dev/null
+++ b/src/components/confirm_modal/confirm_modal.js
@@ -0,0 +1,37 @@
+import DialogModal from '../dialog_modal/dialog_modal.vue'
+
+/**
+ * This component emits the following events:
+ * cancelled, emitted when the action should not be performed;
+ * accepted, emitted when the action should be performed;
+ *
+ * The caller should close this dialog after receiving any of the two events.
+ */
+const ConfirmModal = {
+ components: {
+ DialogModal
+ },
+ props: {
+ title: {
+ type: String
+ },
+ cancelText: {
+ type: String
+ },
+ confirmText: {
+ type: String
+ }
+ },
+ computed: {
+ },
+ methods: {
+ onCancel () {
+ this.$emit('cancelled')
+ },
+ onAccept () {
+ this.$emit('accepted')
+ }
+ }
+}
+
+export default ConfirmModal
diff --git a/src/components/confirm_modal/confirm_modal.vue b/src/components/confirm_modal/confirm_modal.vue
new file mode 100644
index 00000000..3b98174a
--- /dev/null
+++ b/src/components/confirm_modal/confirm_modal.vue
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js
index 08c0e44e..745b1a81 100644
--- a/src/components/desktop_nav/desktop_nav.js
+++ b/src/components/desktop_nav/desktop_nav.js
@@ -1,4 +1,5 @@
import SearchBar from 'components/search_bar/search_bar.vue'
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faSignInAlt,
@@ -30,7 +31,8 @@ library.add(
export default {
components: {
- SearchBar
+ SearchBar,
+ ConfirmModal
},
data: () => ({
searchBarHidden: true,
@@ -40,7 +42,8 @@ export default {
window.CSS.supports('-moz-mask-size', 'contain') ||
window.CSS.supports('-ms-mask-size', 'contain') ||
window.CSS.supports('-o-mask-size', 'contain')
- )
+ ),
+ showingConfirmLogout: false
}),
computed: {
enableMask () { return this.supportsMask && this.$store.state.instance.logoMask },
@@ -73,15 +76,32 @@ export default {
hideSitename () { return this.$store.state.instance.hideSitename },
logoLeft () { return this.$store.state.instance.logoLeft },
currentUser () { return this.$store.state.users.currentUser },
- privateMode () { return this.$store.state.instance.private }
+ privateMode () { return this.$store.state.instance.private },
+ shouldConfirmLogout () {
+ return this.$store.getters.mergedConfig.modalOnLogout
+ }
},
methods: {
scrollToTop () {
window.scrollTo(0, 0)
},
+ showConfirmLogout () {
+ this.showingConfirmLogout = true
+ },
+ hideConfirmLogout () {
+ this.showingConfirmLogout = false
+ },
logout () {
+ if (!this.shouldConfirmLogout) {
+ this.doLogout()
+ } else {
+ this.showConfirmLogout()
+ }
+ },
+ doLogout () {
this.$router.replace('/main/public')
this.$store.dispatch('logout')
+ this.hideConfirmLogout()
},
onSearchBarToggled (hidden) {
this.searchBarHidden = hidden
diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue
index 07bf8005..92622cf9 100644
--- a/src/components/desktop_nav/desktop_nav.vue
+++ b/src/components/desktop_nav/desktop_nav.vue
@@ -76,6 +76,18 @@
+
+
+ {{ $t('login.logout_confirm') }}
+
+
diff --git a/src/components/dialog_modal/dialog_modal.vue b/src/components/dialog_modal/dialog_modal.vue
index 24d65142..341cf105 100644
--- a/src/components/dialog_modal/dialog_modal.vue
+++ b/src/components/dialog_modal/dialog_modal.vue
@@ -39,7 +39,7 @@
right: 0;
top: 0;
background: rgb(27 31 35 / 50%);
- z-index: 99;
+ z-index: 2000;
}
}
@@ -51,7 +51,7 @@
margin: 15vh auto;
position: fixed;
transform: translateX(-50%);
- z-index: 999;
+ z-index: 2001;
cursor: default;
display: block;
background-color: $fallback--bg;
diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js
index 3dc968c9..48b960b2 100644
--- a/src/components/extra_buttons/extra_buttons.js
+++ b/src/components/extra_buttons/extra_buttons.js
@@ -1,4 +1,5 @@
import Popover from '../popover/popover.vue'
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faEllipsisH,
@@ -32,10 +33,14 @@ library.add(
const ExtraButtons = {
props: ['status'],
- components: { Popover },
+ components: {
+ Popover,
+ ConfirmModal
+ },
data () {
return {
- expanded: false
+ expanded: false,
+ showingDeleteDialog: false
}
},
methods: {
@@ -46,11 +51,22 @@ const ExtraButtons = {
this.expanded = false
},
deleteStatus () {
- const confirmed = window.confirm(this.$t('status.delete_confirm'))
- if (confirmed) {
- this.$store.dispatch('deleteStatus', { id: this.status.id })
+ if (this.shouldConfirmDelete) {
+ this.showDeleteStatusConfirmDialog()
+ } else {
+ this.doDeleteStatus()
}
},
+ doDeleteStatus () {
+ this.$store.dispatch('deleteStatus', { id: this.status.id })
+ this.hideDeleteStatusConfirmDialog()
+ },
+ showDeleteStatusConfirmDialog () {
+ this.showingDeleteDialog = true
+ },
+ hideDeleteStatusConfirmDialog () {
+ this.showingDeleteDialog = false
+ },
pinStatus () {
this.$store.dispatch('pinStatus', this.status.id)
.then(() => this.$emit('onSuccess'))
@@ -133,7 +149,10 @@ const ExtraButtons = {
isEdited () {
return this.status.edited_at !== null
},
- editingAvailable () { return this.$store.state.instance.editingAvailable }
+ editingAvailable () { return this.$store.state.instance.editingAvailable },
+ shouldConfirmDelete () {
+ return this.$store.getters.mergedConfig.modalOnDelete
+ }
}
}
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index a84d47f6..c1c15c0f 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -165,6 +165,18 @@
/>
+
+
+ {{ $t('status.delete_confirm') }}
+
+
diff --git a/src/components/follow_button/follow_button.js b/src/components/follow_button/follow_button.js
index 3edbcb86..443aa9bc 100644
--- a/src/components/follow_button/follow_button.js
+++ b/src/components/follow_button/follow_button.js
@@ -1,12 +1,20 @@
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate'
export default {
props: ['relationship', 'user', 'labelFollowing', 'buttonClass'],
+ components: {
+ ConfirmModal
+ },
data () {
return {
- inProgress: false
+ inProgress: false,
+ showingConfirmUnfollow: false
}
},
computed: {
+ shouldConfirmUnfollow () {
+ return this.$store.getters.mergedConfig.modalOnUnfollow
+ },
isPressed () {
return this.inProgress || this.relationship.following
},
@@ -35,6 +43,12 @@ export default {
}
},
methods: {
+ showConfirmUnfollow () {
+ this.showingConfirmUnfollow = true
+ },
+ hideConfirmUnfollow () {
+ this.showingConfirmUnfollow = false
+ },
onClick () {
this.relationship.following || this.relationship.requested ? this.unfollow() : this.follow()
},
@@ -45,12 +59,21 @@ export default {
})
},
unfollow () {
+ if (this.shouldConfirmUnfollow) {
+ this.showConfirmUnfollow()
+ } else {
+ this.doUnfollow()
+ }
+ },
+ doUnfollow () {
const store = this.$store
this.inProgress = true
requestUnfollow(this.relationship.id, store).then(() => {
this.inProgress = false
store.commit('removeStatus', { timeline: 'friends', userId: this.relationship.id })
})
+
+ this.hideConfirmUnfollow()
}
}
}
diff --git a/src/components/follow_button/follow_button.vue b/src/components/follow_button/follow_button.vue
index 965d5256..e421c15b 100644
--- a/src/components/follow_button/follow_button.vue
+++ b/src/components/follow_button/follow_button.vue
@@ -7,6 +7,27 @@
@click="onClick"
>
{{ label }}
+
+
+
+
+
+
+
+
+
diff --git a/src/components/follow_card/follow_card.vue b/src/components/follow_card/follow_card.vue
index eff69fb2..bdb6b809 100644
--- a/src/components/follow_card/follow_card.vue
+++ b/src/components/follow_card/follow_card.vue
@@ -24,6 +24,7 @@
/>
diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js
index cbd75311..b0873bb1 100644
--- a/src/components/follow_request_card/follow_request_card.js
+++ b/src/components/follow_request_card/follow_request_card.js
@@ -1,10 +1,18 @@
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js'
const FollowRequestCard = {
props: ['user'],
components: {
- BasicUserCard
+ BasicUserCard,
+ ConfirmModal
+ },
+ data () {
+ return {
+ showingApproveConfirmDialog: false,
+ showingDenyConfirmDialog: false
+ }
},
methods: {
findFollowRequestNotificationId () {
@@ -13,7 +21,26 @@ const FollowRequestCard = {
)
return notif && notif.id
},
+ showApproveConfirmDialog () {
+ this.showingApproveConfirmDialog = true
+ },
+ hideApproveConfirmDialog () {
+ this.showingApproveConfirmDialog = false
+ },
+ showDenyConfirmDialog () {
+ this.showingDenyConfirmDialog = true
+ },
+ hideDenyConfirmDialog () {
+ this.showingDenyConfirmDialog = false
+ },
approveUser () {
+ if (this.shouldConfirmApprove) {
+ this.showApproveConfirmDialog()
+ } else {
+ this.doApprove()
+ }
+ },
+ doApprove () {
this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
this.$store.dispatch('removeFollowRequest', this.user)
@@ -25,14 +52,34 @@ const FollowRequestCard = {
notification.type = 'follow'
}
})
+ this.hideApproveConfirmDialog()
},
denyUser () {
+ if (this.shouldConfirmDeny) {
+ this.showDenyConfirmDialog()
+ } else {
+ this.doDeny()
+ }
+ },
+ doDeny () {
const notifId = this.findFollowRequestNotificationId()
this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
.then(() => {
this.$store.dispatch('dismissNotificationLocal', { id: notifId })
this.$store.dispatch('removeFollowRequest', this.user)
})
+ this.hideDenyConfirmDialog()
+ }
+ },
+ computed: {
+ mergedConfig () {
+ return this.$store.getters.mergedConfig
+ },
+ shouldConfirmApprove () {
+ return this.mergedConfig.modalOnApproveFollow
+ },
+ shouldConfirmDeny () {
+ return this.mergedConfig.modalOnDenyFollow
}
}
}
diff --git a/src/components/follow_request_card/follow_request_card.vue b/src/components/follow_request_card/follow_request_card.vue
index eb222cc7..55b65112 100644
--- a/src/components/follow_request_card/follow_request_card.vue
+++ b/src/components/follow_request_card/follow_request_card.vue
@@ -14,6 +14,28 @@
{{ $t('user_card.deny') }}
+
+
+ {{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }}
+
+
+ {{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }}
+
+
diff --git a/src/components/interface_language_switcher/interface_language_switcher.vue b/src/components/interface_language_switcher/interface_language_switcher.vue
index 6997f149..a57e8761 100644
--- a/src/components/interface_language_switcher/interface_language_switcher.vue
+++ b/src/components/interface_language_switcher/interface_language_switcher.vue
@@ -1,21 +1,44 @@
-
-
+
+
{{ promptText }}
- {{ ' ' }}
-
-
+
- {{ lang.name }}
-
-
+
+ {{ index === 0 ? $t('settings.primary_language') : $tc('settings.fallback_language', index, { index }) }}
+ setLanguageAt(index, val)"
+ >
+
+ {{ lang.name }}
+
+
+
+ removeLanguageAt(index)"
+ >
+ {{ $t('settings.remove_language') }}
+
+
+
+ {{ $t('settings.add_language') }}
+
+
@@ -34,7 +57,7 @@ export default {
required: true
},
language: {
- type: String,
+ type: [Array, String],
required: true
},
setLanguage: {
@@ -48,7 +71,9 @@ export default {
},
controlledLanguage: {
- get: function () { return this.language },
+ get: function () {
+ return Array.isArray(this.language) ? this.language : [this.language]
+ },
set: function (val) {
this.setLanguage(val)
}
@@ -58,7 +83,30 @@ export default {
methods: {
getLanguageName (code) {
return localeService.getLanguageName(code)
+ },
+ addLanguage () {
+ this.controlledLanguage = [...this.controlledLanguage, '']
+ },
+ setLanguageAt (index, val) {
+ const lang = [...this.controlledLanguage]
+ lang[index] = val
+ this.controlledLanguage = lang
+ },
+ removeLanguageAt (index) {
+ const lang = [...this.controlledLanguage]
+ lang.splice(index, 1)
+ this.controlledLanguage = lang
}
}
}
+
+
diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js
index cdbbb812..dad1f6aa 100644
--- a/src/components/mobile_nav/mobile_nav.js
+++ b/src/components/mobile_nav/mobile_nav.js
@@ -1,5 +1,6 @@
import SideDrawer from '../side_drawer/side_drawer.vue'
import Notifications from '../notifications/notifications.vue'
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
import GestureService from '../../services/gesture_service/gesture_service'
import NavigationPins from 'src/components/navigation/navigation_pins.vue'
@@ -25,12 +26,14 @@ const MobileNav = {
components: {
SideDrawer,
Notifications,
- NavigationPins
+ NavigationPins,
+ ConfirmModal
},
data: () => ({
notificationsCloseGesture: undefined,
notificationsOpen: false,
- notificationsAtTop: true
+ notificationsAtTop: true,
+ showingConfirmLogout: false
}),
created () {
this.notificationsCloseGesture = GestureService.swipeGesture(
@@ -57,7 +60,11 @@ const MobileNav = {
...mapGetters(['unreadChatCount', 'unreadAnnouncementCount']),
chatsPinned () {
return new Set(this.$store.state.serverSideStorage.prefsStorage.collections.pinnedNavItems).has('chats')
- }
+ },
+ shouldConfirmLogout () {
+ return this.$store.getters.mergedConfig.modalOnLogout
+ },
+ ...mapGetters(['unreadChatCount'])
},
methods: {
toggleMobileSidebar () {
@@ -88,9 +95,23 @@ const MobileNav = {
scrollMobileNotificationsToTop () {
this.$refs.mobileNotifications.scrollTo(0, 0)
},
+ showConfirmLogout () {
+ this.showingConfirmLogout = true
+ },
+ hideConfirmLogout () {
+ this.showingConfirmLogout = false
+ },
logout () {
+ if (!this.shouldConfirmLogout) {
+ this.doLogout()
+ } else {
+ this.showConfirmLogout()
+ }
+ },
+ doLogout () {
this.$router.replace('/main/public')
this.$store.dispatch('logout')
+ this.hideConfirmLogout()
},
markNotificationsAsSeen () {
// this.$refs.notifications.markAsSeen()
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index d6fe102c..c2746abe 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -88,6 +88,18 @@
ref="sideDrawer"
:logout="logout"
/>
+
+
+ {{ $t('login.logout_confirm') }}
+
+
@@ -235,6 +247,16 @@
}
}
}
+
+ .confirm-modal.dark-overlay {
+ &::before {
+ z-index: 3000;
+ }
+
+ .dialog-modal.panel {
+ z-index: 3001;
+ }
+ }
}
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index 265aaee0..420db4f0 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -8,6 +8,7 @@ import Report from '../report/report.vue'
import UserLink from '../user_link/user_link.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import UserPopover from '../user_popover/user_popover.vue'
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@@ -43,7 +44,9 @@ const Notification = {
return {
statusExpanded: false,
betterShadow: this.$store.state.interface.browserSupport.cssFilter,
- unmuted: false
+ unmuted: false,
+ showingApproveConfirmDialog: false,
+ showingDenyConfirmDialog: false
}
},
props: ['notification'],
@@ -56,7 +59,8 @@ const Notification = {
Report,
RichContent,
UserPopover,
- UserLink
+ UserLink,
+ ConfirmModal
},
methods: {
toggleStatusExpanded () {
@@ -71,7 +75,26 @@ const Notification = {
toggleMute () {
this.unmuted = !this.unmuted
},
+ showApproveConfirmDialog () {
+ this.showingApproveConfirmDialog = true
+ },
+ hideApproveConfirmDialog () {
+ this.showingApproveConfirmDialog = false
+ },
+ showDenyConfirmDialog () {
+ this.showingDenyConfirmDialog = true
+ },
+ hideDenyConfirmDialog () {
+ this.showingDenyConfirmDialog = false
+ },
approveUser () {
+ if (this.shouldConfirmApprove) {
+ this.showApproveConfirmDialog()
+ } else {
+ this.doApprove()
+ }
+ },
+ doApprove () {
this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
this.$store.dispatch('removeFollowRequest', this.user)
this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id })
@@ -81,13 +104,22 @@ const Notification = {
notification.type = 'follow'
}
})
+ this.hideApproveConfirmDialog()
},
denyUser () {
+ if (this.shouldConfirmDeny) {
+ this.showDenyConfirmDialog()
+ } else {
+ this.doDeny()
+ }
+ },
+ doDeny () {
this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
.then(() => {
this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id })
this.$store.dispatch('removeFollowRequest', this.user)
})
+ this.hideDenyConfirmDialog()
}
},
computed: {
@@ -117,6 +149,15 @@ const Notification = {
isStatusNotification () {
return isStatusNotification(this.notification.type)
},
+ mergedConfig () {
+ return this.$store.getters.mergedConfig
+ },
+ shouldConfirmApprove () {
+ return this.mergedConfig.modalOnApproveFollow
+ },
+ shouldConfirmDeny () {
+ return this.mergedConfig.modalOnDenyFollow
+ },
...mapState({
currentUser: state => state.users.currentUser
})
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index f1aa5420..e1ea42ad 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -243,6 +243,28 @@
+
+
+ {{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }}
+
+
+ {{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }}
+
+
diff --git a/src/components/poll/poll_form.js b/src/components/poll/poll_form.js
index e30645c3..a2070155 100644
--- a/src/components/poll/poll_form.js
+++ b/src/components/poll/poll_form.js
@@ -94,19 +94,10 @@ export default {
},
convertExpiryToUnit (unit, amount) {
// Note: we want seconds and not milliseconds
- switch (unit) {
- case 'minutes': return (1000 * amount) / DateUtils.MINUTE
- case 'hours': return (1000 * amount) / DateUtils.HOUR
- case 'days': return (1000 * amount) / DateUtils.DAY
- }
+ return DateUtils.secondsToUnit(unit, amount)
},
convertExpiryFromUnit (unit, amount) {
- // Note: we want seconds and not milliseconds
- switch (unit) {
- case 'minutes': return 0.001 * amount * DateUtils.MINUTE
- case 'hours': return 0.001 * amount * DateUtils.HOUR
- case 'days': return 0.001 * amount * DateUtils.DAY
- }
+ return DateUtils.unitToSeconds(unit, amount)
},
expiryAmountChange () {
this.expiryAmount =
diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js
index 6eb316d0..22ca6ad6 100644
--- a/src/components/registration/registration.js
+++ b/src/components/registration/registration.js
@@ -3,6 +3,7 @@ import { required, requiredIf, sameAs } from '@vuelidate/validators'
import { mapActions, mapState } from 'vuex'
import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue'
import localeService from '../../services/locale/locale.service.js'
+import { DAY } from 'src/services/date_utils/date_utils.js'
const registration = {
setup () { return { v$: useVuelidate() } },
@@ -13,6 +14,7 @@ const registration = {
username: '',
password: '',
confirm: '',
+ birthday: '',
reason: '',
language: ''
},
@@ -32,6 +34,12 @@ const registration = {
required,
sameAs: sameAs(this.user.password)
},
+ birthday: {
+ required: requiredIf(() => this.birthdayRequired),
+ maxValue: value => {
+ return !this.birthdayRequired || new Date(value).getTime() <= this.birthdayMin.getTime()
+ }
+ },
reason: { required: requiredIf(() => this.accountApprovalRequired) },
language: {}
}
@@ -52,6 +60,24 @@ const registration = {
reasonPlaceholder () {
return this.replaceNewlines(this.$t('registration.reason_placeholder'))
},
+ birthdayMin () {
+ const minAge = this.birthdayMinAge
+ const today = new Date()
+ today.setUTCMilliseconds(0)
+ today.setUTCSeconds(0)
+ today.setUTCMinutes(0)
+ today.setUTCHours(0)
+ const minDate = new Date()
+ minDate.setTime(today.getTime() - minAge * DAY)
+ return minDate
+ },
+ birthdayMinAttr () {
+ return this.birthdayMin.toJSON().replace(/T.+$/, '')
+ },
+ birthdayMinFormatted () {
+ const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale)
+ return this.user.birthday && new Date(Date.parse(this.birthdayMin)).toLocaleDateString(browserLocale, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' })
+ },
...mapState({
registrationOpen: (state) => state.instance.registrationOpen,
signedIn: (state) => !!state.users.currentUser,
@@ -59,7 +85,9 @@ const registration = {
serverValidationErrors: (state) => state.users.signUpErrors,
termsOfService: (state) => state.instance.tos,
accountActivationRequired: (state) => state.instance.accountActivationRequired,
- accountApprovalRequired: (state) => state.instance.accountApprovalRequired
+ accountApprovalRequired: (state) => state.instance.accountApprovalRequired,
+ birthdayRequired: (state) => state.instance.birthdayRequired,
+ birthdayMinAge: (state) => state.instance.birthdayMinAge
})
},
methods: {
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index a26162f0..5701b05e 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -167,6 +167,40 @@
+
+
+ {{ birthdayRequired ? $t('registration.birthday') : $t('registration.birthday_optional') }}
+
+
+
+
+
{
this.inProgress = false
})
+ this.hideConfirmRemoveUserFromFollowers()
}
}
}
diff --git a/src/components/remove_follower_button/remove_follower_button.vue b/src/components/remove_follower_button/remove_follower_button.vue
index a3a4c242..0012aebd 100644
--- a/src/components/remove_follower_button/remove_follower_button.vue
+++ b/src/components/remove_follower_button/remove_follower_button.vue
@@ -7,6 +7,27 @@
@click="onClick"
>
{{ label }}
+
+
+
+
+
+
+
+
+
diff --git a/src/components/retweet_button/retweet_button.js b/src/components/retweet_button/retweet_button.js
index 4d92b5fa..198b6c14 100644
--- a/src/components/retweet_button/retweet_button.js
+++ b/src/components/retweet_button/retweet_button.js
@@ -1,3 +1,4 @@
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faRetweet,
@@ -15,13 +16,24 @@ library.add(
const RetweetButton = {
props: ['status', 'loggedIn', 'visibility'],
+ components: {
+ ConfirmModal
+ },
data () {
return {
- animated: false
+ animated: false,
+ showingConfirmDialog: false
}
},
methods: {
retweet () {
+ if (!this.status.repeated && this.shouldConfirmRepeat) {
+ this.showConfirmDialog()
+ } else {
+ this.doRetweet()
+ }
+ },
+ doRetweet () {
if (!this.status.repeated) {
this.$store.dispatch('retweet', { id: this.status.id })
} else {
@@ -31,6 +43,13 @@ const RetweetButton = {
setTimeout(() => {
this.animated = false
}, 500)
+ this.hideConfirmDialog()
+ },
+ showConfirmDialog () {
+ this.showingConfirmDialog = true
+ },
+ hideConfirmDialog () {
+ this.showingConfirmDialog = false
}
},
computed: {
@@ -39,6 +58,9 @@ const RetweetButton = {
},
remoteInteractionLink () {
return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
+ },
+ shouldConfirmRepeat () {
+ return this.mergedConfig.modalOnRepeat
}
}
}
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index 7700ee0d..134fcb36 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -59,6 +59,18 @@
>
{{ status.repeat_num }}
+
+
+ {{ $t('status.repeat_confirm') }}
+
+
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 582cb288..703e94a0 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -148,6 +148,56 @@
+
+ {{ $t('settings.confirm_dialogs') }}
+
+
+
+ {{ $t('settings.confirm_dialogs_repeat') }}
+
+
+
+
+ {{ $t('settings.confirm_dialogs_unfollow') }}
+
+
+
+
+ {{ $t('settings.confirm_dialogs_block') }}
+
+
+
+
+ {{ $t('settings.confirm_dialogs_mute') }}
+
+
+
+
+ {{ $t('settings.confirm_dialogs_delete') }}
+
+
+
+
+ {{ $t('settings.confirm_dialogs_logout') }}
+
+
+
+
+ {{ $t('settings.confirm_dialogs_approve_follow') }}
+
+
+
+
+ {{ $t('settings.confirm_dialogs_deny_follow') }}
+
+
+
+
+ {{ $t('settings.confirm_dialogs_remove_follower') }}
+
+
+
+
diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js
index ff2ccef2..72d27083 100644
--- a/src/components/settings_modal/tabs/profile_tab.js
+++ b/src/components/settings_modal/tabs/profile_tab.js
@@ -32,6 +32,8 @@ const ProfileTab = {
newName: this.$store.state.users.currentUser.name_unescaped,
newBio: unescape(this.$store.state.users.currentUser.description),
newLocked: this.$store.state.users.currentUser.locked,
+ newBirthday: this.$store.state.users.currentUser.birthday,
+ showBirthday: this.$store.state.users.currentUser.show_birthday,
newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })),
showRole: this.$store.state.users.currentUser.show_role,
role: this.$store.state.users.currentUser.role,
@@ -43,7 +45,7 @@ const ProfileTab = {
bannerPreview: null,
background: null,
backgroundPreview: null,
- emailLanguage: this.$store.state.users.currentUser.language || ''
+ emailLanguage: this.$store.state.users.currentUser.language || ['']
}
},
components: {
@@ -125,12 +127,14 @@ const ProfileTab = {
display_name: this.newName,
fields_attributes: this.newFields.filter(el => el != null),
bot: this.bot,
- show_role: this.showRole
+ show_role: this.showRole,
+ birthday: this.newBirthday || '',
+ show_birthday: this.showBirthday
/* eslint-enable camelcase */
}
if (this.emailLanguage) {
- params.language = localeService.internalToBackendLocale(this.emailLanguage)
+ params.language = localeService.internalToBackendLocaleMulti(this.emailLanguage)
}
this.$store.state.api.backendInteractor
diff --git a/src/components/settings_modal/tabs/profile_tab.scss b/src/components/settings_modal/tabs/profile_tab.scss
index 73879192..ee253ffe 100644
--- a/src/components/settings_modal/tabs/profile_tab.scss
+++ b/src/components/settings_modal/tabs/profile_tab.scss
@@ -129,4 +129,9 @@
padding: 0 0.5em;
}
}
+
+ .birthday-input {
+ display: block;
+ margin-bottom: 1em;
+ }
}
diff --git a/src/components/settings_modal/tabs/profile_tab.vue b/src/components/settings_modal/tabs/profile_tab.vue
index 642d54ca..faa05bcc 100644
--- a/src/components/settings_modal/tabs/profile_tab.vue
+++ b/src/components/settings_modal/tabs/profile_tab.vue
@@ -35,6 +35,18 @@
+
+
{{ $t('settings.birthday.label') }}
+
+
+ {{ $t('settings.birthday.show_birthday') }}
+
+
{{ $t('settings.profile_fields.label') }}
+
+
+
+
+
+
+
+
+
+ {{ $t('user_card.mute_duration_prompt') }}
+
+
+
+
+ {{ $t(`time.${unit}_short`, ['']) }}
+
+
+
+
+
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 08adaeab..acb612ed 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -7,13 +7,16 @@ import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import List from '../list/list.vue'
import withLoadMore from '../../hocs/with_load_more/with_load_more'
+import localeService from 'src/services/locale/locale.service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
- faCircleNotch
+ faCircleNotch,
+ faBirthdayCake
} from '@fortawesome/free-solid-svg-icons'
library.add(
- faCircleNotch
+ faCircleNotch,
+ faBirthdayCake
)
const FollowerList = withLoadMore({
@@ -76,6 +79,10 @@ const UserProfile = {
},
followersTabVisible () {
return this.isUs || !this.user.hide_followers
+ },
+ formattedBirthday () {
+ const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale)
+ return this.user.birthday && new Date(Date.parse(this.user.birthday)).toLocaleDateString(browserLocale, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' })
}
},
methods: {
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index 2720f052..c63a303c 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -12,6 +12,16 @@
rounded="top"
:has-note-editor="true"
/>
+
+
+ {{ $t('user_card.birthday', { birthday: formattedBirthday }) }}
+
languages.includes(code)
const loadLanguageFile = (code) => {
@@ -25,11 +28,26 @@ const messages = {
en: require('./en.json').default
},
setLanguage: async (i18n, language) => {
- if (hasLanguageFile(language)) {
- const messages = await loadLanguageFile(language)
- i18n.setLocaleMessage(language, messages.default)
+ const languages = (Array.isArray(language) ? language : [language]).filter(k => k)
+
+ if (!languages.includes(ULTIMATE_FALLBACK_LOCALE)) {
+ languages.push(ULTIMATE_FALLBACK_LOCALE)
}
- i18n.locale = language
+ const [first, ...rest] = languages
+
+ if (first === i18n.locale && isEqual(rest, i18n.fallbackLocale)) {
+ return
+ }
+
+ for (const lang of languages) {
+ if (hasLanguageFile(lang)) {
+ const messages = await loadLanguageFile(lang)
+ i18n.setLocaleMessage(lang, messages.default)
+ }
+ }
+
+ i18n.fallbackLocale = rest
+ i18n.locale = first
}
}
diff --git a/src/modules/config.js b/src/modules/config.js
index 806e999f..57df2125 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -78,6 +78,15 @@ export const defaultState = {
minimalScopesMode: undefined, // instance default
// This hides statuses filtered via a word filter
hideFilteredStatuses: undefined, // instance default
+ modalOnRepeat: undefined, // instance default
+ modalOnUnfollow: undefined, // instance default
+ modalOnBlock: undefined, // instance default
+ modalOnMute: undefined, // instance default
+ modalOnDelete: undefined, // instance default
+ modalOnLogout: undefined, // instance default
+ modalOnApproveFollow: undefined, // instance default
+ modalOnDenyFollow: undefined, // instance default
+ modalOnRemoveUserFromFollowers: undefined, // instance default
playVideosInModal: false,
useOneClickNsfw: false,
useContainFit: true,
@@ -184,7 +193,10 @@ const config = {
case 'interfaceLanguage':
messages.setLanguage(this.getters.i18n, value)
dispatch('loadUnicodeEmojiData', value)
- Cookies.set(BACKEND_LANGUAGE_COOKIE_NAME, localeService.internalToBackendLocale(value))
+ Cookies.set(
+ BACKEND_LANGUAGE_COOKIE_NAME,
+ localeService.internalToBackendLocaleMulti(value)
+ )
break
case 'thirdColumnMode':
dispatch('setLayoutWidth', undefined)
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 8e8d13d3..16f72583 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -71,6 +71,15 @@ const defaultState = {
hideSitename: false,
hideUserStats: false,
muteBotStatuses: false,
+ modalOnRepeat: false,
+ modalOnUnfollow: false,
+ modalOnBlock: true,
+ modalOnMute: false,
+ modalOnDelete: true,
+ modalOnLogout: true,
+ modalOnApproveFollow: false,
+ modalOnDenyFollow: false,
+ modalOnRemoveUserFromFollowers: false,
loginMethod: 'password',
logo: '/static/logo.svg',
logoMargin: '.2em',
@@ -107,6 +116,8 @@ const defaultState = {
restrictedNicknames: [],
safeDM: true,
knownDomains: [],
+ birthdayRequired: false,
+ birthdayMinAge: 0,
// Feature-set, apparently, not everything here is reported...
shoutAvailable: false,
@@ -286,8 +297,13 @@ const instance = {
langList
.map(async lang => {
if (!state.unicodeEmojiAnnotations[lang]) {
- const annotations = await loadAnnotations(lang)
- commit('setUnicodeEmojiAnnotations', { lang, annotations })
+ try {
+ const annotations = await loadAnnotations(lang)
+ commit('setUnicodeEmojiAnnotations', { lang, annotations })
+ } catch (e) {
+ console.warn(`Error loading unicode emoji annotations for ${lang}: `, e)
+ // ignore
+ }
}
}))
},
diff --git a/src/modules/users.js b/src/modules/users.js
index 053e44b6..a1316ba2 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -61,13 +61,16 @@ const editUserNote = (store, { id, comment }) => {
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
}
-const muteUser = (store, id) => {
+const muteUser = (store, args) => {
+ const id = typeof args === 'object' ? args.id : args
+ const expiresIn = typeof args === 'object' ? args.expiresIn : 0
+
const predictedRelationship = store.state.relationships[id] || { id }
predictedRelationship.muting = true
store.commit('updateUserRelationship', [predictedRelationship])
store.commit('addMuteId', id)
- return store.rootState.api.backendInteractor.muteUser({ id })
+ return store.rootState.api.backendInteractor.muteUser({ id, expiresIn })
.then((relationship) => {
store.commit('updateUserRelationship', [relationship])
store.commit('addMuteId', id)
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index af12265e..b8c10b21 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -1118,8 +1118,12 @@ const fetchMutes = ({ credentials }) => {
.then((users) => users.map(parseUser))
}
-const muteUser = ({ id, credentials }) => {
- return promisedRequest({ url: MASTODON_MUTE_USER_URL(id), credentials, method: 'POST' })
+const muteUser = ({ id, expiresIn, credentials }) => {
+ const payload = {}
+ if (expiresIn) {
+ payload.expires_in = expiresIn
+ }
+ return promisedRequest({ url: MASTODON_MUTE_USER_URL(id), credentials, method: 'POST', payload })
}
const unmuteUser = ({ id, credentials }) => {
diff --git a/src/services/date_utils/date_utils.js b/src/services/date_utils/date_utils.js
index c93d2176..ed8e1417 100644
--- a/src/services/date_utils/date_utils.js
+++ b/src/services/date_utils/date_utils.js
@@ -41,3 +41,19 @@ export const relativeTimeShort = (date, nowThreshold = 1) => {
r.key += '_short'
return r
}
+
+export const unitToSeconds = (unit, amount) => {
+ switch (unit) {
+ case 'minutes': return 0.001 * amount * MINUTE
+ case 'hours': return 0.001 * amount * HOUR
+ case 'days': return 0.001 * amount * DAY
+ }
+}
+
+export const secondsToUnit = (unit, amount) => {
+ switch (unit) {
+ case 'minutes': return (1000 * amount) / MINUTE
+ case 'hours': return (1000 * amount) / HOUR
+ case 'days': return (1000 * amount) / DAY
+ }
+}
diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js
index ea138177..53c3108c 100644
--- a/src/services/entity_normalizer/entity_normalizer.service.js
+++ b/src/services/entity_normalizer/entity_normalizer.service.js
@@ -125,6 +125,8 @@ export const parseUser = (data) => {
output.role = 'member'
}
+ output.birthday = data.pleroma.birthday
+
if (data.pleroma.privileges) {
output.privileges = data.pleroma.privileges
} else if (data.pleroma.is_admin) {
@@ -162,6 +164,7 @@ export const parseUser = (data) => {
output.no_rich_text = data.source.pleroma.no_rich_text
output.show_role = data.source.pleroma.show_role
output.discoverable = data.source.pleroma.discoverable
+ output.show_birthday = data.pleroma.show_birthday
}
}
diff --git a/src/services/locale/locale.service.js b/src/services/locale/locale.service.js
index d3389785..a4af8b90 100644
--- a/src/services/locale/locale.service.js
+++ b/src/services/locale/locale.service.js
@@ -11,6 +11,10 @@ const specialLanguageCodes = {
const internalToBrowserLocale = code => specialLanguageCodes[code] || code
const internalToBackendLocale = code => internalToBrowserLocale(code).replace('_', '-')
+const internalToBackendLocaleMulti = codes => {
+ const langs = Array.isArray(codes) ? codes : [codes]
+ return langs.map(internalToBackendLocale).join(',')
+}
const getLanguageName = (code) => {
const specialLanguageNames = {
@@ -28,6 +32,7 @@ const languages = _.map(languagesObject.languages, (code) => ({ code, name: getL
const localeService = {
internalToBrowserLocale,
internalToBackendLocale,
+ internalToBackendLocaleMulti,
languages,
getLanguageName
}
diff --git a/yarn.lock b/yarn.lock
index bc05dd56..85a8155f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2511,15 +2511,15 @@ array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
-array-includes@^3.1.4:
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9"
- integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==
+array-includes@^3.1.6:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f"
+ integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==
dependencies:
call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
- get-intrinsic "^1.1.1"
+ define-properties "^1.1.4"
+ es-abstract "^1.20.4"
+ get-intrinsic "^1.1.3"
is-string "^1.0.7"
array-union@^2.1.0:
@@ -2527,14 +2527,25 @@ array-union@^2.1.0:
resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-array.prototype.flat@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13"
- integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==
+array.prototype.flat@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2"
+ integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==
dependencies:
call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.0"
+ define-properties "^1.1.4"
+ es-abstract "^1.20.4"
+ es-shim-unscopables "^1.0.0"
+
+array.prototype.flatmap@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183"
+ integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.20.4"
+ es-shim-unscopables "^1.0.0"
arrify@^1.0.1:
version "1.0.1"
@@ -2573,6 +2584,11 @@ autoprefixer@10.4.13:
picocolors "^1.0.0"
postcss-value-parser "^4.2.0"
+available-typed-arrays@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7"
+ integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==
+
axe-core@^4.6.1:
version "4.6.2"
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.6.2.tgz#6e566ab2a3d29e415f5115bc0fd2597a5eb3e5e3"
@@ -3437,7 +3453,7 @@ de-indent@^1.0.2:
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=
-debug@2.6.9, debug@^2.6.9:
+debug@2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
@@ -3552,6 +3568,14 @@ define-properties@^1.1.3:
dependencies:
object-keys "^1.0.12"
+define-properties@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1"
+ integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==
+ dependencies:
+ has-property-descriptors "^1.0.0"
+ object-keys "^1.1.1"
+
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@@ -3824,7 +3848,7 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.19.0, es-abstract@^1.19.1:
+es-abstract@^1.19.0:
version "1.19.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3"
integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==
@@ -3850,11 +3874,66 @@ es-abstract@^1.19.0, es-abstract@^1.19.1:
string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.1"
+es-abstract@^1.20.4:
+ version "1.21.1"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6"
+ integrity sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==
+ dependencies:
+ available-typed-arrays "^1.0.5"
+ call-bind "^1.0.2"
+ es-set-tostringtag "^2.0.1"
+ es-to-primitive "^1.2.1"
+ function-bind "^1.1.1"
+ function.prototype.name "^1.1.5"
+ get-intrinsic "^1.1.3"
+ get-symbol-description "^1.0.0"
+ globalthis "^1.0.3"
+ gopd "^1.0.1"
+ has "^1.0.3"
+ has-property-descriptors "^1.0.0"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ internal-slot "^1.0.4"
+ is-array-buffer "^3.0.1"
+ is-callable "^1.2.7"
+ is-negative-zero "^2.0.2"
+ is-regex "^1.1.4"
+ is-shared-array-buffer "^1.0.2"
+ is-string "^1.0.7"
+ is-typed-array "^1.1.10"
+ is-weakref "^1.0.2"
+ object-inspect "^1.12.2"
+ object-keys "^1.1.1"
+ object.assign "^4.1.4"
+ regexp.prototype.flags "^1.4.3"
+ safe-regex-test "^1.0.0"
+ string.prototype.trimend "^1.0.6"
+ string.prototype.trimstart "^1.0.6"
+ typed-array-length "^1.0.4"
+ unbox-primitive "^1.0.2"
+ which-typed-array "^1.1.9"
+
es-module-lexer@^0.9.0:
version "0.9.3"
resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19"
integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
+es-set-tostringtag@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8"
+ integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==
+ dependencies:
+ get-intrinsic "^1.1.3"
+ has "^1.0.3"
+ has-tostringtag "^1.0.0"
+
+es-shim-unscopables@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241"
+ integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==
+ dependencies:
+ has "^1.0.3"
+
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@@ -3911,21 +3990,21 @@ eslint-formatter-friendly@7.0.0:
strip-ansi "5.2.0"
text-table "0.2.0"
-eslint-import-resolver-node@^0.3.6:
- version "0.3.6"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd"
- integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==
+eslint-import-resolver-node@^0.3.7:
+ version "0.3.7"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7"
+ integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==
dependencies:
debug "^3.2.7"
- resolve "^1.20.0"
+ is-core-module "^2.11.0"
+ resolve "^1.22.1"
-eslint-module-utils@^2.7.3:
- version "2.7.3"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee"
- integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==
+eslint-module-utils@^2.7.4:
+ version "2.7.4"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974"
+ integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==
dependencies:
debug "^3.2.7"
- find-up "^2.1.0"
eslint-plugin-es@^4.1.0:
version "4.1.0"
@@ -3935,23 +4014,25 @@ eslint-plugin-es@^4.1.0:
eslint-utils "^2.0.0"
regexpp "^3.0.0"
-eslint-plugin-import@2.26.0:
- version "2.26.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b"
- integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==
+eslint-plugin-import@2.27.5:
+ version "2.27.5"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz#876a6d03f52608a3e5bb439c2550588e51dd6c65"
+ integrity sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==
dependencies:
- array-includes "^3.1.4"
- array.prototype.flat "^1.2.5"
- debug "^2.6.9"
+ array-includes "^3.1.6"
+ array.prototype.flat "^1.3.1"
+ array.prototype.flatmap "^1.3.1"
+ debug "^3.2.7"
doctrine "^2.1.0"
- eslint-import-resolver-node "^0.3.6"
- eslint-module-utils "^2.7.3"
+ eslint-import-resolver-node "^0.3.7"
+ eslint-module-utils "^2.7.4"
has "^1.0.3"
- is-core-module "^2.8.1"
+ is-core-module "^2.11.0"
is-glob "^4.0.3"
minimatch "^3.1.2"
- object.values "^1.1.5"
- resolve "^1.22.0"
+ object.values "^1.1.6"
+ resolve "^1.22.1"
+ semver "^6.3.0"
tsconfig-paths "^3.14.1"
eslint-plugin-n@15.6.1:
@@ -3973,10 +4054,10 @@ eslint-plugin-promise@6.1.1:
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816"
integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==
-eslint-plugin-vue@9.8.0:
- version "9.8.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.8.0.tgz#91de2aabbee8cdbef078ccd4f650a9ecfa445f4f"
- integrity sha512-E/AXwcTzunyzM83C2QqDHxepMzvI2y6x+mmeYHbVDQlKFqmKYvRrhaVixEeeG27uI44p9oKDFiyCRw4XxgtfHA==
+eslint-plugin-vue@9.9.0:
+ version "9.9.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-9.9.0.tgz#ac788ebccd2eb94d846a507df55da50693b80c91"
+ integrity sha512-YbubS7eK0J7DCf0U2LxvVP7LMfs6rC6UltihIgval3azO3gyDwEGVgsCMe1TmDiEkl6GdMKfRpaME6QxIYtzDQ==
dependencies:
eslint-utils "^3.0.0"
natural-compare "^1.4.0"
@@ -4042,10 +4123,10 @@ eslint-webpack-plugin@3.2.0:
normalize-path "^3.0.0"
schema-utils "^4.0.0"
-eslint@8.31.0:
- version "8.31.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.31.0.tgz#75028e77cbcff102a9feae1d718135931532d524"
- integrity sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==
+eslint@8.32.0:
+ version "8.32.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.32.0.tgz#d9690056bb6f1a302bd991e7090f5b68fbaea861"
+ integrity sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==
dependencies:
"@eslint/eslintrc" "^1.4.1"
"@humanwhocodes/config-array" "^0.11.8"
@@ -4350,12 +4431,6 @@ find-up@5.0.0, find-up@^5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
-find-up@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
- dependencies:
- locate-path "^2.0.0"
-
find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
@@ -4408,6 +4483,13 @@ follow-redirects@^1.15.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
+for-each@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+ integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+ dependencies:
+ is-callable "^1.1.3"
+
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
@@ -4462,6 +4544,21 @@ function-bind@1.1.1, function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+function.prototype.name@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
+ integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+ es-abstract "^1.19.0"
+ functions-have-names "^1.2.2"
+
+functions-have-names@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
+ integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@@ -4486,6 +4583,15 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
has "^1.0.3"
has-symbols "^1.0.1"
+get-intrinsic@^1.1.3:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f"
+ integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==
+ dependencies:
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.3"
+
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
@@ -4582,6 +4688,13 @@ globals@^13.19.0:
dependencies:
type-fest "^0.20.2"
+globalthis@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf"
+ integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==
+ dependencies:
+ define-properties "^1.1.3"
+
globby@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
@@ -4610,6 +4723,13 @@ globjoin@^0.1.4:
resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
+
graceful-fs@^4.1.2:
version "4.1.15"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
@@ -4655,6 +4775,11 @@ has-bigints@^1.0.1:
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
+has-bigints@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa"
+ integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==
+
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -4664,11 +4789,23 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+has-property-descriptors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861"
+ integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==
+ dependencies:
+ get-intrinsic "^1.1.1"
+
+has-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
+ integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==
+
has-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
-has-symbols@^1.0.1, has-symbols@^1.0.2:
+has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
@@ -4953,6 +5090,15 @@ internal-slot@^1.0.3:
has "^1.0.3"
side-channel "^1.0.4"
+internal-slot@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3"
+ integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==
+ dependencies:
+ get-intrinsic "^1.1.3"
+ has "^1.0.3"
+ side-channel "^1.0.4"
+
interpret@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
@@ -4966,6 +5112,15 @@ ipaddr.js@1.9.1:
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+is-array-buffer@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a"
+ integrity sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.3"
+ is-typed-array "^1.1.10"
+
is-arrayish@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
@@ -4992,6 +5147,11 @@ is-boolean-object@^1.1.0:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"
+is-callable@^1.1.3, is-callable@^1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
+ integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
+
is-callable@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
@@ -5058,7 +5218,7 @@ is-interactive@^1.0.0:
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
-is-negative-zero@^2.0.1:
+is-negative-zero@^2.0.1, is-negative-zero@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
@@ -5123,6 +5283,13 @@ is-shared-array-buffer@^1.0.1:
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6"
integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==
+is-shared-array-buffer@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79"
+ integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==
+ dependencies:
+ call-bind "^1.0.2"
+
is-string@^1.0.5, is-string@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
@@ -5143,6 +5310,17 @@ is-symbol@^1.0.3:
dependencies:
has-symbols "^1.0.2"
+is-typed-array@^1.1.10, is-typed-array@^1.1.9:
+ version "1.1.10"
+ resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f"
+ integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==
+ dependencies:
+ available-typed-arrays "^1.0.5"
+ call-bind "^1.0.2"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ has-tostringtag "^1.0.0"
+
is-unicode-supported@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
@@ -5152,7 +5330,7 @@ is-url@^1.2.2:
version "1.2.4"
resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52"
-is-weakref@^1.0.1:
+is-weakref@^1.0.1, is-weakref@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
@@ -5626,13 +5804,6 @@ localforage@1.10.0:
dependencies:
lie "3.1.1"
-locate-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
- dependencies:
- p-locate "^2.0.0"
- path-exists "^3.0.0"
-
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
@@ -6424,6 +6595,11 @@ object-inspect@^1.11.0, object-inspect@^1.9.0:
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
+object-inspect@^1.12.2:
+ version "1.12.3"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9"
+ integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==
+
object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@@ -6438,14 +6614,24 @@ object.assign@^4.1.2:
has-symbols "^1.0.1"
object-keys "^1.1.1"
-object.values@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac"
- integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==
+object.assign@^4.1.4:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f"
+ integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==
dependencies:
call-bind "^1.0.2"
- define-properties "^1.1.3"
- es-abstract "^1.19.1"
+ define-properties "^1.1.4"
+ has-symbols "^1.0.3"
+ object-keys "^1.1.1"
+
+object.values@^1.1.6:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d"
+ integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.20.4"
on-finished@2.4.1:
version "2.4.1"
@@ -6544,12 +6730,6 @@ ora@5.4.1:
strip-ansi "^6.0.0"
wcwidth "^1.0.1"
-p-limit@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
- dependencies:
- p-try "^1.0.0"
-
p-limit@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.1.0.tgz#1d5a0d20fb12707c758a655f6bbc4386b5930d68"
@@ -6570,12 +6750,6 @@ p-limit@^3.0.2:
dependencies:
yocto-queue "^0.1.0"
-p-locate@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
- dependencies:
- p-limit "^1.1.0"
-
p-locate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
@@ -6596,10 +6770,6 @@ p-locate@^5.0.0:
dependencies:
p-limit "^3.0.2"
-p-try@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
-
p-try@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
@@ -7348,6 +7518,15 @@ regenerator-transform@^0.15.0:
dependencies:
"@babel/runtime" "^7.8.4"
+regexp.prototype.flags@^1.4.3:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac"
+ integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.3"
+ functions-have-names "^1.2.2"
+
regexpp@^3.0.0, regexpp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
@@ -7446,7 +7625,7 @@ resolve@^1.10.0:
dependencies:
path-parse "^1.0.6"
-resolve@^1.14.2, resolve@^1.20.0:
+resolve@^1.14.2:
version "1.22.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198"
integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==
@@ -7455,7 +7634,7 @@ resolve@^1.14.2, resolve@^1.20.0:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
-resolve@^1.22.0, resolve@^1.22.1:
+resolve@^1.22.1:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@@ -7510,6 +7689,15 @@ safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+safe-regex-test@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295"
+ integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==
+ dependencies:
+ call-bind "^1.0.2"
+ get-intrinsic "^1.1.3"
+ is-regex "^1.1.4"
+
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
@@ -7877,6 +8065,15 @@ string.prototype.trimend@^1.0.4:
call-bind "^1.0.2"
define-properties "^1.1.3"
+string.prototype.trimend@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533"
+ integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.20.4"
+
string.prototype.trimstart@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed"
@@ -7885,6 +8082,15 @@ string.prototype.trimstart@^1.0.4:
call-bind "^1.0.2"
define-properties "^1.1.3"
+string.prototype.trimstart@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4"
+ integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==
+ dependencies:
+ call-bind "^1.0.2"
+ define-properties "^1.1.4"
+ es-abstract "^1.20.4"
+
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
@@ -8295,6 +8501,15 @@ type-is@~1.6.18:
media-typer "0.3.0"
mime-types "~2.1.24"
+typed-array-length@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb"
+ integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==
+ dependencies:
+ call-bind "^1.0.2"
+ for-each "^0.3.3"
+ is-typed-array "^1.1.9"
+
ua-parser-js@^0.7.30:
version "0.7.31"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6"
@@ -8310,6 +8525,16 @@ unbox-primitive@^1.0.1:
has-symbols "^1.0.2"
which-boxed-primitive "^1.0.2"
+unbox-primitive@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
+ integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==
+ dependencies:
+ call-bind "^1.0.2"
+ has-bigints "^1.0.2"
+ has-symbols "^1.0.3"
+ which-boxed-primitive "^1.0.2"
+
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
@@ -8703,6 +8928,18 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
+which-typed-array@^1.1.9:
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6"
+ integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==
+ dependencies:
+ available-typed-arrays "^1.0.5"
+ call-bind "^1.0.2"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ has-tostringtag "^1.0.0"
+ is-typed-array "^1.1.10"
+
which@2.0.2, which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"