2024-03-18 12:56:44 +00:00
|
|
|
<script setup lang="ts">
|
|
|
|
import type {IProjectView} from '@/modelTypes/IProjectView'
|
|
|
|
import XButton from '@/components/input/button.vue'
|
|
|
|
import FilterInput from '@/components/project/partials/FilterInput.vue'
|
2024-04-02 11:20:17 +00:00
|
|
|
import {ref, watch} from 'vue'
|
|
|
|
import {transformFilterStringForApi, transformFilterStringFromApi} from '@/helpers/filters'
|
|
|
|
import {useLabelStore} from '@/stores/labels'
|
|
|
|
import {useProjectStore} from '@/stores/projects'
|
|
|
|
|
|
|
|
const {
|
|
|
|
modelValue,
|
|
|
|
} = defineProps<{
|
|
|
|
modelValue: IProjectView,
|
|
|
|
}>()
|
|
|
|
|
|
|
|
const emit = defineEmits(['update:modelValue'])
|
|
|
|
|
|
|
|
const view = ref<IProjectView>()
|
|
|
|
|
|
|
|
const labelStore = useLabelStore()
|
|
|
|
const projectStore = useProjectStore()
|
|
|
|
|
|
|
|
watch(
|
|
|
|
() => modelValue,
|
|
|
|
newValue => {
|
|
|
|
const transformed = {
|
|
|
|
...newValue,
|
|
|
|
filter: transformFilterStringFromApi(
|
|
|
|
newValue.filter,
|
|
|
|
labelId => labelStore.getLabelById(labelId)?.title,
|
|
|
|
projectId => projectStore.projects[projectId]?.title || null,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JSON.stringify(view.value) !== JSON.stringify(transformed)) {
|
|
|
|
view.value = transformed
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{immediate: true, deep: true},
|
|
|
|
)
|
|
|
|
|
|
|
|
watch(
|
|
|
|
() => view.value,
|
|
|
|
newView => {
|
|
|
|
emit('update:modelValue', {
|
|
|
|
...newView,
|
|
|
|
filter: transformFilterStringForApi(
|
|
|
|
newView.filter,
|
|
|
|
labelTitle => labelStore.filterLabelsByQuery([], labelTitle)[0]?.id || null,
|
|
|
|
projectTitle => {
|
|
|
|
const found = projectStore.findProjectByExactname(projectTitle)
|
|
|
|
return found?.id || null
|
|
|
|
},
|
|
|
|
),
|
|
|
|
})
|
|
|
|
},
|
|
|
|
{deep: true},
|
|
|
|
)
|
2024-03-18 12:56:44 +00:00
|
|
|
|
|
|
|
const titleValid = ref(true)
|
2024-04-02 11:20:17 +00:00
|
|
|
|
2024-03-18 12:56:44 +00:00
|
|
|
function validateTitle() {
|
2024-04-02 11:20:17 +00:00
|
|
|
titleValid.value = view.value?.title !== ''
|
2024-03-18 12:56:44 +00:00
|
|
|
}
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<form>
|
|
|
|
<div class="field">
|
|
|
|
<label
|
|
|
|
class="label"
|
|
|
|
for="title"
|
|
|
|
>
|
|
|
|
{{ $t('project.views.title') }}
|
|
|
|
</label>
|
|
|
|
<div class="control">
|
|
|
|
<input
|
|
|
|
id="title"
|
2024-04-02 11:20:17 +00:00
|
|
|
v-model="view.title"
|
2024-03-18 12:56:44 +00:00
|
|
|
v-focus
|
|
|
|
class="input"
|
|
|
|
:placeholder="$t('project.share.links.namePlaceholder')"
|
|
|
|
@blur="validateTitle"
|
|
|
|
>
|
|
|
|
</div>
|
2024-04-02 11:20:17 +00:00
|
|
|
<p
|
2024-03-18 12:56:44 +00:00
|
|
|
v-if="!titleValid"
|
|
|
|
class="help is-danger"
|
|
|
|
>
|
|
|
|
{{ $t('project.views.titleRequired') }}
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="field">
|
|
|
|
<label
|
|
|
|
class="label"
|
|
|
|
for="kind"
|
|
|
|
>
|
|
|
|
{{ $t('project.views.kind') }}
|
|
|
|
</label>
|
|
|
|
<div class="control">
|
|
|
|
<div class="select">
|
|
|
|
<select
|
|
|
|
id="kind"
|
2024-04-02 11:20:17 +00:00
|
|
|
v-model="view.viewKind"
|
2024-03-18 12:56:44 +00:00
|
|
|
>
|
|
|
|
<option value="list">
|
|
|
|
{{ $t('project.list.title') }}
|
|
|
|
</option>
|
|
|
|
<option value="gantt">
|
|
|
|
{{ $t('project.gantt.title') }}
|
|
|
|
</option>
|
|
|
|
<option value="table">
|
|
|
|
{{ $t('project.table.title') }}
|
|
|
|
</option>
|
|
|
|
<option value="kanban">
|
|
|
|
{{ $t('project.kanban.title') }}
|
|
|
|
</option>
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<FilterInput
|
2024-04-02 11:20:17 +00:00
|
|
|
v-model="view.filter"
|
2024-03-18 12:56:44 +00:00
|
|
|
:input-label="$t('project.views.filter')"
|
|
|
|
/>
|
|
|
|
|
|
|
|
<div
|
2024-04-02 11:20:17 +00:00
|
|
|
v-if="view.viewKind === 'kanban'"
|
2024-03-18 12:56:44 +00:00
|
|
|
class="field"
|
|
|
|
>
|
|
|
|
<label
|
|
|
|
class="label"
|
|
|
|
for="configMode"
|
|
|
|
>
|
|
|
|
{{ $t('project.views.bucketConfigMode') }}
|
|
|
|
</label>
|
|
|
|
<div class="control">
|
|
|
|
<div class="select">
|
|
|
|
<select
|
|
|
|
id="configMode"
|
2024-04-02 11:20:17 +00:00
|
|
|
v-model="view.bucketConfigurationMode"
|
2024-03-18 12:56:44 +00:00
|
|
|
>
|
|
|
|
<option value="manual">
|
|
|
|
{{ $t('project.views.bucketConfigManual') }}
|
|
|
|
</option>
|
|
|
|
<option value="filter">
|
|
|
|
{{ $t('project.views.filter') }}
|
|
|
|
</option>
|
|
|
|
</select>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div
|
2024-04-02 11:20:17 +00:00
|
|
|
v-if="view.viewKind === 'kanban' && view.bucketConfigurationMode === 'filter'"
|
2024-03-18 12:56:44 +00:00
|
|
|
class="field"
|
|
|
|
>
|
|
|
|
<label class="label">
|
|
|
|
{{ $t('project.views.bucketConfig') }}
|
|
|
|
</label>
|
|
|
|
<div class="control">
|
|
|
|
<div
|
2024-04-02 11:20:17 +00:00
|
|
|
v-for="(b, index) in view.bucketConfiguration"
|
2024-03-18 12:56:44 +00:00
|
|
|
:key="'bucket_'+index"
|
|
|
|
class="filter-bucket"
|
|
|
|
>
|
|
|
|
<button
|
|
|
|
class="is-danger"
|
2024-04-02 11:20:17 +00:00
|
|
|
@click.prevent="() => view.bucketConfiguration.splice(index, 1)"
|
2024-03-18 12:56:44 +00:00
|
|
|
>
|
2024-04-02 12:04:17 +00:00
|
|
|
<icon icon="trash-alt" />
|
2024-03-18 12:56:44 +00:00
|
|
|
</button>
|
|
|
|
<div class="filter-bucket-form">
|
|
|
|
<div class="field">
|
2024-03-18 23:46:18 +00:00
|
|
|
<label
|
|
|
|
class="label"
|
|
|
|
:for="'bucket_'+index+'_title'"
|
|
|
|
>
|
2024-03-18 12:56:44 +00:00
|
|
|
{{ $t('project.views.title') }}
|
|
|
|
</label>
|
|
|
|
<div class="control">
|
|
|
|
<input
|
|
|
|
:id="'bucket_'+index+'_title'"
|
2024-04-02 11:20:17 +00:00
|
|
|
v-model="view.bucketConfiguration[index].title"
|
2024-03-18 12:56:44 +00:00
|
|
|
class="input"
|
|
|
|
:placeholder="$t('project.share.links.namePlaceholder')"
|
|
|
|
>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<FilterInput
|
2024-04-02 11:20:17 +00:00
|
|
|
v-model="view.bucketConfiguration[index].filter"
|
2024-03-18 23:46:18 +00:00
|
|
|
:input-label="$t('project.views.filter')"
|
2024-03-18 12:56:44 +00:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class="is-flex is-justify-content-end">
|
2024-03-18 23:46:18 +00:00
|
|
|
<XButton
|
2024-03-18 12:56:44 +00:00
|
|
|
variant="secondary"
|
|
|
|
icon="plus"
|
2024-04-02 11:20:17 +00:00
|
|
|
@click="() => view.bucketConfiguration.push({title: '', filter: ''})"
|
2024-03-18 12:56:44 +00:00
|
|
|
>
|
|
|
|
{{ $t('project.kanban.addBucket') }}
|
2024-03-18 23:46:18 +00:00
|
|
|
</XButton>
|
2024-03-18 12:56:44 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
.filter-bucket {
|
|
|
|
display: flex;
|
|
|
|
|
|
|
|
button {
|
|
|
|
background: transparent;
|
|
|
|
border: none;
|
|
|
|
color: var(--danger);
|
|
|
|
padding-right: .75rem;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
&-form {
|
|
|
|
margin-bottom: .5rem;
|
|
|
|
padding: .5rem;
|
|
|
|
border: 1px solid var(--grey-200);
|
|
|
|
border-radius: $radius;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|