feat(webapp): more button icons, more loading states (#9243)

This commit is contained in:
Ulf Gebhardt 2026-02-18 03:59:10 +01:00 committed by GitHub
parent 82d2a2b1f3
commit c0a7965d24
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 85 additions and 19 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<title>lock</title>
<path d="M15 3c3.845 0 7 3.155 7 7v3h3v16h-20v-16h3v-3c0-3.845 3.155-7 7-7zM15 5c-2.755 0-5 2.245-5 5v3h10v-3c0-2.755-2.245-5-5-5zM7 15v12h16v-12h-16z"></path>
</svg>

After

Width:  |  Height:  |  Size: 318 B

View File

@ -20,6 +20,9 @@
:loading="loading"
:disabled="disabled || !!errors"
>
<template #icon>
<os-icon :icon="icons.comment" />
</template>
{{ $t('post.comment.submit') }}
</os-button>
</div>
@ -29,7 +32,8 @@
</template>
<script>
import { OsButton } from '@ocelot-social/ui'
import { OsButton, OsIcon } from '@ocelot-social/ui'
import { iconRegistry } from '~/utils/iconRegistry'
import HcEditor from '~/components/Editor/Editor'
import { COMMENT_MIN_LENGTH } from '~/constants/comment'
import { minimisedUserQuery } from '~/graphql/User'
@ -38,6 +42,7 @@ import CommentMutations from '~/graphql/CommentMutations'
export default {
components: {
OsButton,
OsIcon,
HcEditor,
},
props: {
@ -48,6 +53,9 @@ export default {
default: () => {},
},
},
created() {
this.icons = iconRegistry
},
data() {
return {
disabled: true,

View File

@ -172,14 +172,13 @@ describe('DeleteData.vue', () => {
describe('error handling', () => {
it('shows an error toaster when the mutation rejects', async () => {
mocks.$apollo.mutate = jest.fn().mockRejectedValue({ message: 'Not Authorized!' })
enableDeletionInput = wrapper.find('.ds-input')
enableDeletionInput.setValue(deleteAccountName)
await Vue.nextTick()
deleteAccountBtn = wrapper.find('[data-test="delete-button"]')
await deleteAccountBtn.trigger('click')
// second submission causes mutation to reject
await deleteAccountBtn.trigger('click')
await mocks.$apollo.mutate
await flushPromises()
expect(mocks.$toast.error).toHaveBeenCalledWith('Not Authorized!')
})
})

View File

@ -46,6 +46,7 @@
variant="danger"
appearance="filled"
:disabled="!deleteEnabled"
:loading="loading"
data-test="delete-button"
@click="handleSubmit"
>
@ -73,6 +74,7 @@ export default {
deleteComments: false,
enableDeletionValue: null,
currentUserCounts: {},
loading: false,
}
},
apollo: {
@ -101,6 +103,7 @@ export default {
logout: 'auth/logout',
}),
handleSubmit() {
this.loading = true
const resourceArgs = []
if (this.deleteContributions) {
resourceArgs.push('Post')
@ -130,6 +133,7 @@ export default {
})
.catch((error) => {
this.$toast.error(error.message)
this.loading = false
})
},
},

View File

@ -3,19 +3,24 @@
<progress-bar :label="label" :goal="goal" :progress="progress">
<os-button size="sm" variant="primary" @click="redirectToPage(links.DONATE)">
{{ $t('donations.donate-now') }}
<template #suffix>
<os-icon :icon="icons.heartO" />
</template>
</os-button>
</progress-bar>
</div>
</template>
<script>
import { OsButton } from '@ocelot-social/ui'
import { OsButton, OsIcon } from '@ocelot-social/ui'
import { iconRegistry } from '~/utils/iconRegistry'
import links from '~/constants/links.js'
import ProgressBar from '~/components/ProgressBar/ProgressBar.vue'
export default {
components: {
OsButton,
OsIcon,
ProgressBar,
},
props: {
@ -23,6 +28,9 @@ export default {
goal: { type: Number, required: true },
progress: { type: Number, required: true },
},
created() {
this.icons = iconRegistry
},
data() {
return {
links,

View File

@ -63,6 +63,9 @@
userId = scope.row.user.id
"
>
<template #icon>
<os-icon :icon="icons.userTimes" />
</template>
{{ $t('group.removeMemberButton') }}
</os-button>
</template>
@ -80,7 +83,8 @@
</div>
</template>
<script>
import { OsButton } from '@ocelot-social/ui'
import { OsButton, OsIcon } from '@ocelot-social/ui'
import { iconRegistry } from '~/utils/iconRegistry'
import { changeGroupMemberRoleMutation, removeUserFromGroupMutation } from '~/graphql/groups.js'
import ProfileAvatar from '~/components/_new/generic/ProfileAvatar/ProfileAvatar'
@ -88,6 +92,7 @@ export default {
name: 'GroupMember',
components: {
OsButton,
OsIcon,
ProfileAvatar,
},
props: {
@ -100,6 +105,9 @@ export default {
required: false,
},
},
created() {
this.icons = iconRegistry
},
data() {
return {
id: 'search-user-to-add-to-group',

View File

@ -51,14 +51,20 @@
appearance="ghost"
variant="primary"
>
<template #icon>
<os-icon :icon="icons.bell" />
</template>
{{ $t('notifications.pageLink') }}
</os-button>
<os-button
appearance="ghost"
variant="primary"
@click="markAllAsRead(closeMenu)"
@click="markAllAsRead()"
data-test="markAllAsRead-button"
>
<template #icon>
<os-icon :icon="icons.check" />
</template>
{{ $t('notifications.markAllAsRead') }}
</os-button>
</ds-flex-item>
@ -77,7 +83,7 @@
<script>
import { mapGetters } from 'vuex'
import unionBy from 'lodash/unionBy'
import { OsButton } from '@ocelot-social/ui'
import { OsButton, OsIcon } from '@ocelot-social/ui'
import { iconRegistry } from '~/utils/iconRegistry'
import {
notificationQuery,
@ -96,6 +102,7 @@ export default {
CounterIcon,
Dropdown,
OsButton,
OsIcon,
},
data() {
return {
@ -132,12 +139,11 @@ export default {
this.$toast.error(error.message)
}
},
async markAllAsRead(closeMenu) {
async markAllAsRead() {
if (!this.hasNotifications) {
return
}
closeMenu?.()
try {
await this.$apollo.mutate({
mutation: markAllAsReadMutation(this.$i18n),

View File

@ -31,6 +31,9 @@
:disabled="!!errors"
type="submit"
>
<template #icon>
<os-icon :icon="icons.lock" />
</template>
{{ $t('settings.security.change-password.button') }}
</os-button>
</ds-space>
@ -39,7 +42,8 @@
</template>
<script>
import { OsButton } from '@ocelot-social/ui'
import { OsButton, OsIcon } from '@ocelot-social/ui'
import { iconRegistry } from '~/utils/iconRegistry'
import gql from 'graphql-tag'
import PasswordStrength from './Strength'
import PasswordForm from '~/components/utils/PasswordFormHelper'
@ -48,8 +52,12 @@ export default {
name: 'ChangePassword',
components: {
OsButton,
OsIcon,
PasswordStrength,
},
created() {
this.icons = iconRegistry
},
data() {
const passwordForm = PasswordForm({ translate: this.$t })
return {

View File

@ -31,6 +31,9 @@
:disabled="!!errors"
type="submit"
>
<template #icon>
<os-icon :icon="icons.lock" />
</template>
{{ $t('settings.security.change-password.button') }}
</os-button>
</ds-space>
@ -67,7 +70,8 @@
</template>
<script>
import { OsButton } from '@ocelot-social/ui'
import { OsButton, OsIcon } from '@ocelot-social/ui'
import { iconRegistry } from '~/utils/iconRegistry'
import emails from '../../constants/emails.js'
import PasswordStrength from '../Password/Strength'
import gql from 'graphql-tag'
@ -77,6 +81,7 @@ import PasswordForm from '~/components/utils/PasswordFormHelper'
export default {
components: {
OsButton,
OsIcon,
SweetalertIcon,
PasswordStrength,
},
@ -84,6 +89,9 @@ export default {
email: { type: String, required: true },
nonce: { type: String, required: true },
},
created() {
this.icons = iconRegistry
},
data() {
const passwordForm = PasswordForm({ translate: this.$t })
return {

View File

@ -18,6 +18,9 @@
@click="showFiledReports = !showFiledReports"
>
{{ $t('moderation.reports.moreDetails') }}
<template #suffix>
<os-icon :icon="showFiledReports ? icons.angleUp : icons.angleDown" />
</template>
</os-button>
</td>

View File

@ -59,6 +59,7 @@
appearance="outline"
circle
size="sm"
:loading="unblockingUserId === scope.row.id"
:aria-label="$t('settings.blocked-users.columns.unblock')"
@click="unblockUser(scope)"
>
@ -102,6 +103,7 @@ export default {
data() {
return {
blockedUsers: [],
unblockingUserId: null,
}
},
computed: {
@ -119,6 +121,8 @@ export default {
},
methods: {
async unblockUser(user) {
this.unblockingUserId = user.row.id
try {
await this.$apollo.mutate({
mutation: unblockUser(),
variables: { id: user.row.id },
@ -126,6 +130,11 @@ export default {
this.$apollo.queries.blockedUsers.refetch()
const { name } = user.row
this.$toast.success(this.$t('settings.blocked-users.unblocked', { name }))
} catch (error) {
this.$toast.error(error.message)
} finally {
this.unblockingUserId = null
}
},
},
}