feat(link shares): allows switching the initial view by passing a query parameter (#2335)
Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/2335 Reviewed-by: Dominik Pschenitschni <dpschen@noreply.kolaente.de>
This commit is contained in:
commit
a6e9b36bd6
4 changed files with 90 additions and 48 deletions
|
@ -79,30 +79,59 @@
|
|||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ $t('list.share.attributes.link') }}</th>
|
||||
<th>{{ $t('list.share.attributes.name') }}</th>
|
||||
<th>{{ $t('list.share.attributes.sharedBy') }}</th>
|
||||
<th>{{ $t('list.share.attributes.right') }}</th>
|
||||
<th></th>
|
||||
<th>{{ $t('list.share.links.view') }}</th>
|
||||
<th>{{ $t('list.share.attributes.delete') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr :key="s.id" v-for="s in linkShares">
|
||||
<td>
|
||||
<p class="mb-2 is-italic" v-if="s.name !== ''">
|
||||
{{ s.name }}
|
||||
</p>
|
||||
|
||||
<p class="mb-2">
|
||||
<i18n-t keypath="list.share.links.sharedBy">
|
||||
<strong>{{ s.sharedBy.getDisplayName() }}</strong>
|
||||
</i18n-t>
|
||||
</p>
|
||||
|
||||
<p class="mb-2">
|
||||
<template v-if="s.right === RIGHTS.ADMIN">
|
||||
<span class="icon is-small">
|
||||
<icon icon="lock"/>
|
||||
</span>
|
||||
{{ $t('list.share.right.admin') }}
|
||||
</template>
|
||||
<template v-else-if="s.right === RIGHTS.READ_WRITE">
|
||||
<span class="icon is-small">
|
||||
<icon icon="pen"/>
|
||||
</span>
|
||||
{{ $t('list.share.right.readWrite') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="icon is-small">
|
||||
<icon icon="users"/>
|
||||
</span>
|
||||
{{ $t('list.share.right.read') }}
|
||||
</template>
|
||||
</p>
|
||||
|
||||
<div class="field has-addons no-input-mobile">
|
||||
<div class="control">
|
||||
<input
|
||||
:value="getShareLink(s.hash)"
|
||||
class="input"
|
||||
readonly
|
||||
type="text"
|
||||
:value="getShareLink(s.hash, selectedView[s.id])"
|
||||
class="input"
|
||||
readonly
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="control">
|
||||
<x-button
|
||||
@click="copy(getShareLink(s.hash))"
|
||||
:shadow="false"
|
||||
v-tooltip="$t('misc.copy')"
|
||||
@click="copy(getShareLink(s.hash, selectedView[s.id]))"
|
||||
:shadow="false"
|
||||
v-tooltip="$t('misc.copy')"
|
||||
>
|
||||
<span class="icon">
|
||||
<icon icon="paste"/>
|
||||
|
@ -112,33 +141,16 @@
|
|||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="s.name !== ''">
|
||||
{{ s.name }}
|
||||
</template>
|
||||
<i v-else>{{ $t('list.share.links.noName') }}</i>
|
||||
</td>
|
||||
<td>
|
||||
{{ s.sharedBy.getDisplayName() }}
|
||||
</td>
|
||||
<td class="type">
|
||||
<template v-if="s.right === RIGHTS.ADMIN">
|
||||
<span class="icon is-small">
|
||||
<icon icon="lock"/>
|
||||
</span>
|
||||
{{ $t('list.share.right.admin') }}
|
||||
</template>
|
||||
<template v-else-if="s.right === RIGHTS.READ_WRITE">
|
||||
<span class="icon is-small">
|
||||
<icon icon="pen"/>
|
||||
</span>
|
||||
{{ $t('list.share.right.readWrite') }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="icon is-small">
|
||||
<icon icon="users"/>
|
||||
</span>
|
||||
{{ $t('list.share.right.read') }}
|
||||
</template>
|
||||
<div class="select">
|
||||
<select v-model="selectedView[s.id]">
|
||||
<option
|
||||
v-for="(title, key) in availableViews"
|
||||
:value="key"
|
||||
:key="key">
|
||||
{{ title }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td class="actions">
|
||||
<x-button
|
||||
|
@ -166,7 +178,7 @@
|
|||
<template #header>
|
||||
<span>{{ $t('list.share.links.remove') }}</span>
|
||||
</template>
|
||||
|
||||
|
||||
<template #text>
|
||||
<p>{{ $t('list.share.links.removeText') }}</p>
|
||||
</template>
|
||||
|
@ -190,6 +202,8 @@ import LinkShareService from '@/services/linkShare'
|
|||
|
||||
import {useCopyToClipboard} from '@/composables/useCopyToClipboard'
|
||||
import {success} from '@/message'
|
||||
import type {ListView} from '@/types/ListView'
|
||||
import {LIST_VIEWS} from '@/types/ListView'
|
||||
|
||||
const props = defineProps({
|
||||
listId: {
|
||||
|
@ -209,6 +223,17 @@ const showDeleteModal = ref(false)
|
|||
const linkIdToDelete = ref(0)
|
||||
const showNewForm = ref(false)
|
||||
|
||||
type SelectedViewMapper = Record<IList['id'], ListView>
|
||||
|
||||
const selectedView = ref<SelectedViewMapper>({})
|
||||
|
||||
const availableViews = computed<Record<ListView, string>>(() => ({
|
||||
list: t('list.list.title'),
|
||||
gantt: t('list.gantt.title'),
|
||||
table: t('list.table.title'),
|
||||
kanban: t('list.kanban.title'),
|
||||
}))
|
||||
|
||||
const copy = useCopyToClipboard()
|
||||
watch(
|
||||
() => props.listId,
|
||||
|
@ -225,7 +250,11 @@ async function load(listId: IList['id']) {
|
|||
return
|
||||
}
|
||||
|
||||
linkShares.value = await linkShareService.getAll({listId})
|
||||
const links = await linkShareService.getAll({listId})
|
||||
links.forEach((l: ILinkShare) => {
|
||||
selectedView.value[l.id] = 'list'
|
||||
})
|
||||
linkShares.value = links
|
||||
}
|
||||
|
||||
async function add(listId: IList['id']) {
|
||||
|
@ -257,15 +286,15 @@ async function remove(listId: IList['id']) {
|
|||
}
|
||||
}
|
||||
|
||||
function getShareLink(hash: string) {
|
||||
return frontendUrl.value + 'share/' + hash + '/auth'
|
||||
function getShareLink(hash: string, view: ListView = LIST_VIEWS.LIST) {
|
||||
return frontendUrl.value + 'share/' + hash + '/auth?view=' + view
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// FIXME: I think this is not needed
|
||||
.sharables-list:not(.card-content) {
|
||||
overflow-y: auto
|
||||
overflow-y: auto
|
||||
}
|
||||
|
||||
@include modal-transition();
|
||||
|
|
|
@ -242,7 +242,9 @@
|
|||
"remove": "Remove a link share",
|
||||
"removeText": "Are you sure you want to remove this link share? It will no longer be possible to access this list with this link share. This cannot be undone!",
|
||||
"createSuccess": "The link share was successfully created.",
|
||||
"deleteSuccess": "The link share was successfully deleted"
|
||||
"deleteSuccess": "The link share was successfully deleted",
|
||||
"view": "View",
|
||||
"sharedBy": "Shared by {0}"
|
||||
},
|
||||
"userTeam": {
|
||||
"typeUser": "user | users",
|
||||
|
@ -264,9 +266,6 @@
|
|||
},
|
||||
"attributes": {
|
||||
"link": "Link",
|
||||
"name": "Name",
|
||||
"sharedBy": "Shared by",
|
||||
"right": "Right",
|
||||
"delete": "Delete"
|
||||
}
|
||||
},
|
||||
|
|
8
src/types/ListView.ts
Normal file
8
src/types/ListView.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
export const LIST_VIEWS = {
|
||||
LIST: 'list',
|
||||
GANTT: 'gantt',
|
||||
TABLE: 'table',
|
||||
KANBAN: 'kanban',
|
||||
} as const
|
||||
|
||||
export type ListView = typeof LIST_VIEWS[keyof typeof LIST_VIEWS]
|
|
@ -41,6 +41,7 @@ import {useTitle} from '@vueuse/core'
|
|||
|
||||
import Message from '@/components/misc/message.vue'
|
||||
import {LOGO_VISIBLE} from '@/store/mutation-types'
|
||||
import {LIST_VIEWS, type ListView} from '@/types/ListView'
|
||||
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
useTitle(t('sharing.authenticating'))
|
||||
|
@ -79,7 +80,12 @@ function useAuth() {
|
|||
? route.query.logoVisible === 'true'
|
||||
: true
|
||||
store.commit(LOGO_VISIBLE, logoVisible)
|
||||
router.push({name: 'list.list', params: {listId}})
|
||||
|
||||
const view = route.query.view && Object.values(LIST_VIEWS).includes(route.query.view as ListView)
|
||||
? route.query.view
|
||||
: 'list'
|
||||
|
||||
router.push({name: `list.${view}`, params: {listId}})
|
||||
} catch (e: any) {
|
||||
if (e.response?.data?.code === 13001) {
|
||||
authenticateWithPassword.value = true
|
||||
|
|
Loading…
Reference in a new issue