Skip to content

Commit d688a8e

Browse files
authored
Merge branch 'master' into fix/systemtags-search-invalid-tag-id
2 parents 0917faf + 4082691 commit d688a8e

24 files changed

Lines changed: 196 additions & 84 deletions

apps/appstore/src/components/AppTable/AppTable.vue

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,21 @@ const tableElement = useTemplateRef('table')
1919
const { width: tableWidth } = useElementSize(tableElement)
2020
2121
const isNarrow = computed(() => tableWidth.value < 768)
22+
const isWide = computed(() => tableWidth.value >= 1280)
2223
</script>
2324

2425
<template>
25-
<table ref="table" :class="[$style.appTable, { [$style.appTable_narrow]: isNarrow }]">
26+
<table
27+
ref="table"
28+
:class="[$style.appTable, {
29+
[$style.appTable_narrow]: isNarrow,
30+
[$style.appTable_wide]: isWide,
31+
}]">
2632
<colgroup>
2733
<col :class="$style.appTable__colName">
2834
<col :class="$style.appTable__colVersion">
2935
<col v-if="!isNarrow" :class="$style.appTable__colSupport">
36+
<col v-if="isWide" :class="$style.appTable__colGroups">
3037
<col :class="$style.appTable__colActions">
3138
</colgroup>
3239
<thead hidden>
@@ -36,6 +43,9 @@ const isNarrow = computed(() => tableWidth.value < 768)
3643
<th v-if="!isNarrow">
3744
{{ t('appstore', 'Support level') }}
3845
</th>
46+
<th v-if="isWide">
47+
{{ t('appstore', 'Groups') }}
48+
</th>
3949
<th>{{ t('appstore', 'Actions') }}</th>
4050
</tr>
4151
</thead>
@@ -44,7 +54,8 @@ const isNarrow = computed(() => tableWidth.value < 768)
4454
v-for="app in apps"
4555
:key="app.id"
4656
:app
47-
:isNarrow />
57+
:isNarrow
58+
:isWide />
4859
</tbody>
4960
</table>
5061
</template>
@@ -63,14 +74,26 @@ const isNarrow = computed(() => tableWidth.value < 768)
6374
width: 60%;
6475
}
6576
77+
.appTable_wide .appTable__colName {
78+
width: 37%;
79+
}
80+
6681
.appTable__colSupport {
6782
width: 15%;
6883
}
6984
85+
.appTable_wide .appTable__colSupport {
86+
width: 12%;
87+
}
88+
7089
.appTable__colActions {
7190
width: 25%;
7291
}
7392
93+
.appTable_wide .appTable__colActions {
94+
width: 20%;
95+
}
96+
7497
.appTable_narrow .appTable__colActions {
7598
width: calc(3 * var(--default-grid-baseline) + 2 * var(--default-clickable-area));
7699
}

apps/appstore/src/components/AppTable/AppTableRow.vue

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,19 @@ import { t } from '@nextcloud/l10n'
1212
import { computed } from 'vue'
1313
import { useRoute } from 'vue-router'
1414
import NcButton from '@nextcloud/vue/components/NcButton'
15+
import NcChip from '@nextcloud/vue/components/NcChip'
1516
import NcLoadingIcon from '@nextcloud/vue/components/NcLoadingIcon'
1617
import AppActions from '../AppActions.vue'
1718
import AppIcon from '../AppIcon.vue'
1819
import BadgeAppDaemon from '../BadgeAppDaemon.vue'
1920
import BadgeAppLevel from '../BadgeAppLevel.vue'
2021
import { useActions } from '../../composables/useActions.ts'
22+
import { useLimitedGroups } from '../../composables/useLimitedGroups.ts'
2123
2224
const { app, isNarrow } = defineProps<{
2325
app: IAppstoreApp | IAppstoreExApp
2426
isNarrow?: boolean
27+
isWide?: boolean
2528
}>()
2629
2730
const route = useRoute()
@@ -46,6 +49,7 @@ const detailsAction = computed<AppAction>(() => ({
4649
inline: false,
4750
}))
4851
52+
const groupsAppIsLimitedTo = useLimitedGroups(() => app)
4953
const rawActions = useActions(() => app)
5054
const actions = computed(() => [
5155
...rawActions.value,
@@ -80,6 +84,21 @@ const actions = computed(() => [
8084
<BadgeAppDaemon v-if="'daemon' in app && app.daemon" :daemon="app.daemon" />
8185
</div>
8286
</td>
87+
<td v-if="isWide">
88+
<ul
89+
v-if="groupsAppIsLimitedTo.length > 0"
90+
:class="$style.appTableRow__groupsCell"
91+
:title="groupsAppIsLimitedTo.map((group) => group.displayName).join(', ')">
92+
<template v-for="group, index in groupsAppIsLimitedTo" :key="group.id">
93+
<li v-if="index === 3" aria-hidden="true">
94+
95+
</li>
96+
<li :class="{ 'hidden-visually': index > 2 }">
97+
<NcChip :text="group.displayName" noClose />
98+
</li>
99+
</template>
100+
</ul>
101+
</td>
83102
<td>
84103
<div :class="$style.appTableRow__actionsCell">
85104
<AppActions
@@ -117,6 +136,11 @@ const actions = computed(() => [
117136
color: var(--color-text-maxcontrast);
118137
}
119138
139+
.appTableRow__groupsCell {
140+
display: flex;
141+
gap: var(--default-grid-baseline);
142+
}
143+
120144
.appTableRow__actionsCell {
121145
display: flex;
122146
gap: var(--default-grid-baseline);

apps/appstore/src/components/AppstoreSidebar/AppDetailsTab.vue

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'
1616
import BadgeAppDaemon from '../BadgeAppDaemon.vue'
1717
import BadgeAppLevel from '../BadgeAppLevel.vue'
1818
import BadgeAppScore from '../BadgeAppScore.vue'
19+
import { useLimitedGroups } from '../../composables/useLimitedGroups.ts'
1920
import { useAppsStore } from '../../store/apps.ts'
2021
2122
const { app } = defineProps<{ app: IAppstoreApp | IAppstoreExApp }>()
@@ -43,15 +44,8 @@ const appAuthors = computed(() => {
4344
.join(', ')
4445
})
4546
46-
const groupsAppIsLimitedto = computed(() => {
47-
if (!app.groups) {
48-
return []
49-
}
50-
51-
return app.groups.map((group) => ({ id: group, name: group }))
52-
})
53-
5447
const appstoreUrl = computed(() => `https://apps.nextcloud.com/apps/${app.id}`)
48+
const groupsAppIsLimitedTo = useLimitedGroups(() => app)
5549
5650
/**
5751
* Further external resources (e.g. website)
@@ -144,16 +138,16 @@ function authorName(xmlNode): string {
144138
</ul>
145139
</NcNoteCard>
146140

147-
<div v-if="groupsAppIsLimitedto.length" :class="$style.appstoreDetailsTab__section">
141+
<div v-if="groupsAppIsLimitedTo.length" :class="$style.appstoreDetailsTab__section">
148142
<h4 :id="idLimitedToGroups">
149143
{{ t('appstore', 'Limited to groups') }}
150144
</h4>
151145
<ul :aria-labelledby="idLimitedToGroups" :class="$style.appstoreDetailsTab__sectionDetails">
152146
<li
153-
v-for="group of groupsAppIsLimitedto"
147+
v-for="group of groupsAppIsLimitedTo"
154148
:key="group.id"
155149
:title="group.id">
156-
{{ group.name }}
150+
{{ group.displayName }}
157151
</li>
158152
</ul>
159153
</div>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*!
2+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import type { MaybeRefOrGetter } from 'vue'
7+
import type { IAppstoreApp, IAppstoreExApp } from '../apps.d.ts'
8+
9+
import { readonly, ref, toValue, watch } from 'vue'
10+
import { useGroupsStore } from '../store/groups.ts'
11+
12+
/**
13+
* Get the groups an app is limited to and keep it up to date
14+
*
15+
* @param app - The app to get the groups
16+
*/
17+
export function useLimitedGroups(app: MaybeRefOrGetter<IAppstoreApp | IAppstoreExApp>) {
18+
const groupsStore = useGroupsStore()
19+
const groupsAppIsLimitedTo = ref<{ id: string, displayName: string }[]>([])
20+
watch(() => toValue(app).groups, async () => {
21+
const groups = toValue(app).groups
22+
if (groups === undefined) {
23+
groupsAppIsLimitedTo.value = []
24+
return
25+
}
26+
27+
const promises = groups.map((group) => groupsStore.fetchGroupById(group))
28+
const results = await Promise.all(promises)
29+
groupsAppIsLimitedTo.value = results.filter(Boolean) as { id: string, displayName: string }[]
30+
}, { immediate: true })
31+
32+
return readonly(groupsAppIsLimitedTo)
33+
}

apps/appstore/src/store/groups.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,25 @@ import type { NcSelectUsersModel } from '@nextcloud/vue/components/NcSelectUsers
88

99
import axios from '@nextcloud/axios'
1010
import { generateOcsUrl } from '@nextcloud/router'
11+
import PQueue from 'p-queue'
1112
import { defineStore } from 'pinia'
1213
import { computed, ref } from 'vue'
1314
import logger from '../utils/logger.ts'
1415

16+
const queue = new PQueue({ concurrency: 3 })
17+
1518
export const useGroupsStore = defineStore('groups', () => {
1619
const groups = ref(new Map<string, NcSelectUsersModel>())
1720

21+
/**
22+
* Get group details by id
23+
*
24+
* @param groupId - The id of the group to fetch
25+
*/
26+
async function fetchGroupById(groupId: string) {
27+
return await queue.add(() => internalFetchGroupById(groupId))
28+
}
29+
1830
/**
1931
* Search the API for groups matching the query
2032
*
@@ -59,5 +71,18 @@ export const useGroupsStore = defineStore('groups', () => {
5971
groups: computed(() => Array.from(groups.value.values())),
6072
searchGroups,
6173
getGroupById,
74+
fetchGroupById,
75+
}
76+
77+
/**
78+
* Handle fetching group details by id
79+
*
80+
* @param groupId - The id of the group to fetch
81+
*/
82+
async function internalFetchGroupById(groupId: string) {
83+
if (!groups.value.has(groupId)) {
84+
await searchGroups(groupId)
85+
}
86+
return groups.value.get(groupId)
6287
}
6388
})

apps/files_sharing/src/public-nickname-handler.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@ import logger from './services/logger.ts'
1616

1717
const storage = getBuilder('files_sharing').build()
1818

19-
// Setup file-request nickname header for the uploader
2019
/**
20+
* Setup file-request nickname header for the uploader
2121
*
22-
* @param nickname
22+
* @param nickname - The nickname to set in the header
2323
*/
2424
function registerFileRequestHeader(nickname: string) {
2525
const uploader = getUploader()
2626
uploader.setCustomHeader('X-NC-Nickname', encodeURIComponent(nickname))
2727
logger.debug('Nickname header registered for uploader', { headers: uploader.customHeaders })
2828
}
2929

30-
// Callback when a nickname was chosen
3130
/**
31+
* Callback when a nickname was chosen
3232
*
33-
* @param guest
33+
* @param guest - The guest user with the new nickname
3434
*/
3535
function onUserInfoChanged(guest: NextcloudUser) {
3636
logger.debug('User info changed', { guest })
@@ -57,20 +57,20 @@ window.addEventListener('DOMContentLoaded', () => {
5757

5858
const options = {
5959
nickname,
60-
notice: t('files_sharing', 'To upload files to {folder}, you need to provide your name first.', { folder }),
60+
notice: t('files_sharing', 'To upload files to {folder}, you need to provide your name first.', { folder }, { escape: false }),
6161
subtitle: undefined as string | undefined,
62-
title: t('files_sharing', 'Upload files to {folder}', { folder }),
62+
title: t('files_sharing', 'Upload files to {folder}', { folder }, { escape: false }),
6363
}
6464

6565
// If the guest already has a nickname, we just make them double check
6666
if (nickname) {
67-
options.notice = t('files_sharing', 'Please confirm your name to upload files to {folder}', { folder })
67+
options.notice = t('files_sharing', 'Please confirm your name to upload files to {folder}', { folder }, { escape: false })
6868
}
6969

7070
// If the account owner set their name as public,
7171
// we show it in the subtitle
7272
if (owner) {
73-
options.subtitle = t('files_sharing', '{ownerDisplayName} shared a folder with you.', { ownerDisplayName })
73+
options.subtitle = t('files_sharing', '{ownerDisplayName} shared a folder with you.', { ownerDisplayName }, { escape: false })
7474
}
7575

7676
// If this is a file request, then we need a nickname

apps/files_sharing/src/views/SharingDetailsTab.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,9 @@ export default {
11311131
11321132
// ugly hack to make code work - we need the id to be set but at the same time we need to keep values we want to update
11331133
this.share._share.id = share.id
1134+
// Similarly the token is always set by the backend when the
1135+
// share is created.
1136+
this.share._share.token = share.token
11341137
await this.queueUpdate(...permissionsAndAttributes)
11351138
// Also a ugly hack to update the updated permissions
11361139
for (const prop of permissionsAndAttributes) {

build/eslint-baseline-legacy.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
},
1717
"apps/files_sharing/src/views/SharingDetailsTab.vue": {
1818
"vue/no-mutating-props": {
19-
"count": 23
19+
"count": 24
2020
}
2121
},
2222
"apps/files_sharing/src/views/SharingLinkList.vue": {
Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)