mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-13 19:58:09 +00:00
Ability to change done state (#888)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
parent
b2f3479a24
commit
a5f662e43f
@ -428,6 +428,14 @@ export function createModel (builder: Builder): void {
|
||||
presenter: task.component.StatePresenter
|
||||
})
|
||||
|
||||
builder.mixin(task.class.DoneState, core.class.Class, view.mixin.AttributeEditor, {
|
||||
editor: task.component.DoneStateEditor
|
||||
})
|
||||
|
||||
builder.mixin(task.class.DoneState, core.class.Class, view.mixin.AttributePresenter, {
|
||||
presenter: task.component.DoneStatePresenter
|
||||
})
|
||||
|
||||
builder.createDoc(
|
||||
view.class.ViewletDescriptor,
|
||||
core.space.Model,
|
||||
|
@ -55,6 +55,7 @@ export default mergeIds(taskId, task, {
|
||||
StatePresenter: '' as AnyComponent,
|
||||
DoneStatePresenter: '' as AnyComponent,
|
||||
StateEditor: '' as AnyComponent,
|
||||
DoneStateEditor: '' as AnyComponent,
|
||||
KanbanView: '' as AnyComponent,
|
||||
Todos: '' as AnyComponent,
|
||||
TodoItemPresenter: '' as AnyComponent,
|
||||
|
@ -13,7 +13,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import type { Doc } from '@anticrm/core'
|
||||
import { getResource } from '@anticrm/platform'
|
||||
@ -37,7 +36,7 @@
|
||||
|
||||
$: attribute = typeof key === 'string' ? hierarchy.getAttribute(_class, key) : key.attr
|
||||
$: attributeKey = typeof key === 'string' ? key : key.key
|
||||
$: typeClassId = (attribute !== undefined) ? getAttributePresenterClass(attribute) : undefined
|
||||
$: typeClassId = attribute !== undefined ? getAttributePresenterClass(attribute) : undefined
|
||||
|
||||
let editor: Promise<AnySvelteComponent> | undefined
|
||||
|
||||
@ -57,7 +56,6 @@
|
||||
{#await editor}
|
||||
...
|
||||
{:then instance}
|
||||
|
||||
{#if attribute.icon}
|
||||
<div class="flex-row-center">
|
||||
<CircleButton icon={attribute.icon} size={'large'} />
|
||||
@ -66,19 +64,46 @@
|
||||
{#if showHeader}
|
||||
<Label label={attribute.label} />
|
||||
{/if}
|
||||
<div class="value"><svelte:component this={instance} label={attribute?.label} placeholder={attribute?.label} {maxWidth} value={getAttribute(client, object, { key: attributeKey, attr: attribute })} {onChange} {focus}/></div>
|
||||
<div class="value">
|
||||
<svelte:component
|
||||
this={instance}
|
||||
label={attribute?.label}
|
||||
placeholder={attribute?.label}
|
||||
{maxWidth}
|
||||
value={getAttribute(client, object, { key: attributeKey, attr: attribute })}
|
||||
space={object.space}
|
||||
{onChange}
|
||||
{focus}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{:else if showHeader}
|
||||
<div class="flex-col">
|
||||
<Label label={attribute.label} />
|
||||
<div class="value"><svelte:component this={instance} label={attribute?.label} placeholder={attribute?.label} {maxWidth} value={getAttribute(client, object, { key: attributeKey, attr: attribute })} {onChange} {focus}/></div>
|
||||
<div class="value">
|
||||
<svelte:component
|
||||
this={instance}
|
||||
label={attribute?.label}
|
||||
placeholder={attribute?.label}
|
||||
{maxWidth}
|
||||
value={getAttribute(client, object, { key: attributeKey, attr: attribute })}
|
||||
space={object.space}
|
||||
{onChange}
|
||||
{focus}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<svelte:component this={instance} {maxWidth} value={getAttribute(client, object, { key: attributeKey, attr: attribute })} {onChange} {focus}/>
|
||||
<svelte:component
|
||||
this={instance}
|
||||
{maxWidth}
|
||||
value={getAttribute(client, object, { key: attributeKey, attr: attribute })}
|
||||
space={object.space}
|
||||
{onChange}
|
||||
{focus}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{/await}
|
||||
{/if}
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
"DoneStates": "Done states",
|
||||
"States": "States",
|
||||
"ChooseAColor": "Choose a color",
|
||||
"SearchTask": "Search for task..."
|
||||
"SearchTask": "Search for task...",
|
||||
"NoDoneState": "Not done"
|
||||
}
|
||||
}
|
@ -67,6 +67,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<AttributeBarEditor key={'state'} {object} showHeader={false} />
|
||||
<AttributeBarEditor key={'doneState'} {object} showHeader={false} />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -0,0 +1,70 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Ref } from '@anticrm/core'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import { DoneState, SpaceWithStates } from '@anticrm/task'
|
||||
import { Label, showPopup } from '@anticrm/ui'
|
||||
import DoneStatePresenter from './DoneStatePresenter.svelte'
|
||||
import DoneStatesPopup from './DoneStatesPopup.svelte'
|
||||
import task from '../../plugin'
|
||||
|
||||
export let value: Ref<DoneState> | null | undefined
|
||||
export let onChange: (value: any) => void
|
||||
export let space: Ref<SpaceWithStates>
|
||||
let state: DoneState | undefined
|
||||
let container: HTMLElement
|
||||
let opened: boolean = false
|
||||
|
||||
const query = createQuery()
|
||||
$: if (value != null) {
|
||||
query.query(
|
||||
task.class.DoneState,
|
||||
{ _id: value },
|
||||
(res) => {
|
||||
state = res[0]
|
||||
},
|
||||
{ limit: 1 }
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex-row-center cursor-pointer"
|
||||
bind:this={container}
|
||||
on:click|preventDefault={() => {
|
||||
if (!opened) {
|
||||
opened = true
|
||||
showPopup(DoneStatesPopup, { space }, container, (result) => {
|
||||
if (result) {
|
||||
value = result._id
|
||||
onChange(value)
|
||||
} else if (result == null) {
|
||||
value = null
|
||||
onChange(value)
|
||||
}
|
||||
|
||||
opened = false
|
||||
})
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if state}
|
||||
<DoneStatePresenter value={state} showTitle />
|
||||
{:else}
|
||||
<Label label={task.string.NoDoneState} />
|
||||
{/if}
|
||||
</div>
|
@ -17,16 +17,21 @@
|
||||
<script lang="ts">
|
||||
import type { DoneState } from '@anticrm/task'
|
||||
import task from '@anticrm/task'
|
||||
import { getPlatformColor } from '@anticrm/ui'
|
||||
|
||||
export let value: DoneState
|
||||
export let showTitle: boolean = false
|
||||
|
||||
$: color = value._class === task.class.WonState ? '#a5d179' : '#f28469'
|
||||
$: color = value._class === task.class.WonState ? getPlatformColor(0) : getPlatformColor(11)
|
||||
|
||||
</script>
|
||||
|
||||
{#if value }
|
||||
<div class="flex-center">
|
||||
<div class="state-container" style="background-color: {color};" />
|
||||
<div class="state-container" class:state-container-title={showTitle} style="background-color: {color};" />
|
||||
{#if showTitle}
|
||||
{value.title}
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@ -36,4 +41,7 @@
|
||||
height: .5rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
.state-container-title {
|
||||
margin-right: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
|
@ -0,0 +1,100 @@
|
||||
<!--
|
||||
// Copyright © 2020, 2021 Anticrm Platform Contributors.
|
||||
// Copyright © 2021 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { Class, Doc, Ref, SortingOrder } from '@anticrm/core'
|
||||
import { createQuery } from '@anticrm/presentation'
|
||||
import { DoneState, SpaceWithStates } from '@anticrm/task'
|
||||
import { getPlatformColor, Label } from '@anticrm/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import task from '../../plugin'
|
||||
|
||||
export let space: Ref<SpaceWithStates>
|
||||
let states: DoneState[] = []
|
||||
const dispatch = createEventDispatcher()
|
||||
const statesQuery = createQuery()
|
||||
statesQuery.query(
|
||||
task.class.DoneState,
|
||||
{ space },
|
||||
(res) => {
|
||||
states = res
|
||||
},
|
||||
{
|
||||
sort: {
|
||||
rank: SortingOrder.Ascending
|
||||
}
|
||||
}
|
||||
)
|
||||
function getColor (_class: Ref<Class<Doc>>): string {
|
||||
return _class === task.class.WonState ? getPlatformColor(0) : getPlatformColor(11)
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex-col statuses-container">
|
||||
{#each states as state}
|
||||
<div
|
||||
class="flex-row-center state"
|
||||
on:click={() => {
|
||||
dispatch('close', state)
|
||||
}}
|
||||
>
|
||||
<div class="color" style="background-color: {getColor(state._class)}" />
|
||||
{state.title}
|
||||
</div>
|
||||
{/each}
|
||||
<div
|
||||
class="flex-row-center state"
|
||||
on:click={() => {
|
||||
dispatch('close', null)
|
||||
}}
|
||||
>
|
||||
<div class='not-done'>
|
||||
<Label label={task.string.NoDoneState}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.statuses-container {
|
||||
padding: 0.5rem;
|
||||
max-height: 100%;
|
||||
min-width: 10rem;
|
||||
color: var(--theme-caption-color);
|
||||
background-color: var(--theme-button-bg-focused);
|
||||
border: 1px solid var(--theme-button-border-enabled);
|
||||
border-radius: 0.75rem;
|
||||
user-select: none;
|
||||
filter: drop-shadow(0 1.5rem 4rem rgba(0, 0, 0, 0.35));
|
||||
|
||||
.state {
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--theme-button-bg-hovered);
|
||||
}
|
||||
.color {
|
||||
margin-right: 0.75rem;
|
||||
width: .5rem;
|
||||
height: .5rem;
|
||||
border-radius: .5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.not-done {
|
||||
margin-left: 1.25rem;
|
||||
}
|
||||
</style>
|
@ -26,6 +26,7 @@ import EditIssue from './components/EditIssue.svelte'
|
||||
import KanbanView from './components/kanban/KanbanView.svelte'
|
||||
import KanbanCard from './components/KanbanCard.svelte'
|
||||
import DoneStatePresenter from './components/state/DoneStatePresenter.svelte'
|
||||
import DoneStateEditor from './components/state/DoneStateEditor.svelte'
|
||||
import EditStatuses from './components/state/EditStatuses.svelte'
|
||||
import StateEditor from './components/state/StateEditor.svelte'
|
||||
import StatePresenter from './components/state/StatePresenter.svelte'
|
||||
@ -140,7 +141,8 @@ export default async (): Promise<Resources> => ({
|
||||
TodoItemPresenter,
|
||||
TodoStatePresenter,
|
||||
StatusTableView,
|
||||
TaskHeader
|
||||
TaskHeader,
|
||||
DoneStateEditor
|
||||
},
|
||||
actionImpl: {
|
||||
CreateTask: createTask,
|
||||
|
@ -58,7 +58,8 @@ export default mergeIds(taskId, task, {
|
||||
DoneStatesWon: '' as IntlString,
|
||||
DoneStatesLost: '' as IntlString,
|
||||
AllStates: '' as IntlString,
|
||||
ChooseAColor: '' as IntlString
|
||||
ChooseAColor: '' as IntlString,
|
||||
NoDoneState: '' as IntlString
|
||||
},
|
||||
status: {
|
||||
AssigneeRequired: '' as IntlString
|
||||
|
Loading…
Reference in New Issue
Block a user