Skip to content

Commit 8c9e597

Browse files
authored
Fix org security avatars and member links (#1536)
* fix(frontend): sign org security avatars * feat(frontend): link to members from security * chore(frontend): import useRouter in security
1 parent 803bae3 commit 8c9e597

File tree

1 file changed

+78
-31
lines changed

1 file changed

+78
-31
lines changed

src/pages/settings/organization/Security.vue

Lines changed: 78 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { computedAsync } from '@vueuse/core'
33
import { storeToRefs } from 'pinia'
44
import { computed, onMounted, ref, watch } from 'vue'
55
import { useI18n } from 'vue-i18n'
6+
import { useRouter } from 'vue-router'
67
import { toast } from 'vue-sonner'
78
import IconCheck from '~icons/heroicons/check-circle'
89
import IconWarning from '~icons/heroicons/exclamation-triangle'
@@ -12,6 +13,7 @@ import IconLock from '~icons/heroicons/lock-closed'
1213
import IconShield from '~icons/heroicons/shield-check'
1314
import IconUser from '~icons/heroicons/user'
1415
import { checkPermissions } from '~/services/permissions'
16+
import { createSignedImageUrl } from '~/services/storage'
1517
import { useSupabase } from '~/services/supabase'
1618
import { useDialogV2Store } from '~/stores/dialogv2'
1719
import { useDisplayStore } from '~/stores/display'
@@ -41,6 +43,7 @@ const { t } = useI18n()
4143
const displayStore = useDisplayStore()
4244
const organizationStore = useOrganizationStore()
4345
const dialogStore = useDialogV2Store()
46+
const router = useRouter()
4447
const supabase = useSupabase()
4548
const isLoading = ref(true)
4649
const isSaving = ref(false)
@@ -160,6 +163,12 @@ function loadApikeyPolicyFromOrg() {
160163
maxApikeyExpirationDays.value = currentOrganization.value?.max_apikey_expiration_days ?? null
161164
}
162165
166+
async function goToMembersPage(closeDialog = false) {
167+
if (closeDialog)
168+
await dialogStore.closeDialog()
169+
await router.push('/settings/organization/members')
170+
}
171+
163172
async function loadData() {
164173
if (!currentOrganization.value?.gid)
165174
return
@@ -242,13 +251,16 @@ async function loadMembersWithMfaStatus() {
242251
}
243252
244253
// Merge members with MFA status
245-
membersWithMfaStatus.value = (members || []).map(member => ({
246-
uid: member.uid,
247-
email: member.email,
248-
image_url: member.image_url || '',
249-
role: member.role,
250-
is_tmp: member.is_tmp,
251-
has_2fa: mfaMap.get(member.uid) ?? false,
254+
membersWithMfaStatus.value = await Promise.all((members || []).map(async (member) => {
255+
const signedImage = member.image_url ? await createSignedImageUrl(member.image_url) : ''
256+
return {
257+
uid: member.uid,
258+
email: member.email,
259+
image_url: signedImage || '',
260+
role: member.role,
261+
is_tmp: member.is_tmp,
262+
has_2fa: mfaMap.get(member.uid) ?? false,
263+
}
252264
}))
253265
254266
// Calculate impacted members (those without 2FA, excluding pending invites)
@@ -304,19 +316,20 @@ async function loadMembersWithPasswordPolicyStatus() {
304316
}
305317
306318
// Merge members with password policy compliance status
307-
membersWithPasswordPolicyStatus.value = (members || []).map((member) => {
319+
membersWithPasswordPolicyStatus.value = await Promise.all((members || []).map(async (member) => {
308320
const compliance = complianceMap.get(member.uid)
321+
const signedImage = member.image_url ? await createSignedImageUrl(member.image_url) : ''
309322
return {
310323
uid: member.uid,
311324
email: member.email,
312325
first_name: compliance?.first_name || null,
313326
last_name: compliance?.last_name || null,
314-
image_url: member.image_url || '',
327+
image_url: signedImage || '',
315328
role: member.role,
316329
is_tmp: member.is_tmp,
317330
password_policy_compliant: compliance?.compliant ?? false,
318331
}
319-
})
332+
}))
320333
321334
// Calculate non-compliant members (excluding pending invites)
322335
nonCompliantPasswordMembers.value = membersWithPasswordPolicyStatus.value.filter(m => !m.password_policy_compliant && !m.is_tmp)
@@ -951,13 +964,22 @@ onMounted(async () => {
951964
{{ t('2fa-impacted-members-title') }}
952965
</h4>
953966
</div>
954-
<button
955-
type="button"
956-
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
957-
@click="copyEmailList"
958-
>
959-
{{ t('copy-email-list') }}
960-
</button>
967+
<div class="flex items-center gap-2">
968+
<button
969+
type="button"
970+
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
971+
@click="goToMembersPage()"
972+
>
973+
{{ t('view') }} {{ t('members') }}
974+
</button>
975+
<button
976+
type="button"
977+
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
978+
@click="copyEmailList"
979+
>
980+
{{ t('copy-email-list') }}
981+
</button>
982+
</div>
961983
</div>
962984
<p class="mb-4 text-sm text-amber-700 dark:text-amber-300">
963985
{{ t('2fa-impacted-members-description') }}
@@ -1229,13 +1251,22 @@ onMounted(async () => {
12291251
{{ t('password-policy-impacted-members-title') }}
12301252
</h4>
12311253
</div>
1232-
<button
1233-
type="button"
1234-
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
1235-
@click="copyPasswordPolicyEmailList"
1236-
>
1237-
{{ t('copy-email-list') }}
1238-
</button>
1254+
<div class="flex items-center gap-2">
1255+
<button
1256+
type="button"
1257+
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
1258+
@click="goToMembersPage()"
1259+
>
1260+
{{ t('view') }} {{ t('members') }}
1261+
</button>
1262+
<button
1263+
type="button"
1264+
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
1265+
@click="copyPasswordPolicyEmailList"
1266+
>
1267+
{{ t('copy-email-list') }}
1268+
</button>
1269+
</div>
12391270
</div>
12401271
<p class="mb-4 text-sm text-amber-700 dark:text-amber-300">
12411272
{{ t('password-policy-impacted-members-description') }}
@@ -1389,13 +1420,22 @@ onMounted(async () => {
13891420
<span class="text-xs text-amber-600 dark:text-amber-400">({{ member.role.replace('_', ' ') }})</span>
13901421
</li>
13911422
</ul>
1392-
<button
1393-
type="button"
1394-
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
1395-
@click="copyEmailList"
1396-
>
1397-
{{ t('copy-email-list') }}
1398-
</button>
1423+
<div class="flex items-center gap-2">
1424+
<button
1425+
type="button"
1426+
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
1427+
@click="goToMembersPage(true)"
1428+
>
1429+
{{ t('view') }} {{ t('members') }}
1430+
</button>
1431+
<button
1432+
type="button"
1433+
class="px-3 py-2 text-xs font-medium text-center border rounded-lg cursor-pointer text-amber-700 dark:text-amber-300 hover:bg-amber-100 focus:ring-4 focus:ring-amber-300 border-amber-400 dark:border-amber-600 dark:hover:bg-amber-800/30 dark:focus:ring-amber-800 focus:outline-hidden"
1434+
@click="copyEmailList"
1435+
>
1436+
{{ t('copy-email-list') }}
1437+
</button>
1438+
</div>
13991439
</div>
14001440
</Teleport>
14011441

@@ -1416,6 +1456,13 @@ onMounted(async () => {
14161456
</div>
14171457
</li>
14181458
</ul>
1459+
<button
1460+
type="button"
1461+
class="px-3 py-2 mt-4 text-xs font-medium text-center border rounded-lg cursor-pointer text-red-700 dark:text-red-300 hover:bg-red-100 focus:ring-4 focus:ring-red-200 border-red-300 dark:border-red-600 dark:hover:bg-red-900/30 dark:focus:ring-red-900 focus:outline-hidden"
1462+
@click="goToMembersPage(true)"
1463+
>
1464+
{{ t('view') }} {{ t('members') }}
1465+
</button>
14191466
<p class="mt-3 text-sm text-red-600 dark:text-red-400">
14201467
{{ t('users-must-change-password') }}
14211468
</p>

0 commit comments

Comments
 (0)