mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-24 01:07:50 +00:00
UBER-219: updated CreateIssue layout (#3244)
Signed-off-by: Alexander Platov <sas_lord@mail.ru>
This commit is contained in:
parent
d8e69eb6bc
commit
edfc99ccd8
@ -14,17 +14,16 @@
|
||||
"AddSocialLinks": "Add social links",
|
||||
"EditSocialLinks": "Edit social links",
|
||||
"Change": "Change",
|
||||
"Remove": "Remove",
|
||||
"Remove": "Remove",
|
||||
"Search": "Search...",
|
||||
"Spaces": "Spaces",
|
||||
"CreateMore": "Create more",
|
||||
"Spaces": "Spaces",
|
||||
"NumberSpaces": "{count, plural, =0 {In} =1 {In 1 place} other {In # places}}",
|
||||
"InThis": "In this {space}",
|
||||
"NoMatchesInThis": "No matches in this {space}",
|
||||
"NoMatchesFound": "No matches found",
|
||||
"NotInThis": "Not in this {space}",
|
||||
"Add": "Add",
|
||||
"Edit": "Edit",
|
||||
"Edit": "Edit",
|
||||
"DocumentPreview": "Preview",
|
||||
"MakePrivate": "Make private",
|
||||
"MakePrivateDescription": "Only members can see it"
|
||||
|
@ -16,8 +16,7 @@
|
||||
"Change": "Изменить",
|
||||
"Remove": "Удалить",
|
||||
"Search": "Поиск...",
|
||||
"Spaces": "Пространства",
|
||||
"CreateMore": "Создать еще",
|
||||
"Spaces": "Пространства",
|
||||
"NumberSpaces": "{count, plural, =0 {В} =1 {В 1 месте} other {В # местах}}",
|
||||
"InThis": "В этом {space}",
|
||||
"NoMatchesInThis": "В этом {space} совпадения не обнаружены",
|
||||
|
@ -15,7 +15,7 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import { Button, IconClose, Label, MiniToggle, Scroller } from '@hcengineering/ui'
|
||||
import { Button, IconClose, Label, Scroller } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import presentation from '..'
|
||||
import { deviceOptionsStore as deviceInfo, resizeObserver } from '@hcengineering/ui'
|
||||
@ -25,10 +25,12 @@
|
||||
export let labelProps: any | undefined = undefined
|
||||
export let okAction: () => Promise<void> | void
|
||||
export let canSave: boolean = false
|
||||
export let createMore: boolean | undefined = undefined
|
||||
export let okLabel: IntlString = presentation.string.Create
|
||||
export let onCancel: Function | undefined = undefined
|
||||
export let fullSize = false
|
||||
export let fullSize: boolean = false
|
||||
export let hideAttachments: boolean = false
|
||||
export let hideSubheader: boolean = false
|
||||
export let gap: string | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@ -44,7 +46,7 @@
|
||||
dispatch('changeContent')
|
||||
}}
|
||||
>
|
||||
<div class="antiCard-header">
|
||||
<div class="antiCard-header" class:withSub={$$slots.subheader && !hideSubheader}>
|
||||
<div class="antiCard-header__title-wrap">
|
||||
{#if $$slots.header}
|
||||
<slot name="header" />
|
||||
@ -58,12 +60,15 @@
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
<div class="buttons-group small-gap">
|
||||
<div class="buttons-group small-gap content-dark-color">
|
||||
<Button
|
||||
id="card-close"
|
||||
focusIndex={10002}
|
||||
icon={IconClose}
|
||||
iconSize={'medium'}
|
||||
iconProps={{ fill: 'var(--theme-dark-color)' }}
|
||||
kind={'transparent'}
|
||||
size={'small'}
|
||||
on:click={() => {
|
||||
if (onCancel) {
|
||||
onCancel()
|
||||
@ -74,25 +79,35 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Scroller horizontal>
|
||||
<div class="antiCard-content">
|
||||
<slot />
|
||||
{#if $$slots.subheader && !hideSubheader}
|
||||
<div class="antiCard-subheader">
|
||||
<slot name="subheader" />
|
||||
</div>
|
||||
</Scroller>
|
||||
{/if}
|
||||
<div class="antiCard-content">
|
||||
<Scroller padding={$$slots.pool ? '.5rem 1.5rem' : '.5rem 1.5rem 1.5rem'} {gap}>
|
||||
<slot />
|
||||
</Scroller>
|
||||
</div>
|
||||
{#if $$slots.pool}
|
||||
<div class="antiCard-pool">
|
||||
<slot name="pool" />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="antiCard-pool__separator" />
|
||||
<div class="antiCard-footer reverse">
|
||||
{#if $$slots.attachments && !hideAttachments}
|
||||
<div class="antiCard-attachments">
|
||||
<Scroller horizontal contentDirection={'horizontal'} {gap}>
|
||||
<div class="antiCard-attachments__container">
|
||||
<slot name="attachments" />
|
||||
</div>
|
||||
</Scroller>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="antiCard-footer divide reverse">
|
||||
<div class="buttons-group text-sm flex-no-shrink">
|
||||
{#if $$slots.buttons}
|
||||
<slot name="buttons" />
|
||||
{/if}
|
||||
{#if createMore !== undefined}
|
||||
<MiniToggle label={presentation.string.CreateMore} bind:on={createMore} />
|
||||
{/if}
|
||||
<Button
|
||||
loading={okProcessing}
|
||||
focusIndex={10001}
|
||||
@ -109,11 +124,9 @@
|
||||
if (r instanceof Promise) {
|
||||
r.then(() => {
|
||||
okProcessing = false
|
||||
if (!createMore) {
|
||||
dispatch('close')
|
||||
}
|
||||
dispatch('close')
|
||||
})
|
||||
} else if (!createMore) {
|
||||
} else {
|
||||
okProcessing = false
|
||||
dispatch('close')
|
||||
}
|
||||
|
@ -36,7 +36,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="antiCard-content"><slot /></div>
|
||||
<div class="antiCard-content px-6"><slot /></div>
|
||||
<div class="antiCard-footer">
|
||||
<Button
|
||||
disabled={!canSave}
|
||||
|
@ -18,7 +18,5 @@
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M11.4,7.7L5.7,2.1C5.5,1.9,5.2,1.9,5,2.1S4.8,2.6,5,2.8L10.3,8L5,13.3c-0.2,0.2-0.2,0.5,0,0.7c0.1,0.1,0.2,0.1,0.4,0.1s0.3,0,0.4-0.1l5.6-5.6c0.1-0.1,0.1-0.2,0.1-0.4S11.4,7.8,11.4,7.7z"
|
||||
/>
|
||||
<path d="M11.0001 8L6.00008 3L5.29297 3.70711L9.58586 8L5.29297 12.2929L6.00008 13L11.0001 8Z" />
|
||||
</svg>
|
||||
|
@ -46,7 +46,6 @@ export default plugin(presentationId, {
|
||||
Remove: '' as IntlString,
|
||||
Search: '' as IntlString,
|
||||
Spaces: '' as IntlString,
|
||||
CreateMore: '' as IntlString,
|
||||
NumberMembers: '' as IntlString,
|
||||
NumberSpaces: '' as IntlString,
|
||||
InThis: '' as IntlString,
|
||||
|
@ -130,7 +130,7 @@
|
||||
max-height: inherit !important;
|
||||
outline: none;
|
||||
line-height: 150%;
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
p:not(:last-child) {
|
||||
margin-block-end: 1em;
|
||||
@ -148,10 +148,13 @@
|
||||
p.is-editor-empty:first-child::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: var(--dark-color);
|
||||
color: var(--theme-halfcontent-color);
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
&:focus-within p.is-editor-empty:first-child::before {
|
||||
color: var(--theme-trans-color);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--scrollbar-bar-color);
|
||||
@ -166,14 +169,6 @@
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
/* Placeholder (at the top) */
|
||||
.ProseMirror p.is-editor-empty:first-child::before {
|
||||
color: #adb5bd;
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
height: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.lint-icon {
|
||||
display: inline-block;
|
||||
@ -227,7 +222,7 @@
|
||||
}
|
||||
|
||||
.code-block {
|
||||
border: 1px solid var(--divider-color);
|
||||
border: 1px solid var(--theme-divider-color);
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
export let showButtons = true
|
||||
export let buttonSize: IconSize = 'small'
|
||||
export let focus = false
|
||||
export let emphasized: boolean = false
|
||||
export let kind: 'normal' | 'emphasized' | 'indented' = 'normal'
|
||||
export let isScrollable: boolean = false
|
||||
export let maxHeight: 'max' | 'card' | 'limited' | string | undefined = undefined
|
||||
export let required = false
|
||||
@ -49,8 +49,9 @@
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="antiComponent styled-box clear-mins"
|
||||
class:antiEmphasized={emphasized}
|
||||
class="antiComponent styled-box focusable clear-mins"
|
||||
class:antiEmphasized={kind === 'emphasized'}
|
||||
class:antiIndented={kind === 'indented'}
|
||||
on:click={() => {
|
||||
textEditor?.focus()
|
||||
}}
|
||||
|
@ -22,7 +22,7 @@
|
||||
export let content: string
|
||||
export let placeholder: IntlString = textEditorPlugin.string.EditorPlaceholder
|
||||
|
||||
export let emphasized: boolean = false
|
||||
export let kind: 'normal' | 'emphasized' | 'indented' = 'normal'
|
||||
export let alwaysEdit: boolean = false
|
||||
export let showButtons: boolean = true
|
||||
export let hideAttachments: boolean = false
|
||||
@ -133,8 +133,9 @@
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="antiComponent styled-box clear-mins"
|
||||
class:antiEmphasized={emphasized}
|
||||
class:antiEmphasized-focus={(mode === Mode.Edit || alwaysEdit) && focused}
|
||||
class:antiEmphasized={kind === 'emphasized'}
|
||||
class:antiIndented={kind === 'indented'}
|
||||
class:focusable={(mode === Mode.Edit || alwaysEdit) && focused}
|
||||
on:click={() => {
|
||||
if (alwaysEdit && focused) {
|
||||
textEditor?.focus()
|
||||
@ -230,9 +231,7 @@
|
||||
|
||||
.label {
|
||||
padding-bottom: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--caption-color);
|
||||
opacity: 0.3;
|
||||
color: var(--theme-halfcontent-color);
|
||||
transition: top 200ms;
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
|
@ -80,6 +80,7 @@
|
||||
|
||||
let textEditor: TextEditor
|
||||
let isEmpty = true
|
||||
let contentHeight: number
|
||||
|
||||
export function submit (): void {
|
||||
textEditor.submit()
|
||||
@ -551,7 +552,13 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="textInput" class:focusable>
|
||||
<div class="inputMsg" class:scrollable={isScrollable} style="--texteditor-maxheight: {varsStyle};">
|
||||
<div
|
||||
bind:clientHeight={contentHeight}
|
||||
class="inputMsg"
|
||||
class:scrollable={isScrollable}
|
||||
class:showScroll={contentHeight > 32}
|
||||
style="--texteditor-maxheight: {varsStyle};"
|
||||
>
|
||||
{#if isScrollable}
|
||||
<Scroller>
|
||||
<TextEditor
|
||||
@ -617,21 +624,21 @@
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 4.5rem;
|
||||
min-height: 1.25rem;
|
||||
|
||||
.textInput {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
min-height: 2.75rem;
|
||||
min-height: 1.25rem;
|
||||
background-color: transparent;
|
||||
|
||||
.inputMsg {
|
||||
align-self: stretch;
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
color: var(--content-color);
|
||||
color: var(--theme-caption-color);
|
||||
background-color: transparent;
|
||||
|
||||
:global(.ProseMirror) {
|
||||
@ -639,6 +646,9 @@
|
||||
// max-height: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
&:not(.showScroll)::-webkit-scrollbar-thumb {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&.scrollable {
|
||||
overflow: auto;
|
||||
|
@ -248,7 +248,7 @@
|
||||
max-height: inherit !important;
|
||||
outline: none;
|
||||
line-height: 150%;
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
p:not(:last-child) {
|
||||
margin-block-end: 1em;
|
||||
@ -262,10 +262,13 @@
|
||||
p.is-editor-empty:first-child::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: var(--dark-color);
|
||||
color: var(--theme-halfcontent-color);
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
&:focus-within p.is-editor-empty:first-child::before {
|
||||
color: var(--theme-trans-color);
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--scrollbar-bar-color);
|
||||
|
@ -69,13 +69,14 @@
|
||||
--theme-button-pressed: rgba(255, 255, 255, .08);
|
||||
--theme-button-focused: rgba(255, 255, 255, .04);
|
||||
--theme-button-disabled: rgba(255, 255, 255, .02);
|
||||
--theme-button-border: rgba(255, 255, 255, .06);
|
||||
--theme-button-border: rgba(255, 255, 255, .09);
|
||||
|
||||
--theme-refinput-color: rgba(255, 255, 255, .03);
|
||||
--theme-refinput-divider: rgba(255, 255, 255, .07);
|
||||
--theme-refinput-border: rgba(255, 255, 255, .03);
|
||||
|
||||
--theme-bg-color: #1A1A28;
|
||||
--theme-bg-accent-color: rgba(0, 0, 0, .08);
|
||||
--theme-back-color: #0f0f18;
|
||||
--theme-overlay-color: rgba(0, 0, 0, .3);
|
||||
--theme-statusbar-color: #2C2C35;
|
||||
@ -239,13 +240,14 @@
|
||||
--theme-button-pressed: rgba(0, 0, 0, .08);
|
||||
--theme-button-focused: rgba(0, 0, 0, .04);
|
||||
--theme-button-disabled: rgba(0, 0, 0, .02);
|
||||
--theme-button-border: rgba(0, 0, 0, .06);
|
||||
--theme-button-border: rgba(0, 0, 0, .09);
|
||||
|
||||
--theme-refinput-color: rgba(0, 0, 0, .03);
|
||||
--theme-refinput-divider: rgba(0, 0, 0, .07);
|
||||
--theme-refinput-border: rgba(0, 0, 0, .03);
|
||||
|
||||
--theme-bg-color: #F1F1F4;
|
||||
--theme-bg-accent-color: rgba(255, 255, 255, .08);
|
||||
--theme-back-color: #D9D9DD;
|
||||
--theme-overlay-color: rgba(0, 0, 0, .2);
|
||||
--theme-statusbar-color: #bfbfc6;
|
||||
|
@ -59,8 +59,9 @@ input {
|
||||
font: inherit;
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
color: var(--caption-color);
|
||||
&::placeholder { color: var(--dark-color); }
|
||||
color: var(--theme-caption-color);
|
||||
&::placeholder { color: var(--theme-halfcontent-color); }
|
||||
&:focus::placeholder { color: var(--theme-trans-color); }
|
||||
&.wrong-input { background-color: var(--system-error-color) !important; }
|
||||
}
|
||||
audio, canvas, embed, iframe, img, object, svg, video {
|
||||
@ -77,7 +78,7 @@ textarea:-webkit-autofill:focus,
|
||||
select:-webkit-autofill,
|
||||
select:-webkit-autofill:hover,
|
||||
select:-webkit-autofill:focus {
|
||||
-webkit-text-fill-color: var(--caption-color);
|
||||
-webkit-text-fill-color: var(--theme-caption-color);
|
||||
transition: background-color 5000s ease-in-out 0s;
|
||||
background: transparent;
|
||||
}
|
||||
@ -278,9 +279,9 @@ input.search {
|
||||
background-color: var(--avatar-bg-color);
|
||||
border-radius: 50%;
|
||||
}
|
||||
&:not(.small-gap, .medium-gap) { margin-right: .5rem; }
|
||||
&:not(.small-gap, .large-gap) { margin-right: .375rem; }
|
||||
&.small-gap { margin-right: .25rem; }
|
||||
&.medium-gap { margin-right: .375rem; }
|
||||
&.large-gap { margin-right: .5rem; }
|
||||
}
|
||||
.label {
|
||||
min-width: 0;
|
||||
@ -407,6 +408,11 @@ input.search {
|
||||
&:not(.reverse) > *:not(:first-child) { margin-left: .75rem; }
|
||||
&.reverse > *:not(:last-child) { margin-right: .75rem; }
|
||||
}
|
||||
.gap-4 {
|
||||
&:not(.reverse) > *:not(:first-child) { margin-left: 1rem; }
|
||||
&.reverse > *:not(:last-child) { margin-right: 1rem; }
|
||||
}
|
||||
.gapV-4 > *:not(:last-child) { margin-bottom: 1rem; }
|
||||
.gap-around-2 > * { margin: .25rem; }
|
||||
.gap-around-4 > * { margin: .5rem; }
|
||||
|
||||
@ -491,6 +497,7 @@ input.search {
|
||||
.m--1 { margin: -.25rem; }
|
||||
.m-0-5 { margin: .125rem; }
|
||||
.m-1 { margin: .25rem; }
|
||||
.m-3 { margin: .75rem; }
|
||||
|
||||
.pl-1 { padding-left: .25rem; }
|
||||
.pl-2 { padding-left: .5rem; }
|
||||
@ -613,6 +620,7 @@ input.search {
|
||||
.w-full { width: 100%; }
|
||||
.w-2 { width: .5rem; }
|
||||
.w-4 { width: 1rem; }
|
||||
.w-6 { width: 1.5rem; }
|
||||
.w-9 { width: 2.25rem; }
|
||||
.w-14 { width: 3.5rem; }
|
||||
.w-16 { width: 4rem; }
|
||||
@ -641,6 +649,7 @@ input.search {
|
||||
.max-w-2 { max-width: .5rem; }
|
||||
.max-w-4 { max-width: 1rem; }
|
||||
.max-w-9 { max-width: 2.25rem; }
|
||||
.max-w-20 { max-width: 5rem; }
|
||||
.max-w-30 { max-width: 7.5rem; }
|
||||
.max-w-40 { max-width: 10rem; }
|
||||
.max-w-60 { max-width: 15rem; }
|
||||
@ -843,9 +852,9 @@ a.no-line {
|
||||
&:hover { background-color: var(--scrollbar-bar-hover); }
|
||||
}
|
||||
.scroll-divider-color::-webkit-scrollbar-thumb {
|
||||
background-color: var(--divider-color);
|
||||
background-color: var(--theme-divider-color);
|
||||
&:horizontal { border-radius: .25rem .25rem 0 0; }
|
||||
&:hover { background-color: var(--popup-bg-hover); }
|
||||
&:hover { background-color: var(--theme-popup-hover); }
|
||||
}
|
||||
|
||||
/* Backgrounds & Colors */
|
||||
|
@ -2,7 +2,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 0 0.625rem;
|
||||
padding: 0 0.75rem;
|
||||
min-width: 1.375rem;
|
||||
white-space: nowrap;
|
||||
color: var(--theme-caption-color);
|
||||
@ -11,6 +11,12 @@
|
||||
transition-property: border, background-color, color, box-shadow;
|
||||
transition-duration: 0.15s;
|
||||
|
||||
&.iconL:not(.iconR) {
|
||||
padding: 0 1rem 0 0.75rem;
|
||||
}
|
||||
&.iconR:not(.iconL) {
|
||||
padding: 0 0.75rem 0 1rem;
|
||||
}
|
||||
&.accent {
|
||||
font-weight: 500;
|
||||
}
|
||||
@ -26,10 +32,10 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
&:not(.only-icon) .btn-icon:not(.spinner) {
|
||||
margin-right: 0.5rem;
|
||||
margin-right: 0.375rem;
|
||||
}
|
||||
&:not(.only-icon) .btn-right-icon {
|
||||
margin-left: 0.5rem;
|
||||
margin-left: 0.375rem;
|
||||
}
|
||||
&.no-border:not(.only-icon) .btn-icon,
|
||||
&.link-bordered:not(.only-icon) .btn-icon,
|
||||
@ -39,7 +45,7 @@
|
||||
}
|
||||
|
||||
&.short {
|
||||
max-width: 7rem;
|
||||
max-width: 8.5rem;
|
||||
}
|
||||
&.sh-no-shape {
|
||||
border-radius: 0.25rem;
|
||||
|
@ -424,6 +424,17 @@
|
||||
// Replacing the background of a text editor in Activity
|
||||
.activity-content .ref-container .textInput { background-color: var(--body-color) !important; }
|
||||
|
||||
// Indented
|
||||
.antiIndented {
|
||||
margin: .75rem;
|
||||
border-radius: .25rem;
|
||||
|
||||
&:hover,
|
||||
&.focusable:focus-within {
|
||||
border-color: var(--theme-divider-color);
|
||||
}
|
||||
}
|
||||
|
||||
// Emphasized
|
||||
.antiEmphasized {
|
||||
padding: .75rem;
|
||||
@ -435,7 +446,7 @@
|
||||
transition-timing-function: var(--timing-main);
|
||||
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
&.focusable:focus-within {
|
||||
// background-color: var(--body-color);
|
||||
border-color: var(--theme-list-divider-color);
|
||||
}
|
||||
|
@ -39,8 +39,9 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: 1.5rem 1.5rem .5rem 1.75rem;
|
||||
font-size: .8125rem;
|
||||
|
||||
&.withSub { padding: 1.5rem 1.5rem 0; }
|
||||
&:not(.withSub) { padding: 1.5rem 1.5rem 1rem; }
|
||||
|
||||
&__title-wrap {
|
||||
display: flex;
|
||||
@ -58,7 +59,7 @@
|
||||
line-height: 150%;
|
||||
color: var(--theme-caption-color);
|
||||
}
|
||||
&__divider { color: var(--theme-content-color); }
|
||||
&__divider { color: var(--theme-dark-color); }
|
||||
&__error {
|
||||
min-width: 0;
|
||||
flex-grow: 1;
|
||||
@ -74,17 +75,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
.antiCard-subheader {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
padding: .5rem 1.5rem 1rem;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.antiCard-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
flex-shrink: 1;
|
||||
padding: 1rem 1.75rem;
|
||||
// margin: 1.5rem 1.5rem .5rem;
|
||||
height: fit-content;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
|
||||
& > *:not(:last-child) { margin-bottom: 1rem; }
|
||||
}
|
||||
|
||||
.antiCard-pool {
|
||||
@ -92,18 +100,41 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin: .5rem 1.25rem 0 1.75rem;
|
||||
margin: .5rem 1.5rem 1.5rem;
|
||||
min-width: 0;
|
||||
font-size: .8125rem;
|
||||
color: var(--theme-caption-color);
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 100%;
|
||||
order: 0;
|
||||
}
|
||||
&__separator {
|
||||
flex-shrink: 0;
|
||||
margin-top: 1.25rem;
|
||||
margin-top: 1.5rem;
|
||||
height: 1px;
|
||||
background-color: var(--theme-popup-divider);
|
||||
}
|
||||
& > * { margin: .5rem .5rem 0 0; }
|
||||
.new-line {
|
||||
min-width: 0;
|
||||
order: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.antiCard-attachments {
|
||||
background-color: var(--theme-bg-accent-color);
|
||||
border-top: 1px solid var(--theme-popup-divider);
|
||||
|
||||
&__container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 1rem 1.5rem;
|
||||
|
||||
& > * { margin-right: 1rem; }
|
||||
& > *:last-child { margin-right: 1.5rem; }
|
||||
}
|
||||
}
|
||||
|
||||
.antiCard-footer {
|
||||
@ -113,10 +144,11 @@
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1rem 1.75rem;
|
||||
padding: 1rem 1.5rem;
|
||||
height: 4.25rem;
|
||||
border-radius: 0 0 .5rem .5rem;
|
||||
|
||||
|
||||
&.divide { border-top: 1px solid var(--theme-popup-divider); }
|
||||
&.reverse { flex-direction: row-reverse; }
|
||||
&__error {
|
||||
flex-grow: 1;
|
||||
|
@ -53,9 +53,11 @@
|
||||
export let accent: boolean = false
|
||||
|
||||
// $: iconSize = size === 'inline' ? 'inline' : 'small'
|
||||
let iconOnly: boolean = false
|
||||
$: iconOnly =
|
||||
label === undefined &&
|
||||
($$slots.content === undefined || $$slots.icon !== undefined || $$slots.iconRight !== undefined)
|
||||
$$slots.content === undefined &&
|
||||
(icon !== undefined || iconRight !== undefined || $$slots.icon || $$slots.iconRight)
|
||||
|
||||
onMount(() => {
|
||||
if (focus && input) {
|
||||
@ -102,6 +104,8 @@
|
||||
class:highlight
|
||||
class:selected
|
||||
class:notSelected
|
||||
class:iconL={(icon || $$slots.icon) && (label || $$slots.content)}
|
||||
class:iconR={(iconRight || $$slots.iconRight) && (label || $$slots.content)}
|
||||
disabled={disabled || loading}
|
||||
class:short
|
||||
style:width
|
||||
@ -149,13 +153,20 @@
|
||||
width: 1.375rem;
|
||||
}
|
||||
}
|
||||
.small {
|
||||
.x-small {
|
||||
height: 1.5rem;
|
||||
font-size: 0.75rem;
|
||||
&.only-icon {
|
||||
width: 1.5rem;
|
||||
}
|
||||
}
|
||||
.small {
|
||||
height: 1.75rem;
|
||||
font-size: 0.8125rem;
|
||||
&.only-icon {
|
||||
width: 1.75rem;
|
||||
}
|
||||
}
|
||||
.medium {
|
||||
height: 2rem;
|
||||
&.only-icon {
|
||||
|
@ -34,6 +34,7 @@
|
||||
export let maxDigitsAfterPoint: number | undefined = undefined
|
||||
export let kind: EditStyle = 'editbox'
|
||||
export let focus: boolean = false
|
||||
export let select: boolean = false
|
||||
export let focusable: boolean = false
|
||||
export let disabled: boolean = false
|
||||
export let fullSize = false
|
||||
@ -89,6 +90,10 @@
|
||||
input.focus()
|
||||
focus = false
|
||||
}
|
||||
if (select) {
|
||||
input.select()
|
||||
select = false
|
||||
}
|
||||
computeSize(input)
|
||||
})
|
||||
|
||||
@ -99,6 +104,9 @@
|
||||
export function focusInput () {
|
||||
input?.focus()
|
||||
}
|
||||
export function selectInput () {
|
||||
input?.select()
|
||||
}
|
||||
|
||||
// Focusable control with index
|
||||
export let focusIndex = -1
|
||||
@ -218,12 +226,11 @@
|
||||
|
||||
input {
|
||||
padding: 0.25rem 0.5rem;
|
||||
background-color: var(--accent-bg-color);
|
||||
border: 1px solid transparent;
|
||||
background-color: var(--theme-editbox-focus-color);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid var(--primary-edit-border-color);
|
||||
box-shadow: 0 0 0 1px var(--theme-editbox-focus-border);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,12 +238,11 @@
|
||||
margin: 0 -0.75rem;
|
||||
padding: 0.625rem 0.75rem;
|
||||
width: calc(100% + 1.5rem);
|
||||
border: 1px solid transparent;
|
||||
border-radius: 0.25rem;
|
||||
transition: border-color 0.15s ease-in-out;
|
||||
|
||||
&:focus-within {
|
||||
border-color: var(--primary-edit-border-color);
|
||||
box-shadow: 0 0 0 1px var(--theme-editbox-focus-border);
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +250,7 @@
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-caption-color);
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
</script>
|
||||
|
||||
{#if isAsset(icon)}
|
||||
<svg class="svg-{size}" fill={_fill}>
|
||||
<svg class="svg-{size}" fill={_fill} {...iconProps}>
|
||||
<use href={url} />
|
||||
</svg>
|
||||
{:else if typeof icon !== 'string'}
|
||||
|
@ -475,7 +475,7 @@
|
||||
divHeight = element.clientHeight
|
||||
}}
|
||||
class="scroll relative flex-shrink"
|
||||
class:overflow-x={horizontal ? 'auto' : 'hidden'}
|
||||
style:overflow-x={horizontal ? 'auto' : 'hidden'}
|
||||
on:scroll={(evt) => {
|
||||
if ($tooltipstore.label !== undefined) closeTooltip()
|
||||
const newPos = divScroll?.scrollTop ?? 0
|
||||
|
@ -23,7 +23,7 @@
|
||||
export let title: IntlString
|
||||
export let value: number | null | undefined = null
|
||||
export let withTime: boolean = false
|
||||
export let icon: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let iconModifier: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let labelNull: IntlString = ui.string.NoDate
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -41,6 +41,6 @@
|
||||
<div class="antiSelect antiWrapper cursor-default">
|
||||
<div class="flex-col">
|
||||
<span class="label mb-1"><Label label={title} /></span>
|
||||
<DatePresenter {value} {mode} {icon} {labelNull} editable on:change={changeValue} />
|
||||
<DatePresenter {value} {mode} {iconModifier} {labelNull} editable on:change={changeValue} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -13,24 +13,26 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import type { IntlString } from '@hcengineering/platform'
|
||||
import type { IntlString, Asset } from '@hcengineering/platform'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
import { DateRangeMode } from '@hcengineering/core'
|
||||
import ui from '../../plugin'
|
||||
import { showPopup } from '../../popups'
|
||||
import { ButtonKind, ButtonSize } from '../../types'
|
||||
import { ButtonKind, ButtonSize, AnySvelteComponent } from '../../types'
|
||||
import Icon from '../Icon.svelte'
|
||||
import Label from '../Label.svelte'
|
||||
import DatePopup from './DatePopup.svelte'
|
||||
import DPCalendar from './icons/DPCalendar.svelte'
|
||||
import { getMonthName } from './internal/DateUtils'
|
||||
import { ComponentType } from 'svelte'
|
||||
|
||||
export let value: number | null | undefined
|
||||
export let mode: DateRangeMode = DateRangeMode.DATE
|
||||
export let mondayStart: boolean = true
|
||||
export let editable: boolean = false
|
||||
export let icon: 'normal' | 'warning' | 'critical' | 'overdue' = 'normal'
|
||||
export let icon: Asset | AnySvelteComponent | ComponentType | undefined = undefined
|
||||
export let iconModifier: 'normal' | 'warning' | 'critical' | 'overdue' = 'normal'
|
||||
export let labelNull: IntlString = ui.string.NoDate
|
||||
export let showIcon = true
|
||||
export let shouldShowLabel: boolean = true
|
||||
@ -68,6 +70,7 @@
|
||||
class:editable
|
||||
class:dateTimeButtonNoLabel={!shouldShowLabel}
|
||||
class:text-xs={size === 'x-small'}
|
||||
class:noDate={!value}
|
||||
style:width
|
||||
on:click={(e) => {
|
||||
if (editable && !opened) {
|
||||
@ -89,8 +92,8 @@
|
||||
}}
|
||||
>
|
||||
{#if showIcon}
|
||||
<div class="btn-icon {icon}" class:buttonIconNoLabel={!shouldShowLabel}>
|
||||
<Icon icon={DPCalendar} size="full" />
|
||||
<div class="btn-icon {iconModifier}" class:buttonIconNoLabel={!shouldShowLabel}>
|
||||
<Icon icon={icon ?? DPCalendar} size="full" />
|
||||
</div>
|
||||
{/if}
|
||||
{#if value !== null && value !== undefined}
|
||||
@ -185,7 +188,7 @@
|
||||
transition-duration: 0;
|
||||
|
||||
.not-selected {
|
||||
color: var(--theme-caption-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
}
|
||||
&.editable {
|
||||
@ -324,6 +327,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.noDate .btn-icon {
|
||||
color: var(--theme-dark-color);
|
||||
}
|
||||
&.noDate:hover .btn-icon {
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
|
||||
.time-divider {
|
||||
flex-shrink: 0;
|
||||
margin: 0 0.25rem;
|
||||
|
@ -23,7 +23,7 @@
|
||||
export let title: IntlString
|
||||
export let value: number | null | undefined = null
|
||||
export let withTime: boolean = false
|
||||
export let icon: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let iconModifier: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let labelNull: IntlString = ui.string.NoDate
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -39,6 +39,13 @@
|
||||
<div class="antiSelect antiWrapper cursor-default">
|
||||
<div class="flex-col">
|
||||
<span class="label mb-1"><Label label={title} /></span>
|
||||
<DateRangePresenter {value} mode={DateRangeMode.DATETIME} {icon} {labelNull} editable on:change={changeValue} />
|
||||
<DateRangePresenter
|
||||
{value}
|
||||
mode={DateRangeMode.DATETIME}
|
||||
{iconModifier}
|
||||
{labelNull}
|
||||
editable
|
||||
on:change={changeValue}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -28,7 +28,7 @@
|
||||
export let value: number | null | undefined = null
|
||||
export let mode: DateRangeMode = DateRangeMode.DATE
|
||||
export let editable: boolean = false
|
||||
export let icon: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let iconModifier: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let labelNull: IntlString = ui.string.NoDate
|
||||
export let kind: 'default' | 'no-border' | 'link' | 'secondary' = 'default'
|
||||
export let size: 'small' | 'medium' | 'large' = 'small'
|
||||
@ -392,7 +392,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="btn-icon {icon}">
|
||||
<div class="btn-icon {iconModifier}">
|
||||
<Icon icon={DPCalendar} size={'full'} />
|
||||
</div>
|
||||
{#if value !== undefined && value !== null && value.toString() !== ''}
|
||||
|
@ -20,9 +20,9 @@
|
||||
|
||||
export let value: number | null | undefined
|
||||
export let editable: boolean = false
|
||||
export let icon: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let iconModifier: 'normal' | 'warning' | 'overdue' = 'normal'
|
||||
export let labelNull: IntlString = ui.string.NoDate
|
||||
export let noShift: boolean = false
|
||||
</script>
|
||||
|
||||
<DateRangePresenter bind:value mode={DateRangeMode.DATETIME} {editable} {icon} {labelNull} {noShift} />
|
||||
<DateRangePresenter bind:value mode={DateRangeMode.DATETIME} {editable} {iconModifier} {labelNull} {noShift} />
|
||||
|
@ -93,6 +93,6 @@
|
||||
}
|
||||
: undefined}
|
||||
>
|
||||
<DatePresenter {value} {editable} icon={iconModifier} {kind} {size} {width} on:change={handleDueDateChanged} />
|
||||
<DatePresenter {value} {editable} {iconModifier} {kind} {size} {width} on:change={handleDueDateChanged} />
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -15,11 +15,13 @@
|
||||
-->
|
||||
<script lang="ts">
|
||||
export let size: 'small' | 'medium' | 'large'
|
||||
const fill: string = 'currentColor'
|
||||
export let fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3,8.5L8.1,3c1.1-1.2,2.9-1.2,4,0c1.1,1.2,1.1,3,0,4.2l-5.9,6.3c-0.4,0.5-1.1,0.5-1.6,0c-0.4-0.5-0.4-1.2,0-1.7l5.9-6.3c0.2-0.2,0.2-0.6,0-0.8c-0.2-0.2-0.6-0.2-0.8,0L3.7,11c-0.9,0.9-0.9,2.4,0,3.3c0.9,0.9,2.3,0.9,3.2,0l5.9-6.3c1.5-1.6,1.5-4.2,0-5.8c-1.5-1.6-4-1.6-5.5,0L2.2,7.6c-0.2,0.2-0.2,0.6,0,0.8C2.4,8.7,2.7,8.7,3,8.5z"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M26.682 5.31802C24.9246 3.56066 22.0754 3.56066 20.318 5.31802L5.31802 20.318C3.56066 22.0754 3.56066 24.9246 5.31802 26.682C7.07538 28.4393 9.92462 28.4393 11.682 26.682L11.6875 26.6765L14.1575 24.282C14.5541 23.8976 15.1871 23.9074 15.5716 24.304C15.956 24.7005 15.9461 25.3336 15.5496 25.718L13.0905 28.1019C10.5516 30.6346 6.44031 30.6327 3.90381 28.0962C1.3654 25.5578 1.3654 21.4422 3.90381 18.9038L18.9038 3.90381C21.4422 1.3654 25.5578 1.3654 28.0962 3.90381C30.6346 6.44221 30.6346 10.5578 28.0962 13.0962L20.5104 20.682C18.753 22.4393 15.9038 22.4393 14.1464 20.682C12.3891 18.9246 12.3891 16.0754 14.1464 14.318L17.7929 10.6716C18.1834 10.281 18.8166 10.281 19.2071 10.6716C19.5976 11.0621 19.5976 11.6953 19.2071 12.0858L15.5607 15.7322C14.5843 16.7085 14.5843 18.2915 15.5607 19.2678C16.537 20.2441 18.1199 20.2441 19.0962 19.2678L26.682 11.682C28.4393 9.92462 28.4393 7.07538 26.682 5.31802Z"
|
||||
/>
|
||||
</svg>
|
||||
|
@ -3,8 +3,8 @@
|
||||
export let fill: string = 'currentColor'
|
||||
</script>
|
||||
|
||||
<svg class="svg-{size}" {fill} viewBox="-7 -7 38 38" xmlns="http://www.w3.org/2000/svg">
|
||||
<svg class="svg-{size}" {fill} viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M0.439127 21.44C0.157865 21.7214 -9.37008e-05 22.103 7.33302e-08 22.5008C9.38474e-05 22.8987 0.158232 23.2802 0.439627 23.5615C0.721022 23.8427 1.10262 24.0007 1.50048 24.0006C1.89834 24.0005 2.27987 23.8424 2.56113 23.561L11.8231 14.3C11.8463 14.2767 11.8739 14.2582 11.9043 14.2456C11.9347 14.233 11.9672 14.2265 12.0001 14.2265C12.033 14.2265 12.0656 14.233 12.0959 14.2456C12.1263 14.2582 12.1539 14.2767 12.1771 14.3L21.4391 23.563C21.5784 23.7023 21.7437 23.8128 21.9257 23.8883C22.1077 23.9637 22.3028 24.0025 22.4998 24.0026C22.6968 24.0026 22.8919 23.9639 23.0739 23.8885C23.2559 23.8132 23.4213 23.7027 23.5606 23.5635C23.7 23.4242 23.8105 23.2589 23.8859 23.0769C23.9614 22.8949 24.0002 22.6998 24.0003 22.5028C24.0003 22.3058 23.9615 22.1107 23.8862 21.9287C23.8109 21.7467 23.7004 21.5813 23.5611 21.442L14.3001 12.177C14.2768 12.1537 14.2584 12.1262 14.2458 12.0958C14.2332 12.0654 14.2267 12.0329 14.2267 12C14.2267 11.9671 14.2332 11.9345 14.2458 11.9042C14.2584 11.8738 14.2768 11.8462 14.3001 11.823L23.5631 2.56097C23.8444 2.27931 24.0022 1.89745 24.002 1.49941C24.0017 1.10136 23.8433 0.71973 23.5616 0.438468C23.28 0.157206 22.8981 -0.000647135 22.5001 -0.000365836C22.102 -8.45362e-05 21.7204 0.158308 21.4391 0.439968L12.1771 9.69997C12.1539 9.72325 12.1263 9.74172 12.0959 9.75432C12.0656 9.76693 12.033 9.77342 12.0001 9.77342C11.9672 9.77342 11.9347 9.76693 11.9043 9.75432C11.8739 9.74172 11.8463 9.72325 11.8231 9.69997L2.56113 0.439968C2.42186 0.300636 2.25651 0.190098 2.07453 0.114667C1.89254 0.0392356 1.69748 0.000387673 1.50048 0.000341244C1.10262 0.000247476 0.721022 0.158206 0.439627 0.439468C0.158232 0.72073 9.38099e-05 1.10226 4.17235e-08 1.50011C-9.37265e-05 1.89797 0.157865 2.27957 0.439127 2.56097L9.70013 11.823C9.72341 11.8462 9.74188 11.8738 9.75448 11.9042C9.76709 11.9345 9.77357 11.9671 9.77357 12C9.77357 12.0329 9.76709 12.0654 9.75448 12.0958C9.74188 12.1262 9.72341 12.1537 9.70013 12.177L0.439127 21.44Z"
|
||||
d="M5.18306 5.18306C4.93898 5.42714 4.93898 5.82286 5.18306 6.06694L9.11612 10L5.18306 13.9331C4.93898 14.1771 4.93898 14.5729 5.18306 14.8169C5.42714 15.061 5.82286 15.061 6.06694 14.8169L10 10.8839L13.9331 14.8169C14.1771 15.061 14.5729 15.061 14.8169 14.8169C15.061 14.5729 15.061 14.1771 14.8169 13.9331L10.8839 10L14.8169 6.06694C15.061 5.82286 15.061 5.42714 14.8169 5.18306C14.5729 4.93898 14.1771 4.93898 13.9331 5.18306L10 9.11612L6.06694 5.18306C5.82286 4.93898 5.42714 4.93898 5.18306 5.18306Z"
|
||||
/>
|
||||
</svg>
|
||||
|
@ -125,7 +125,7 @@ export type ButtonKind =
|
||||
| 'dangerous'
|
||||
| 'list'
|
||||
| 'list-header'
|
||||
export type ButtonSize = 'inline' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
export type ButtonSize = 'inline' | 'x-small' | 'small' | 'medium' | 'large' | 'x-large'
|
||||
export type ButtonShape = 'rectangle' | 'rectangle-left' | 'rectangle-right' | 'circle' | 'round' | 'filter' | undefined
|
||||
export type EditStyle = 'editbox' | 'large-style' | 'small-style' | 'search-style' | 'underline'
|
||||
export interface PopupPositionElement {
|
||||
|
@ -81,6 +81,7 @@
|
||||
>
|
||||
<div
|
||||
class="flex-center icon"
|
||||
class:svg={value.type === 'image/svg+xml'}
|
||||
class:image={isImage(value.type)}
|
||||
style:background-image={isImage(value.type) ? `url(${getFileUrl(value.file)})` : 'none'}
|
||||
>
|
||||
@ -106,7 +107,7 @@
|
||||
on:click={(ev) => {
|
||||
ev.stopPropagation()
|
||||
ev.preventDefault()
|
||||
dispatch('remove')
|
||||
dispatch('remove', value)
|
||||
}}
|
||||
>
|
||||
<Label label={presentation.string.Delete} />
|
||||
@ -118,33 +119,43 @@
|
||||
|
||||
<style lang="scss">
|
||||
.attachment-container {
|
||||
padding: 0.375rem 0.75rem 0.375rem 0.375rem;
|
||||
flex-shrink: 0;
|
||||
width: auto;
|
||||
height: 3rem;
|
||||
min-width: 14rem;
|
||||
max-width: 19rem;
|
||||
background-color: var(--theme-button-enabled);
|
||||
border: 1px solid var(--theme-button-border);
|
||||
background-color: var(--theme-button-hovered);
|
||||
border-radius: 0.25rem;
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
margin-right: 0.75rem;
|
||||
width: 3.25rem;
|
||||
height: 3.25rem;
|
||||
border: 1px solid var(--primary-button-border);
|
||||
border-radius: 0.25rem;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border: 1px solid var(--theme-button-border);
|
||||
border-radius: 0.25rem 0 0 0.25rem;
|
||||
cursor: pointer;
|
||||
|
||||
&:not(.image) {
|
||||
color: var(--primary-button-color);
|
||||
background-color: var(--primary-button-enabled);
|
||||
}
|
||||
&.svg {
|
||||
background-color: #fff;
|
||||
}
|
||||
&.image {
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
}
|
||||
.info-container {
|
||||
padding: 0.5rem 0.75rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid var(--theme-button-border);
|
||||
border-left: none;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
}
|
||||
.name {
|
||||
white-space: nowrap;
|
||||
font-size: 0.8125rem;
|
||||
@ -152,7 +163,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
.info-content {
|
||||
margin-top: 0.125rem;
|
||||
white-space: nowrap;
|
||||
font-size: 0.6875rem;
|
||||
color: var(--theme-darker-color);
|
||||
|
@ -32,7 +32,7 @@
|
||||
export let placeholder: IntlString | undefined = undefined
|
||||
export let alwaysEdit = false
|
||||
export let showButtons = false
|
||||
export let emphasized: boolean = false
|
||||
export let kind: 'normal' | 'emphasized' | 'indented' = 'normal'
|
||||
export let buttonSize: IconSize = 'medium'
|
||||
export let formatButtonSize: IconSize = 'small'
|
||||
export let maxHeight: 'max' | 'card' | 'limited' | string = 'max'
|
||||
@ -302,6 +302,11 @@
|
||||
export function isEmptyContent (): boolean {
|
||||
return refInput.isEmptyContent()
|
||||
}
|
||||
|
||||
$: dispatch('attachments', {
|
||||
size: attachments.size,
|
||||
values: attachments.size === 0 ? true : attachments
|
||||
})
|
||||
</script>
|
||||
|
||||
<input
|
||||
@ -337,7 +342,7 @@
|
||||
{formatButtonSize}
|
||||
{maxHeight}
|
||||
{focusable}
|
||||
{emphasized}
|
||||
{kind}
|
||||
{enableBackReferences}
|
||||
on:changeSize
|
||||
on:changeContent
|
||||
|
@ -36,7 +36,7 @@
|
||||
<Icon icon={board.icon.Card} {size} />
|
||||
{done}/{total}
|
||||
{#if item.dueTo !== null}
|
||||
<DatePresenter value={item.dueTo} size="x-small" icon={getDateIcon(item)} kind="transparent" />
|
||||
<DatePresenter value={item.dueTo} size="x-small" iconModifier={getDateIcon(item)} kind="transparent" />
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
{#if value}
|
||||
<div class="flex-presenter flex-gap-1 h-full">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="flex-center h-full" on:click>
|
||||
<div class="flex-row-center background-button-bg-color pr-1 pl-1 border-radius-1 w-full">
|
||||
{#if value.startDate}
|
||||
@ -21,7 +22,7 @@
|
||||
<DatePresenter
|
||||
bind:value={value.dueDate}
|
||||
mode={DateRangeMode.DATETIME}
|
||||
icon={isOverdue ? 'overdue' : undefined}
|
||||
iconModifier={isOverdue ? 'overdue' : undefined}
|
||||
{size}
|
||||
kind="transparent"
|
||||
/>
|
||||
|
@ -80,7 +80,7 @@
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<StyledTextBox
|
||||
emphasized
|
||||
kind={'emphasized'}
|
||||
content={object.description}
|
||||
on:value={(evt) => {
|
||||
client.update(object, { description: evt.detail })
|
||||
|
@ -64,6 +64,7 @@
|
||||
export let showTooltip: LabelAndProps | undefined = undefined
|
||||
export let showNavigate = true
|
||||
export let id: string | undefined = undefined
|
||||
export let short: boolean = false
|
||||
|
||||
const icon = IconPerson
|
||||
|
||||
@ -147,7 +148,7 @@
|
||||
>
|
||||
{#if selected}
|
||||
{#if hideIcon || selected}
|
||||
<UserInfo value={selected} size={avatarSize} {icon} on:accent-color />
|
||||
<UserInfo value={selected} size={avatarSize} {icon} {short} on:accent-color />
|
||||
{:else}
|
||||
{getName(selected)}
|
||||
{/if}
|
||||
|
@ -23,12 +23,13 @@
|
||||
export let subtitle: string | undefined = undefined
|
||||
export let size: IconSize
|
||||
export let icon: Asset | AnySvelteComponent | undefined = undefined
|
||||
export let short: boolean = false
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="flex-row-center" on:click>
|
||||
<Avatar avatar={value.avatar} {size} {icon} on:accent-color />
|
||||
<div class="flex-col min-w-0 {size === 'tiny' || size === 'inline' ? 'ml-1' : 'ml-2'}">
|
||||
<div class="flex-col min-w-0 {size === 'tiny' || size === 'inline' ? 'ml-1' : 'ml-2'}" class:max-w-20={short}>
|
||||
{#if subtitle}<div class="content-dark-color text-sm">{subtitle}</div>{/if}
|
||||
<div class="label overflow-label text-left">{getName(value)}</div>
|
||||
</div>
|
||||
|
@ -106,6 +106,7 @@
|
||||
labelProps={{ type: typeLabel }}
|
||||
okAction={saveRequest}
|
||||
canSave={value !== undefined && !notLimit}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
|
@ -35,7 +35,6 @@
|
||||
|
||||
let firstName = ''
|
||||
let lastName = ''
|
||||
let createMore: boolean = false
|
||||
|
||||
export function canClose (): boolean {
|
||||
return firstName === '' && lastName === ''
|
||||
@ -43,7 +42,7 @@
|
||||
|
||||
let avatarEditor: EditableAvatar
|
||||
|
||||
let object: Customer = {
|
||||
const object: Customer = {
|
||||
_class: contact.class.Person
|
||||
} as Customer
|
||||
|
||||
@ -92,18 +91,6 @@
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (createMore) {
|
||||
// Prepare for next
|
||||
object = {
|
||||
_class: targetClass._id
|
||||
} as Customer
|
||||
customerId = generateId()
|
||||
avatar = undefined
|
||||
firstName = ''
|
||||
lastName = ''
|
||||
channels = []
|
||||
}
|
||||
}
|
||||
|
||||
const targets = [
|
||||
@ -163,7 +150,6 @@
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
bind:createMore
|
||||
on:changeContent
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
|
@ -71,13 +71,12 @@
|
||||
export let preserveVacancy = false
|
||||
|
||||
let status: Status = OK
|
||||
let createMore: boolean = false
|
||||
|
||||
let _space = space
|
||||
|
||||
$: _candidate = candidate
|
||||
|
||||
let doc: Applicant = {
|
||||
const doc: Applicant = {
|
||||
state: '' as Ref<State>,
|
||||
doneState: null,
|
||||
number: 0,
|
||||
@ -160,30 +159,6 @@
|
||||
message: _comment
|
||||
})
|
||||
}
|
||||
|
||||
if (createMore) {
|
||||
// Prepare for next
|
||||
_candidate = '' as Ref<Candidate>
|
||||
_comment = ''
|
||||
doc = {
|
||||
state: selectedState?._id as Ref<State>,
|
||||
doneState: null,
|
||||
number: 0,
|
||||
assignee,
|
||||
rank: '',
|
||||
attachedTo: _candidate,
|
||||
attachedToClass: recruit.mixin.Candidate,
|
||||
_class: recruit.class.Applicant,
|
||||
space: _space,
|
||||
_id: generateId(),
|
||||
collection: 'applications',
|
||||
modifiedOn: Date.now(),
|
||||
modifiedBy: '' as Ref<Account>,
|
||||
startDate: null,
|
||||
dueDate: null
|
||||
}
|
||||
fillDefaults(hierarchy, doc, recruit.class.Applicant)
|
||||
}
|
||||
}
|
||||
|
||||
async function invokeValidate (
|
||||
@ -295,7 +270,7 @@
|
||||
label={recruit.string.CreateApplication}
|
||||
okAction={createApplication}
|
||||
canSave={status.severity === Severity.OK}
|
||||
bind:createMore
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
@ -367,7 +342,7 @@
|
||||
space={_space}
|
||||
alwaysEdit
|
||||
showButtons={false}
|
||||
emphasized
|
||||
kind={'emphasized'}
|
||||
bind:content={_comment}
|
||||
placeholder={recruit.string.Description}
|
||||
on:changeSize={() => dispatch('changeContent')}
|
||||
|
@ -111,7 +111,6 @@
|
||||
type: string
|
||||
lastModified: number
|
||||
}
|
||||
let createMore: boolean = false
|
||||
|
||||
export function canClose (): boolean {
|
||||
return true
|
||||
@ -271,9 +270,7 @@
|
||||
|
||||
await applyOps.commit()
|
||||
draftController.remove()
|
||||
if (!createMore) {
|
||||
dispatch('close', object._id)
|
||||
}
|
||||
dispatch('close', object._id)
|
||||
resetObject()
|
||||
}
|
||||
|
||||
@ -516,7 +513,6 @@
|
||||
dispatch('close')
|
||||
}}
|
||||
onCancel={showConfirmationDialog}
|
||||
bind:createMore
|
||||
on:changeContent
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
|
@ -236,6 +236,7 @@
|
||||
label={recruit.string.CreateVacancy}
|
||||
okAction={createVacancy}
|
||||
canSave={!!name}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
@ -266,7 +267,7 @@
|
||||
maxHeight={'card'}
|
||||
bind:content={fullDescription}
|
||||
placeholder={recruit.string.FullDescription}
|
||||
emphasized
|
||||
kind={'emphasized'}
|
||||
/>
|
||||
{/key}
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
||||
<div class="mt-3">
|
||||
{#key template._id}
|
||||
<StyledTextBox
|
||||
emphasized
|
||||
kind={'emphasized'}
|
||||
alwaysEdit
|
||||
showButtons={false}
|
||||
content={template.description ?? ''}
|
||||
|
@ -83,6 +83,7 @@
|
||||
label={recruit.string.CreateOpinion}
|
||||
okAction={createOpinion}
|
||||
canSave={(doc.value ?? '').trim().length > 0}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
@ -95,5 +96,5 @@
|
||||
placeholder={recruit.string.OpinionValuePlaceholder}
|
||||
focus
|
||||
/>
|
||||
<StyledTextArea placeholder={recruit.string.Description} bind:content={doc.description} emphasized />
|
||||
<StyledTextArea placeholder={recruit.string.Description} bind:content={doc.description} kind={'emphasized'} />
|
||||
</Card>
|
||||
|
@ -150,6 +150,7 @@
|
||||
labelProps={{ label: '' }}
|
||||
okAction={createReview}
|
||||
canSave={status.severity === Severity.OK && title.trim().length > 0 && doc.attachedTo !== undefined}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
@ -158,7 +159,7 @@
|
||||
<StatusControl slot="error" {status} />
|
||||
<EditBox placeholder={recruit.string.Title} bind:value={title} kind={'large-style'} focus />
|
||||
<EditBox placeholder={recruit.string.Location} bind:value={location} kind={'small-style'} />
|
||||
<StyledTextArea bind:content={description} placeholder={recruit.string.AddDescription} emphasized />
|
||||
<StyledTextArea bind:content={description} placeholder={recruit.string.AddDescription} kind={'emphasized'} />
|
||||
<svelte:fragment slot="pool">
|
||||
{#if !preserveCandidate}
|
||||
<UserBox
|
||||
|
@ -62,6 +62,7 @@
|
||||
label={recruit.string.Opinion}
|
||||
okAction={editOpinion}
|
||||
canSave={value.length > 0}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
@ -75,5 +76,5 @@
|
||||
placeholder={recruit.string.OpinionValue}
|
||||
focus
|
||||
/>
|
||||
<StyledTextArea placeholder={recruit.string.Description} bind:content={description} emphasized />
|
||||
<StyledTextArea placeholder={recruit.string.Description} bind:content={description} kind={'emphasized'} />
|
||||
</Card>
|
||||
|
@ -104,7 +104,6 @@
|
||||
labelProps={{ word: keyTitle }}
|
||||
okAction={createTagElenent}
|
||||
canSave={title.length > 0}
|
||||
createMore={false}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
|
@ -174,10 +174,10 @@
|
||||
<symbol id="milestone" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 1.49988C8 1.22374 7.77614 0.999878 7.5 0.999878C7.22386 0.999878 7 1.22374 7 1.49988V2.99988H3C2.44772 2.99988 2 3.44759 2 3.99988V7.99988C2 8.55216 2.44771 8.99988 3 8.99988H7V14.4999C7 14.776 7.22386 14.9999 7.5 14.9999C7.77614 14.9999 8 14.776 8 14.4999V8.99988H11.3787C11.9091 8.99988 12.4178 8.78917 12.7929 8.41409L14.8536 6.35343C14.9473 6.25966 15 6.13249 15 5.99988C15 5.86727 14.9473 5.74009 14.8536 5.64632L12.7929 3.58566C12.4178 3.21059 11.9091 2.99988 11.3787 2.99988H8V1.49988ZM11.3787 7.99988C11.6439 7.99988 11.8982 7.89452 12.0858 7.70698L13.7929 5.99988L12.0858 4.29277C11.8983 4.10523 11.6439 3.99988 11.3787 3.99988H3V7.99988H11.3787Z" />
|
||||
</symbol>
|
||||
<symbol id="issuetemplates" viewBox="0 0 16 16">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 5L8 9L15 5L8 1L1 5ZM3.01556 5L8 7.84825L12.9844 5L8 2.15175L3.01556 5Z"/>
|
||||
<path d="M1 11L8 15L15 11L13.9426 10.3958L8 13.8482L2.05741 10.3958L1 11Z"/>
|
||||
<path d="M8 11.9992L1 7.99922L2.05741 7.39499L8 10.8475L13.9426 7.39499L15 7.99922L8 11.9992Z"/>
|
||||
<symbol id="issuetemplates" viewBox="0 0 32 32">
|
||||
<path d="M26 6V10H6V6H26ZM26 4H6C5.46957 4 4.96086 4.21071 4.58579 4.58579C4.21071 4.96086 4 5.46957 4 6V10C4 10.5304 4.21071 11.0391 4.58579 11.4142C4.96086 11.7893 5.46957 12 6 12H26C26.5304 12 27.0391 11.7893 27.4142 11.4142C27.7893 11.0391 28 10.5304 28 10V6C28 5.46957 27.7893 4.96086 27.4142 4.58579C27.0391 4.21071 26.5304 4 26 4Z" />
|
||||
<path d="M10 16V26H6V16H10ZM10 14H6C5.46957 14 4.96086 14.2107 4.58579 14.5858C4.21071 14.9609 4 15.4696 4 16V26C4 26.5304 4.21071 27.0391 4.58579 27.4142C4.96086 27.7893 5.46957 28 6 28H10C10.5304 28 11.0391 27.7893 11.4142 27.4142C11.7893 27.0391 12 26.5304 12 26V16C12 15.4696 11.7893 14.9609 11.4142 14.5858C11.0391 14.2107 10.5304 14 10 14Z" />
|
||||
<path d="M26 16V26H16V16H26ZM26 14H16C15.4696 14 14.9609 14.2107 14.5858 14.5858C14.2107 14.9609 14 15.4696 14 16V26C14 26.5304 14.2107 27.0391 14.5858 27.4142C14.9609 27.7893 15.4696 28 16 28H26C26.5304 28 27.0391 27.7893 27.4142 27.4142C27.7893 27.0391 28 26.5304 28 26V16C28 15.4696 27.7893 14.9609 27.4142 14.5858C27.0391 14.2107 26.5304 14 26 14Z" />
|
||||
</symbol>
|
||||
<symbol id="timeReport" viewBox="0 0 16 16">
|
||||
<path d="M8 1.99988C11.3 1.99988 14 4.69988 14 7.99988C14 11.2999 11.3 13.9999 8 13.9999C4.7 13.9999 2 11.2999 2 7.99988C2 4.69988 4.7 1.99988 8 1.99988ZM8 0.999878C4.15 0.999878 1 4.14988 1 7.99988C1 11.8499 4.15 14.9999 8 14.9999C11.85 14.9999 15 11.8499 15 7.99988C15 4.14988 11.85 0.999878 8 0.999878Z" />
|
||||
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 34 KiB |
@ -78,7 +78,7 @@
|
||||
"AssignTo": "Assign to...",
|
||||
"AssignedTo": "Assigned to {value}",
|
||||
"Parent": "Parent issue",
|
||||
"SetParent": "Set parent issue\u2026",
|
||||
"SetParent": "Set parent issue",
|
||||
"ChangeParent": "Change parent issue\u2026",
|
||||
"RemoveParent": "Remove parent issue",
|
||||
"OpenParent": "Open parent issue",
|
||||
@ -93,6 +93,7 @@
|
||||
"Labels": "Labels",
|
||||
"Component": "Component",
|
||||
"Space": "",
|
||||
"NoDueDate": "No due date",
|
||||
"SetDueDate": "Set due date\u2026",
|
||||
"ChangeDueDate": "Change due date\u2026",
|
||||
"ModificationDate": "Updated {value}",
|
||||
|
@ -78,7 +78,7 @@
|
||||
"AssignTo": "Назначить...",
|
||||
"AssignedTo": "Назначен на {value}",
|
||||
"Parent": "Родительская задача",
|
||||
"SetParent": "Задать родительскую задачу\u2026",
|
||||
"SetParent": "Задать родительскую задачу",
|
||||
"ChangeParent": "Изменить родительскую задачу\u2026",
|
||||
"RemoveParent": "Удалить родительскую задачу",
|
||||
"OpenParent": "Открыть родительскую задачу",
|
||||
@ -93,6 +93,7 @@
|
||||
"Labels": "Метки",
|
||||
"Component": "Компонент",
|
||||
"Space": "",
|
||||
"NoDueDate": "Нет срока выполнения",
|
||||
"SetDueDate": "Указать срок выполнения\u2026",
|
||||
"ChangeDueDate": "Изменить срок выполнения\u2026",
|
||||
"ModificationDate": "Изменено {value}",
|
||||
|
@ -41,7 +41,6 @@
|
||||
Project
|
||||
} from '@hcengineering/tracker'
|
||||
import {
|
||||
ActionIcon,
|
||||
addNotification,
|
||||
Button,
|
||||
Component,
|
||||
@ -50,11 +49,11 @@
|
||||
EditBox,
|
||||
FocusHandler,
|
||||
IconAttachment,
|
||||
IconMoreH,
|
||||
Label,
|
||||
Menu,
|
||||
showPopup
|
||||
} from '@hcengineering/ui'
|
||||
import { Attachment } from '@hcengineering/attachment'
|
||||
import { AttachmentPresenter } from '@hcengineering/attachment-resources'
|
||||
import view from '@hcengineering/view'
|
||||
import { ObjectBox } from '@hcengineering/view-resources'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
@ -68,7 +67,6 @@
|
||||
import StatusEditor from './issues/StatusEditor.svelte'
|
||||
import EstimationEditor from './issues/timereport/EstimationEditor.svelte'
|
||||
import MilestoneSelector from './milestones/MilestoneSelector.svelte'
|
||||
import SetDueDateActionPopup from './SetDueDateActionPopup.svelte'
|
||||
import SetParentIssueActionPopup from './SetParentIssueActionPopup.svelte'
|
||||
import SubIssues from './SubIssues.svelte'
|
||||
import { createBacklinks } from '@hcengineering/chunter-resources'
|
||||
@ -409,51 +407,17 @@
|
||||
descriptionBox?.removeDraft(false)
|
||||
}
|
||||
|
||||
async function showMoreActions (ev: Event) {
|
||||
ev.preventDefault()
|
||||
|
||||
const selectDueDate = {
|
||||
label: object.dueDate === null ? tracker.string.SetDueDate : tracker.string.ChangeDueDate,
|
||||
icon: tracker.icon.DueDate,
|
||||
action: async () =>
|
||||
showPopup(
|
||||
SetDueDateActionPopup,
|
||||
{ value: object },
|
||||
'top',
|
||||
undefined,
|
||||
(newDueDate) => newDueDate !== undefined && (object.dueDate = newDueDate)
|
||||
)
|
||||
}
|
||||
|
||||
const setParentIssue = {
|
||||
label: parentIssue ? tracker.string.ChangeParent : tracker.string.SetParent,
|
||||
icon: tracker.icon.Parent,
|
||||
action: async () =>
|
||||
showPopup(
|
||||
SetParentIssueActionPopup,
|
||||
{ value: { ...object, space: _space, attachedTo: parentIssue?._id } },
|
||||
'top',
|
||||
(selectedIssue) => {
|
||||
if (selectedIssue !== undefined) {
|
||||
parentIssue = selectedIssue
|
||||
object.parentIssue = parentIssue?._id
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const removeParentIssue = parentIssue && {
|
||||
label: tracker.string.RemoveParent,
|
||||
icon: tracker.icon.Parent,
|
||||
action: clearParentIssue
|
||||
}
|
||||
|
||||
async function setParentIssue () {
|
||||
showPopup(
|
||||
Menu,
|
||||
{
|
||||
actions: [selectDueDate, setParentIssue, ...(removeParentIssue ? [removeParentIssue] : [])]
|
||||
},
|
||||
ev.target as HTMLElement
|
||||
SetParentIssueActionPopup,
|
||||
{ value: { ...object, space: _space, attachedTo: parentIssue?._id } },
|
||||
'top',
|
||||
(selectedIssue) => {
|
||||
if (selectedIssue !== undefined) {
|
||||
parentIssue = selectedIssue
|
||||
object.parentIssue = parentIssue?._id
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@ -530,6 +494,8 @@
|
||||
|
||||
$: objectId = object._id
|
||||
const manager = createFocusManager()
|
||||
|
||||
let attachments: Map<Ref<Attachment>, Attachment> = new Map<Ref<Attachment>, Attachment>()
|
||||
</script>
|
||||
|
||||
<FocusHandler {manager} />
|
||||
@ -540,8 +506,9 @@
|
||||
{canSave}
|
||||
okLabel={tracker.string.SaveIssue}
|
||||
on:close={() => dispatch('close')}
|
||||
createMore={false}
|
||||
onCancel={showConfirmationDialog}
|
||||
hideAttachments={attachments.size === 0}
|
||||
hideSubheader={!parentIssue}
|
||||
on:changeContent
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
@ -550,7 +517,7 @@
|
||||
label={tracker.string.Project}
|
||||
bind:space={_space}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
size={'small'}
|
||||
/>
|
||||
<ObjectBox
|
||||
_class={tracker.class.IssueTemplate}
|
||||
@ -560,7 +527,7 @@
|
||||
}}
|
||||
on:change={handleTemplateChange}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
size={'small'}
|
||||
label={tracker.string.NoIssueTemplate}
|
||||
icon={tracker.icon.IssueTemplates}
|
||||
searchField={'title'}
|
||||
@ -576,20 +543,29 @@
|
||||
<Label {label} />
|
||||
</div>
|
||||
{#if relatedTo}
|
||||
<div class="mr-2">
|
||||
<div class="lower mr-2">
|
||||
<Label label={tracker.string.RelatedTo} />
|
||||
</div>
|
||||
<Component
|
||||
is={view.component.ObjectPresenter}
|
||||
props={{ value: relatedTo, _class: relatedTo._class, objectId: relatedTo._id, inline: true }}
|
||||
props={{
|
||||
value: relatedTo,
|
||||
_class: relatedTo._class,
|
||||
objectId: relatedTo._id,
|
||||
inline: true,
|
||||
shouldShowAvatar: false,
|
||||
noUnderline: true
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
{#if parentIssue}
|
||||
<ParentIssue issue={parentIssue} on:close={clearParentIssue} />
|
||||
{/if}
|
||||
<div id="issue-name">
|
||||
<svelte:fragment slot="subheader">
|
||||
{#if parentIssue}
|
||||
<ParentIssue issue={parentIssue} on:close={clearParentIssue} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<div id="issue-name" class="m-3 clear-mins">
|
||||
<EditBox
|
||||
focusIndex={1}
|
||||
bind:value={object.title}
|
||||
@ -610,7 +586,8 @@
|
||||
space={_space}
|
||||
alwaysEdit
|
||||
showButtons={false}
|
||||
emphasized
|
||||
kind={'indented'}
|
||||
fakeAttach={'hidden'}
|
||||
enableBackReferences={true}
|
||||
bind:content={object.description}
|
||||
placeholder={tracker.string.IssueDescriptionPlaceholder}
|
||||
@ -620,6 +597,13 @@
|
||||
object.attachments = ev.detail.value
|
||||
}
|
||||
}}
|
||||
on:attachments={(ev) => {
|
||||
if (ev.detail.size > 0) attachments = ev.detail.values
|
||||
else if (ev.detail.size === 0 && ev.detail.values) {
|
||||
attachments.clear()
|
||||
attachments = attachments
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/key}
|
||||
</div>
|
||||
@ -640,6 +624,7 @@
|
||||
size={'large'}
|
||||
defaultIssueStatus={currentProject?.defaultIssueStatus}
|
||||
shouldShowLabel={true}
|
||||
short
|
||||
on:refocus={() => {
|
||||
manager.setFocusPos(3)
|
||||
}}
|
||||
@ -672,6 +657,7 @@
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
width={'min-content'}
|
||||
short
|
||||
on:change={({ detail }) => {
|
||||
object.assignee = detail
|
||||
manager.setFocusPos(5)
|
||||
@ -696,9 +682,6 @@
|
||||
object.labels = object.labels.filter((it) => it._id !== evt.detail)
|
||||
}}
|
||||
/>
|
||||
<div id="estimation-editor">
|
||||
<EstimationEditor focusIndex={7} kind={'secondary'} size={'large'} value={object} />
|
||||
</div>
|
||||
<ComponentSelector
|
||||
focusIndex={8}
|
||||
value={object.component}
|
||||
@ -706,25 +689,63 @@
|
||||
isEditable={true}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
short
|
||||
/>
|
||||
<MilestoneSelector
|
||||
focusIndex={9}
|
||||
value={object.milestone}
|
||||
onChange={handleMilestoneIdChanged}
|
||||
useComponent={(!originalIssue && object.component) || undefined}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
/>
|
||||
{#if object.dueDate !== null}
|
||||
<DatePresenter bind:value={object.dueDate} kind={'secondary'} size={'large'} editable />
|
||||
<div id="estimation-editor" class="new-line">
|
||||
<EstimationEditor focusIndex={7} kind={'secondary'} size={'large'} value={object} />
|
||||
</div>
|
||||
<div id="milestone-editor" class="new-line">
|
||||
<MilestoneSelector
|
||||
focusIndex={9}
|
||||
value={object.milestone}
|
||||
onChange={handleMilestoneIdChanged}
|
||||
useComponent={(!originalIssue && object.component) || undefined}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
short
|
||||
/>
|
||||
</div>
|
||||
<div id="duedate-editor" class="new-line">
|
||||
<DatePresenter
|
||||
bind:value={object.dueDate}
|
||||
labelNull={tracker.string.NoDueDate}
|
||||
icon={tracker.icon.DueDate}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
editable
|
||||
/>
|
||||
</div>
|
||||
<div id="parentissue-editor" class="new-line">
|
||||
<Button
|
||||
icon={tracker.icon.Parent}
|
||||
label={object.parentIssue ? tracker.string.RemoveParent : tracker.string.SetParent}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
notSelected={object.parentIssue === undefined}
|
||||
on:click={object.parentIssue ? clearParentIssue : setParentIssue}
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="attachments">
|
||||
{#if attachments.size > 0}
|
||||
{#each Array.from(attachments.values()) as attachment}
|
||||
<AttachmentPresenter
|
||||
value={attachment}
|
||||
removable
|
||||
on:remove={(result) => {
|
||||
if (result.detail !== undefined) descriptionBox.removeAttachmentById(result.detail._id)
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
{/if}
|
||||
<div id="more-actions"><ActionIcon icon={IconMoreH} size={'medium'} action={showMoreActions} /></div>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button
|
||||
focusIndex={10}
|
||||
icon={IconAttachment}
|
||||
iconProps={{ fill: 'var(--theme-dark-color)' }}
|
||||
size={'large'}
|
||||
kind={'transparent'}
|
||||
on:click={() => {
|
||||
descriptionBox.attach()
|
||||
}}
|
||||
|
@ -45,6 +45,7 @@
|
||||
okAction={onSave}
|
||||
canSave={object.label !== ''}
|
||||
okLabel={tracker.string.CreateComponent}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => dispatch('close')}
|
||||
on:changeContent
|
||||
>
|
||||
@ -61,7 +62,7 @@
|
||||
<StyledTextArea
|
||||
bind:content={object.description}
|
||||
placeholder={tracker.string.ComponentDescriptionPlaceholder}
|
||||
emphasized
|
||||
kind={'emphasized'}
|
||||
showButtons={false}
|
||||
/>
|
||||
<svelte:fragment slot="pool">
|
||||
|
@ -33,6 +33,7 @@
|
||||
{fill}
|
||||
id={category._id}
|
||||
style:transform={category._id === tracker.issueStatusCategory.Started ? 'rotate(-90deg)' : ''}
|
||||
style:flex-shrink={0}
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
|
@ -30,6 +30,7 @@
|
||||
export let tooltipAlignment: TooltipAlignment | undefined = undefined
|
||||
export let width: string = '100%'
|
||||
export let focusIndex: number | undefined = undefined
|
||||
export let short: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -99,6 +100,7 @@
|
||||
{kind}
|
||||
{avatarSize}
|
||||
{width}
|
||||
{short}
|
||||
showNavigate={false}
|
||||
justify={'left'}
|
||||
showTooltip={{ label: tracker.string.AssignTo, direction: tooltipAlignment }}
|
||||
|
@ -24,7 +24,7 @@
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="ac-header full divide"
|
||||
class="ac-header full divide caption-height"
|
||||
class:header-with-mode-selector={modeSelectorProps !== undefined}
|
||||
class:header-without-label={!label}
|
||||
>
|
||||
|
@ -15,10 +15,11 @@
|
||||
<script lang="ts">
|
||||
import { createQuery } from '@hcengineering/presentation'
|
||||
import { Project, Issue } from '@hcengineering/tracker'
|
||||
import { Spinner, IconClose, tooltip } from '@hcengineering/ui'
|
||||
import { Spinner, IconClose, Button } from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import tracker from '../../plugin'
|
||||
import { getIssueId } from '../../issues'
|
||||
import PriorityRefPresenter from './PriorityRefPresenter.svelte'
|
||||
|
||||
export let issue: Issue
|
||||
|
||||
@ -31,51 +32,65 @@
|
||||
$: issueId = project && getIssueId(project, issue)
|
||||
</script>
|
||||
|
||||
<div class="flex-center root">
|
||||
<div class="parentIssue-container">
|
||||
<div class="flex-no-shrink mr-1-5">
|
||||
<PriorityRefPresenter value={issue.priority} shouldShowLabel={false} />
|
||||
</div>
|
||||
{#if issueId}
|
||||
<span class="overflow-label flex-no-shrink">{issueId}</span>
|
||||
<span class="overflow-label flex-no-shrink content-dark-color">{issueId}</span>
|
||||
{:else}
|
||||
<Spinner size="small" />
|
||||
{/if}
|
||||
<span class="overflow-label issue-title">{issue.title}</span>
|
||||
<Button
|
||||
icon={IconClose}
|
||||
showTooltip={{ label: tracker.string.RemoveParent, direction: 'bottom' }}
|
||||
kind={'transparent'}
|
||||
size={'small'}
|
||||
on:click={() => dispatch('close')}
|
||||
/>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
<!-- <div
|
||||
class="button-close"
|
||||
use:tooltip={{ label: tracker.string.RemoveParent, direction: 'bottom' }}
|
||||
on:click={() => dispatch('close')}
|
||||
>
|
||||
<IconClose size="x-small" />
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.root {
|
||||
padding: 0.375rem 0.75rem;
|
||||
line-height: 150%;
|
||||
.parentIssue-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.25rem 0.25rem 0.25rem 0.75rem;
|
||||
max-width: fit-content;
|
||||
border: 1px solid var(--button-border-color);
|
||||
min-width: 0;
|
||||
// line-height: 150%;
|
||||
height: 2.25rem;
|
||||
border: 1px solid var(--theme-button-border);
|
||||
border-radius: 0.25rem;
|
||||
box-shadow: var(--button-shadow);
|
||||
}
|
||||
|
||||
.issue-title {
|
||||
margin: 0 0.75rem 0 0.5rem;
|
||||
margin: 0 0.25rem 0 0.375rem;
|
||||
padding-right: 0.75rem;
|
||||
color: var(--accent-color);
|
||||
border-right: 1px solid var(--button-border-color);
|
||||
min-width: 0;
|
||||
color: var(--theme-caption-color);
|
||||
border-right: 1px solid var(--theme-button-border);
|
||||
}
|
||||
|
||||
.button-close {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
color: var(--content-color);
|
||||
color: var(--theme-dark-color);
|
||||
transition: color 0.15s;
|
||||
|
||||
&:hover {
|
||||
color: var(--caption-color);
|
||||
color: var(--theme-content-color);
|
||||
}
|
||||
&:active {
|
||||
color: var(--accent-color);
|
||||
color: var(--theme-dark-color);
|
||||
}
|
||||
&::before {
|
||||
position: absolute;
|
||||
|
@ -22,6 +22,7 @@
|
||||
export let colorInherit: boolean = false
|
||||
export let accent: boolean = false
|
||||
export let inline: boolean = false
|
||||
export let shouldShowLabel: boolean = true
|
||||
|
||||
$: icon = issuePriorities[value]?.icon
|
||||
$: label = issuePriorities[value]?.label
|
||||
@ -31,12 +32,14 @@
|
||||
{#if !inline && icon}
|
||||
<Icon {icon} {size} fill={'var(--theme-caption-color)'} />
|
||||
{/if}
|
||||
<span
|
||||
class="overflow-label"
|
||||
class:ml-2={!inline && icon}
|
||||
style:color={colorInherit ? 'inherit' : 'var(--theme-content-color)'}
|
||||
class:fs-bold={accent}
|
||||
>
|
||||
<Label {label} />
|
||||
</span>
|
||||
{#if shouldShowLabel}
|
||||
<span
|
||||
class="overflow-label"
|
||||
class:ml-2={!inline && icon}
|
||||
style:color={colorInherit ? 'inherit' : 'var(--theme-content-color)'}
|
||||
class:fs-bold={accent}
|
||||
>
|
||||
<Label {label} />
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
@ -40,6 +40,7 @@
|
||||
export let width: string | undefined = undefined
|
||||
export let defaultIssueStatus: Ref<IssueStatus> | undefined = undefined
|
||||
export let focusIndex: number | undefined = undefined
|
||||
export let short: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
const dispatch = createEventDispatcher()
|
||||
@ -120,7 +121,10 @@
|
||||
{#if selectedStatus}<IssueStatusIcon value={selectedStatus} size={kind === 'list' ? 'small' : 'medium'} />{/if}
|
||||
</div>
|
||||
{#if selectedStatusLabel}
|
||||
<span class="{kind === 'list' ? 'ml-1 text-md' : 'ml-2 text-base'} overflow-label disabled content-color">
|
||||
<span
|
||||
class="{kind === 'list' ? 'ml-1 text-md' : 'ml-2 text-base'} overflow-label disabled content-color"
|
||||
class:max-w-20={short}
|
||||
>
|
||||
{selectedStatusLabel}
|
||||
</span>
|
||||
{/if}
|
||||
@ -134,22 +138,25 @@
|
||||
{kind}
|
||||
{width}
|
||||
{focusIndex}
|
||||
{short}
|
||||
on:click={handleStatusEditorOpened}
|
||||
>
|
||||
<span slot="content" class="flex-row-center pointer-events-none">
|
||||
<svelte:fragment slot="icon">
|
||||
{#if selectedStatus}
|
||||
<IssueStatusIcon value={selectedStatus} size={iconSize} />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="content">
|
||||
{#if selectedStatusLabel}
|
||||
<span
|
||||
class="overflow-label disabled"
|
||||
class:ml-1={selectedStatus && smallgap}
|
||||
class:ml-1-5={selectedStatus && smallgap}
|
||||
class:ml-2={selectedStatus && !smallgap}
|
||||
>
|
||||
{selectedStatusLabel}
|
||||
</span>
|
||||
{/if}
|
||||
</span>
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
{/if}
|
||||
{/if}
|
||||
|
@ -84,7 +84,7 @@
|
||||
label={tracker.string.TimeSpendValue}
|
||||
notSelected={value.estimation === 0}
|
||||
labelParams={{ value: value.estimation }}
|
||||
icon={tracker.icon.Estimation}
|
||||
icon={tracker.icon.DueDate}
|
||||
{justify}
|
||||
{width}
|
||||
{size}
|
||||
|
@ -68,6 +68,7 @@
|
||||
dispatch('close')
|
||||
}}
|
||||
okLabel={presentation.string.Ok}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close', null)
|
||||
}}
|
||||
|
@ -89,6 +89,7 @@
|
||||
label={value === undefined ? tracker.string.TimeSpendReportAdd : tracker.string.TimeSpendReportValue}
|
||||
{canSave}
|
||||
okAction={create}
|
||||
gap={'gapV-4'}
|
||||
on:close
|
||||
okLabel={value === undefined ? presentation.string.Create : presentation.string.Save}
|
||||
on:changeContent
|
||||
|
@ -43,7 +43,7 @@
|
||||
value={dateMs}
|
||||
editable={true}
|
||||
shouldShowLabel={true}
|
||||
icon={'normal'}
|
||||
iconModifier={'normal'}
|
||||
{kind}
|
||||
{size}
|
||||
on:change={handleDateChanged}
|
||||
|
@ -57,6 +57,7 @@
|
||||
okAction={onSave}
|
||||
canSave={object.label !== ''}
|
||||
okLabel={tracker.string.CreateMilestone}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => dispatch('close')}
|
||||
on:changeContent
|
||||
>
|
||||
@ -73,7 +74,7 @@
|
||||
<StyledTextArea
|
||||
bind:content={object.description}
|
||||
placeholder={tracker.string.ComponentDescriptionPlaceholder}
|
||||
emphasized
|
||||
kind={'emphasized'}
|
||||
showButtons={false}
|
||||
/>
|
||||
<svelte:fragment slot="pool">
|
||||
|
@ -183,6 +183,7 @@
|
||||
okLabel={isNew ? presentation.string.Create : presentation.string.Save}
|
||||
okAction={handleSave}
|
||||
canSave={name.length > 0 && !(members.length === 0 && isPrivate)}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
|
@ -64,6 +64,7 @@
|
||||
okLabel={tracker.string.CreateScrum}
|
||||
{canSave}
|
||||
okAction={onSave}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => dispatch('close')}
|
||||
on:changeContent
|
||||
>
|
||||
@ -74,7 +75,7 @@
|
||||
<StyledTextArea
|
||||
bind:content={object.description}
|
||||
placeholder={tracker.string.ScrumDescriptionPlaceholder}
|
||||
emphasized
|
||||
kind={'emphasized'}
|
||||
/>
|
||||
<svelte:fragment slot="pool">
|
||||
<UserBoxList bind:items={object.members} label={tracker.string.ScrumMembersSearchPlaceholder} />
|
||||
|
@ -125,10 +125,10 @@
|
||||
okAction={createIssueTemplate}
|
||||
{canSave}
|
||||
okLabel={tracker.string.SaveProcess}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
createMore={false}
|
||||
on:changeContent
|
||||
>
|
||||
<svelte:fragment slot="header">
|
||||
@ -148,7 +148,7 @@
|
||||
<StyledTextBox
|
||||
alwaysEdit
|
||||
showButtons={false}
|
||||
emphasized
|
||||
kind={'emphasized'}
|
||||
bind:content={object.description}
|
||||
placeholder={tracker.string.IssueDescriptionPlaceholder}
|
||||
/>
|
||||
|
@ -131,6 +131,7 @@ export default mergeIds(trackerId, tracker, {
|
||||
Attachments: '' as IntlString,
|
||||
Labels: '' as IntlString,
|
||||
Space: '' as IntlString,
|
||||
NoDueDate: '' as IntlString,
|
||||
SetDueDate: '' as IntlString,
|
||||
ChangeDueDate: '' as IntlString,
|
||||
ModificationDate: '' as IntlString,
|
||||
|
@ -34,7 +34,7 @@
|
||||
<div class="selectPopup" use:resizeObserver={() => dispatch('changeContent')}>
|
||||
<div class="flex-row-center justify-stretch p-2">
|
||||
<div class="overflow-label flex-grow">
|
||||
<EditBox bind:value {placeholder} {format} {kind} focus on:keypress={_onkeypress} maxWidth={'12rem'} />
|
||||
<EditBox bind:value {placeholder} {format} {kind} select on:keypress={_onkeypress} maxWidth={'12rem'} />
|
||||
</div>
|
||||
<div class="ml-2">
|
||||
<Button icon={IconCheck} size={'small'} on:click={() => dispatch('close', value)} />
|
||||
|
@ -24,6 +24,7 @@
|
||||
export let props: Record<string, any> = {}
|
||||
export let inline: boolean = true
|
||||
export let shouldShowAvatar: boolean = true
|
||||
export let noUnderline: boolean = false
|
||||
|
||||
const client = getClient()
|
||||
let presenter: AttributeModel | undefined
|
||||
@ -58,5 +59,5 @@
|
||||
</script>
|
||||
|
||||
{#if presenter}
|
||||
<svelte:component this={presenter.presenter} value={doc} {...props} {inline} {shouldShowAvatar} />
|
||||
<svelte:component this={presenter.presenter} value={doc} {...props} {inline} {shouldShowAvatar} {noUnderline} />
|
||||
{/if}
|
||||
|
@ -23,6 +23,7 @@
|
||||
export let placeholder: IntlString
|
||||
export let value: string
|
||||
export let focus: boolean = false
|
||||
export let select: boolean = false
|
||||
export let onChange: (value: string) => void = () => {}
|
||||
export let kind: ButtonKind | undefined = undefined
|
||||
export let readonly = false
|
||||
@ -70,5 +71,5 @@
|
||||
<span class="content-dark-color"><Label label={placeholder} /></span>
|
||||
{/if}
|
||||
{:else}
|
||||
<EditBox {placeholder} bind:value {focus} on:change={_onchange} />
|
||||
<EditBox {placeholder} bind:value {focus} {select} on:change={_onchange} />
|
||||
{/if}
|
||||
|
@ -306,6 +306,7 @@
|
||||
okAction={save}
|
||||
okLabel={presentation.string.Save}
|
||||
canSave={true}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
|
@ -42,6 +42,7 @@
|
||||
label={view.string.NewFilteredView}
|
||||
okAction={saveFilter}
|
||||
canSave={filterName.length > 0}
|
||||
gap={'gapV-4'}
|
||||
on:close={() => {
|
||||
dispatch('close')
|
||||
}}
|
||||
|
@ -87,7 +87,7 @@ async function initIssues (prefix: string, page: Page): Promise<IssueProps[]> {
|
||||
test.describe('tracker layout tests', () => {
|
||||
const id = generateId(4)
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.setTimeout(60000)
|
||||
test.setTimeout(120000)
|
||||
await navigate(page)
|
||||
issuesProps = await initIssues(id, page)
|
||||
})
|
||||
|
@ -245,10 +245,8 @@ test('create-issue-draft', async ({ page }) => {
|
||||
await page.locator('[placeholder="Type text\\.\\.\\."]').fill('1')
|
||||
await page.locator('.ml-2 > .antiButton').click()
|
||||
|
||||
// Click button:nth-child(8)
|
||||
await page.locator('#more-actions').click()
|
||||
// Click button:has-text("Set due date…")
|
||||
await page.locator('button:has-text("Set due date…")').click()
|
||||
// Click button:has-text("No due date")
|
||||
await page.locator('button:has-text("No due date")').click()
|
||||
// Click text=24 >> nth=0
|
||||
await page.locator('.date-popup-container >> text=24').first().click()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user