feat(teams): add public flags to teams to allow easier sharing with other teams (#2179)
Resolves #2173 Co-authored-by: Daniel Herrmann <daniel.herrmann1@gmail.com> Reviewed-on: https://kolaente.dev/vikunja/vikunja/pulls/2179 Reviewed-by: konrad <k@knt.li> Co-authored-by: waza-ari <daniel.herrmann@makerspace-darmstadt.de> Co-committed-by: waza-ari <daniel.herrmann@makerspace-darmstadt.de>
This commit is contained in:
@ -172,6 +172,7 @@ import Multiselect from '@/components/input/multiselect.vue'
|
||||
import Nothing from '@/components/misc/nothing.vue'
|
||||
import {success} from '@/message'
|
||||
import {useAuthStore} from '@/stores/auth'
|
||||
import {useConfigStore} from '@/stores/config'
|
||||
|
||||
// FIXME: I think this whole thing can now only manage user/team sharing for projects? Maybe remove a little generalization?
|
||||
|
||||
@ -210,8 +211,8 @@ const selectedRight = ref({})
|
||||
const sharables = ref([])
|
||||
const showDeleteModal = ref(false)
|
||||
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const configStore = useConfigStore()
|
||||
const userInfo = computed(() => authStore.info)
|
||||
|
||||
function createShareTypeNameComputed(count: number) {
|
||||
@ -360,7 +361,15 @@ async function find(query: string) {
|
||||
found.value = []
|
||||
return
|
||||
}
|
||||
const results = await searchService.getAll({}, {s: query})
|
||||
|
||||
// Include public teams here if we are sharing with teams and its enabled in the config
|
||||
let results = []
|
||||
if (props.shareType === 'team' && configStore.publicTeamsEnabled) {
|
||||
results = await searchService.getAll({}, {s: query, includePublic: true})
|
||||
} else {
|
||||
results = await searchService.getAll({}, {s: query})
|
||||
}
|
||||
|
||||
found.value = results
|
||||
.filter(m => {
|
||||
if(props.shareType === 'user' && m.id === currentUserId.value) {
|
||||
|
@ -986,7 +986,9 @@
|
||||
"description": "Description",
|
||||
"descriptionPlaceholder": "Describe the team here, hit '/' for more options…",
|
||||
"admin": "Admin",
|
||||
"member": "Member"
|
||||
"member": "Member",
|
||||
"isPublic": "Public Team",
|
||||
"isPublicDescription": "Make the team publicly discoverable. When enabled, anyone can share projects with this team even when not being a direct member."
|
||||
}
|
||||
},
|
||||
"keyboardShortcuts": {
|
||||
|
@ -10,6 +10,7 @@ export interface ITeam extends IAbstract {
|
||||
members: ITeamMember[]
|
||||
right: Right
|
||||
oidcId: string
|
||||
isPublic: boolean
|
||||
|
||||
createdBy: IUser
|
||||
created: Date
|
||||
|
@ -14,6 +14,7 @@ export default class TeamModel extends AbstractModel<ITeam> implements ITeam {
|
||||
members: ITeamMember[] = []
|
||||
right: Right = RIGHTS.READ
|
||||
oidcId = ''
|
||||
isPublic: boolean = false
|
||||
|
||||
createdBy: IUser = {} // FIXME: seems wrong
|
||||
created: Date = null
|
||||
|
@ -37,6 +37,7 @@ export interface ConfigState {
|
||||
providers: IProvider[],
|
||||
},
|
||||
},
|
||||
publicTeamsEnabled: boolean,
|
||||
}
|
||||
|
||||
export const useConfigStore = defineStore('config', () => {
|
||||
@ -70,6 +71,7 @@ export const useConfigStore = defineStore('config', () => {
|
||||
providers: [],
|
||||
},
|
||||
},
|
||||
publicTeamsEnabled: false,
|
||||
})
|
||||
|
||||
const migratorsEnabled = computed(() => state.availableMigrators?.length > 0)
|
||||
|
@ -33,6 +33,27 @@
|
||||
>
|
||||
{{ $t('team.attributes.nameRequired') }}
|
||||
</p>
|
||||
<div
|
||||
v-if="configStore.publicTeamsEnabled"
|
||||
class="field"
|
||||
>
|
||||
<label
|
||||
class="label"
|
||||
for="teamIsPublic"
|
||||
>{{ $t('team.attributes.isPublic') }}</label>
|
||||
<div
|
||||
class="control is-expanded"
|
||||
:class="{ 'is-loading': teamService.loading }"
|
||||
>
|
||||
<Fancycheckbox
|
||||
v-model="team.isPublic"
|
||||
:disabled="teamMemberService.loading || undefined"
|
||||
:class="{ 'disabled': teamService.loading }"
|
||||
>
|
||||
{{ $t('team.attributes.isPublicDescription') }}
|
||||
</Fancycheckbox>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label
|
||||
class="label"
|
||||
@ -242,6 +263,7 @@ import {useI18n} from 'vue-i18n'
|
||||
import {useRoute, useRouter} from 'vue-router'
|
||||
|
||||
import Editor from '@/components/input/AsyncEditor'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||
import Multiselect from '@/components/input/multiselect.vue'
|
||||
import User from '@/components/misc/user.vue'
|
||||
|
||||
@ -254,12 +276,14 @@ import {RIGHTS as Rights} from '@/constants/rights'
|
||||
import {useTitle} from '@/composables/useTitle'
|
||||
import {success} from '@/message'
|
||||
import {useAuthStore} from '@/stores/auth'
|
||||
import {useConfigStore} from '@/stores/config'
|
||||
|
||||
import type {ITeam} from '@/modelTypes/ITeam'
|
||||
import type {IUser} from '@/modelTypes/IUser'
|
||||
import type {ITeamMember} from '@/modelTypes/ITeamMember'
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const configStore = useConfigStore()
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const {t} = useI18n({useScope: 'global'})
|
||||
|
@ -25,6 +25,26 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="configStore.publicTeamsEnabled"
|
||||
class="field"
|
||||
>
|
||||
<label
|
||||
class="label"
|
||||
for="teamIsPublic"
|
||||
>{{ $t('team.attributes.isPublic') }}</label>
|
||||
<div
|
||||
class="control is-expanded"
|
||||
:class="{ 'is-loading': teamService.loading }"
|
||||
>
|
||||
<Fancycheckbox
|
||||
v-model="team.isPublic"
|
||||
:class="{ 'disabled': teamService.loading }"
|
||||
>
|
||||
{{ $t('team.attributes.isPublicDescription') }}
|
||||
</Fancycheckbox>
|
||||
</div>
|
||||
</div>
|
||||
<p
|
||||
v-if="showError && team.name === ''"
|
||||
class="help is-danger"
|
||||
@ -46,11 +66,14 @@ import TeamModel from '@/models/team'
|
||||
import TeamService from '@/services/team'
|
||||
|
||||
import CreateEdit from '@/components/misc/create-edit.vue'
|
||||
import Fancycheckbox from '@/components/input/fancycheckbox.vue'
|
||||
|
||||
import {useTitle} from '@/composables/useTitle'
|
||||
import {useRouter} from 'vue-router'
|
||||
import {success} from '@/message'
|
||||
|
||||
import {useConfigStore} from '@/stores/config'
|
||||
|
||||
const {t} = useI18n()
|
||||
const title = computed(() => t('team.create.title'))
|
||||
useTitle(title)
|
||||
@ -60,6 +83,8 @@ const teamService = shallowReactive(new TeamService())
|
||||
const team = reactive(new TeamModel())
|
||||
const showError = ref(false)
|
||||
|
||||
const configStore = useConfigStore()
|
||||
|
||||
async function newTeam() {
|
||||
if (team.name === '') {
|
||||
showError.value = true
|
||||
|
Reference in New Issue
Block a user