mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-04 06:18:34 +00:00
Merge branch 'staging' into develop
Some checks failed
CI / build (push) Has been cancelled
CI / uitest (push) Has been cancelled
CI / uitest-pg (push) Has been cancelled
CI / uitest-qms (push) Has been cancelled
CI / uitest-workspaces (push) Has been cancelled
CI / svelte-check (push) Has been cancelled
CI / formatting (push) Has been cancelled
CI / test (push) Has been cancelled
CI / docker-build (push) Has been cancelled
CI / dist-build (push) Has been cancelled
Some checks failed
CI / build (push) Has been cancelled
CI / uitest (push) Has been cancelled
CI / uitest-pg (push) Has been cancelled
CI / uitest-qms (push) Has been cancelled
CI / uitest-workspaces (push) Has been cancelled
CI / svelte-check (push) Has been cancelled
CI / formatting (push) Has been cancelled
CI / test (push) Has been cancelled
CI / docker-build (push) Has been cancelled
CI / dist-build (push) Has been cancelled
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
commit
ce10156fe4
@ -19,7 +19,7 @@
|
||||
.underline {
|
||||
font-weight: 500;
|
||||
|
||||
input {
|
||||
.antiEditBoxInput {
|
||||
padding: 0.25rem 0.5rem;
|
||||
background-color: var(--theme-editbox-focus-color);
|
||||
border-radius: 0.25rem;
|
||||
@ -43,7 +43,7 @@
|
||||
&:focus-within::after { content: ''; }
|
||||
}
|
||||
|
||||
input {
|
||||
.antiEditBoxInput {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
@ -86,7 +86,7 @@
|
||||
border-radius: .375rem;
|
||||
border: 1px solid transparent;
|
||||
|
||||
input {
|
||||
.antiEditBoxInput {
|
||||
color: inherit;
|
||||
|
||||
&::placeholder { color: var(--theme-darker-color); }
|
||||
@ -109,7 +109,7 @@
|
||||
font-weight: 500;
|
||||
font-size: 1.5rem;
|
||||
|
||||
input {
|
||||
.antiEditBoxInput {
|
||||
font: inherit;
|
||||
|
||||
&::placeholder {
|
||||
@ -119,17 +119,17 @@
|
||||
&:hover input:not(:focus)::placeholder {
|
||||
color: var(--input-hover-PlaceholderColor);
|
||||
}
|
||||
input:focus::placeholder {
|
||||
.antiEditBoxInput:focus::placeholder {
|
||||
color: var(--input-focus-PlaceholderColor);
|
||||
}
|
||||
&.disabled {
|
||||
box-shadow: inset 0 0 0 1px var(--input-BorderColor);
|
||||
|
||||
&,
|
||||
input {
|
||||
.antiEditBoxInput {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
input::placeholder {
|
||||
.antiEditBoxInput::placeholder {
|
||||
color: var(--input-PlaceholderColor);
|
||||
}
|
||||
}
|
||||
@ -139,4 +139,27 @@
|
||||
content: ' *';
|
||||
color: var(--theme-error-color);
|
||||
}
|
||||
|
||||
.antiEditBoxGridWrapper {
|
||||
display: grid;
|
||||
&::after {
|
||||
content: attr(data-value) " ";
|
||||
white-space: pre-wrap;
|
||||
visibility: hidden;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
|
||||
&::after, textarea {
|
||||
font: inherit;
|
||||
outline: none;
|
||||
background-color: transparent;
|
||||
overflow: hidden;
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
min-height: 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
export let value: string | number | undefined = undefined
|
||||
export let placeholder: IntlString = plugin.string.EditBoxPlaceholder
|
||||
export let placeholderParam: any | undefined = undefined
|
||||
export let format: 'text' | 'password' | 'number' = 'text'
|
||||
export let format: 'text' | 'password' | 'number' | 'text-multiline' = 'text'
|
||||
export let maxDigitsAfterPoint: number | undefined = undefined
|
||||
export let kind: EditStyle = 'editbox'
|
||||
export let autoFocus: boolean = false
|
||||
@ -43,7 +43,7 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let input: HTMLInputElement
|
||||
let input: HTMLInputElement | HTMLTextAreaElement
|
||||
let phTranslate: string = ''
|
||||
|
||||
$: {
|
||||
@ -135,8 +135,28 @@
|
||||
class:w-full={fullSize}
|
||||
style:width={maxWidth}
|
||||
>
|
||||
{#if format === 'password'}
|
||||
{#if format === 'text-multiline'}
|
||||
<div class="antiEditBoxGridWrapper" data-value={value}>
|
||||
<textarea
|
||||
rows="1"
|
||||
class="antiEditBoxInput"
|
||||
{disabled}
|
||||
style:width={maxWidth}
|
||||
bind:this={input}
|
||||
bind:value
|
||||
placeholder={phTranslate}
|
||||
on:input={handleInput}
|
||||
on:change
|
||||
on:keydown
|
||||
on:keypress
|
||||
on:blur={() => {
|
||||
dispatch('blur', value)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{:else if format === 'password'}
|
||||
<input
|
||||
class="antiEditBoxInput"
|
||||
{disabled}
|
||||
style:width={maxWidth}
|
||||
id="userPassword"
|
||||
@ -154,11 +174,11 @@
|
||||
/>
|
||||
{:else if format === 'number'}
|
||||
<input
|
||||
class="antiEditBoxInput number"
|
||||
{disabled}
|
||||
style:width={maxWidth}
|
||||
bind:this={input}
|
||||
type="number"
|
||||
class="number"
|
||||
bind:value
|
||||
placeholder={phTranslate}
|
||||
on:input={handleInput}
|
||||
@ -171,6 +191,7 @@
|
||||
/>
|
||||
{:else}
|
||||
<input
|
||||
class="antiEditBoxInput"
|
||||
{disabled}
|
||||
style:width={maxWidth}
|
||||
bind:this={input}
|
||||
|
@ -43,6 +43,7 @@
|
||||
"SurveySubmitConfirm": "You will not be able to change answers after that. Are you sure you want to submit now?",
|
||||
"ValidateFail": "Some required questions are not answered",
|
||||
"ValidateInfo": "This is how the form will look like for an user. Try to type answers and select options to test your survey. A green icon in the header above shows the form is filled properly",
|
||||
"ValidateOk": "Form is filled correctly"
|
||||
"ValidateOk": "Form is filled correctly",
|
||||
"EditAnswers": "Edit answers"
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +43,7 @@
|
||||
"SurveySubmitConfirm": "После этого вы больше не сможете изменять ответы. Вы уверены, что хотите завершить опрос сейчас?",
|
||||
"ValidateFail": "Нет ответов на некоторые обязательные вопросы",
|
||||
"ValidateInfo": "Так будет выглядеть форма для пользователя. Для проверки анкеты попробуйте вводить ответы и выбирать варианты. Зеленый значок в заголовке покажет, что форма заполнена правильно",
|
||||
"ValidateOk": "Форма заполнена правильно"
|
||||
"ValidateOk": "Форма заполнена правильно",
|
||||
"EditAnswers": "Редактировать ответы"
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="antiSection flex-gap-4">
|
||||
<div class="antiSection flex-gap-4 poll mb-8">
|
||||
{#if hasText(object.prompt)}
|
||||
<div class="antiSection-header">
|
||||
<span class="antiSection-header__title">
|
||||
@ -73,10 +73,16 @@
|
||||
<PollQuestion
|
||||
bind:this={questionNodes[index]}
|
||||
bind:isAnswered={isAnswered[index]}
|
||||
readonly={readonly || object.isCompleted}
|
||||
{readonly}
|
||||
on:answered={saveAnswers}
|
||||
{question}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.poll {
|
||||
user-select: text;
|
||||
}
|
||||
</style>
|
||||
|
@ -35,6 +35,10 @@
|
||||
|
||||
let object: Poll | undefined = undefined
|
||||
let canSubmit = false
|
||||
let requestUpdate = false
|
||||
|
||||
$: isCompleted = object?.isCompleted ?? false
|
||||
$: editable = (!readonly && !isCompleted) || requestUpdate
|
||||
|
||||
$: updateObject(_id)
|
||||
|
||||
@ -48,19 +52,21 @@
|
||||
if (object === undefined) {
|
||||
return
|
||||
}
|
||||
showPopup(
|
||||
MessageBox,
|
||||
{
|
||||
label: survey.string.SurveySubmit,
|
||||
message: survey.string.SurveySubmitConfirm
|
||||
},
|
||||
undefined,
|
||||
async (result?: boolean) => {
|
||||
if (result === true && object !== undefined) {
|
||||
await getClient().updateDoc(object._class, object.space, object._id, { isCompleted: true })
|
||||
}
|
||||
}
|
||||
)
|
||||
requestUpdate = false
|
||||
// showPopup(
|
||||
// MessageBox,
|
||||
// {
|
||||
// label: survey.string.SurveySubmit,
|
||||
// message: survey.string.SurveySubmitConfirm
|
||||
// },
|
||||
// undefined,
|
||||
// async (result?: boolean) => {
|
||||
// if (result === true && object !== undefined) {
|
||||
// await getClient().updateDoc(object._class, object.space, object._id, { isCompleted: true })
|
||||
// }
|
||||
// }
|
||||
// )
|
||||
await getClient().updateDoc(object._class, object.space, object._id, { isCompleted: true })
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -85,30 +91,36 @@
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="utils">
|
||||
{#if !readonly}
|
||||
{#if !(object.isCompleted ?? false)}
|
||||
<Button
|
||||
icon={survey.icon.Submit}
|
||||
label={survey.string.SurveySubmit}
|
||||
kind={'primary'}
|
||||
disabled={!canSubmit}
|
||||
showTooltip={{ label: canSubmit ? undefined : survey.string.ValidateFail }}
|
||||
on:click={submit}
|
||||
/>
|
||||
{/if}
|
||||
{#if editable}
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
on:click={(e) => {
|
||||
showMenu(e, { object, excludedActions: [view.action.Open] })
|
||||
icon={survey.icon.Submit}
|
||||
label={survey.string.SurveySubmit}
|
||||
kind={'primary'}
|
||||
disabled={!canSubmit}
|
||||
showTooltip={{ label: canSubmit ? undefined : survey.string.ValidateFail }}
|
||||
on:click={submit}
|
||||
/>
|
||||
{:else}
|
||||
<Button
|
||||
icon={view.icon.Edit}
|
||||
label={survey.string.EditAnswers}
|
||||
on:click={() => {
|
||||
requestUpdate = true
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<Button
|
||||
icon={IconMoreH}
|
||||
iconProps={{ size: 'medium' }}
|
||||
kind={'icon'}
|
||||
on:click={(e) => {
|
||||
showMenu(e, { object, excludedActions: [view.action.Open] })
|
||||
}}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
|
||||
<div class="flex-col flex-grow flex-no-shrink">
|
||||
<EditPoll {object} {readonly} bind:canSubmit />
|
||||
<EditPoll {object} readonly={!editable} bind:canSubmit />
|
||||
</div>
|
||||
</Panel>
|
||||
{/if}
|
||||
|
@ -18,16 +18,16 @@
|
||||
import { MessageBox, getClient } from '@hcengineering/presentation'
|
||||
import { Question, QuestionKind, Survey } from '@hcengineering/survey'
|
||||
import {
|
||||
ButtonIcon,
|
||||
EditBox,
|
||||
Icon,
|
||||
IconDelete,
|
||||
SelectPopup,
|
||||
eventToHTMLElement,
|
||||
showPopup,
|
||||
tooltip,
|
||||
ButtonIcon
|
||||
tooltip
|
||||
} from '@hcengineering/ui'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||
import survey from '../plugin'
|
||||
|
||||
const client = getClient()
|
||||
@ -40,40 +40,65 @@
|
||||
let editQuestion: EditBox
|
||||
let hovered: boolean = false
|
||||
|
||||
$: question = parent?.questions?.[index] as Question
|
||||
let defaultQuestion: Question = {
|
||||
name: '',
|
||||
kind: QuestionKind.STRING,
|
||||
isMandatory: false,
|
||||
hasCustomOption: false
|
||||
}
|
||||
|
||||
$: question = (parent?.questions?.[index] as Question) ?? defaultQuestion
|
||||
$: isNewQuestion = parent?.questions?.[index] === undefined
|
||||
$: options = question?.options ?? []
|
||||
$: questionIcon =
|
||||
question === undefined
|
||||
? survey.icon.Question
|
||||
: question.kind === QuestionKind.OPTIONS
|
||||
? survey.icon.QuestionKindOptions
|
||||
: question.kind === QuestionKind.OPTION
|
||||
? survey.icon.QuestionKindOption
|
||||
: survey.icon.QuestionKindString
|
||||
$: questionIcon = isNewQuestion
|
||||
? survey.icon.Question
|
||||
: question.kind === QuestionKind.OPTIONS
|
||||
? survey.icon.QuestionKindOptions
|
||||
: question.kind === QuestionKind.OPTION
|
||||
? survey.icon.QuestionKindOption
|
||||
: survey.icon.QuestionKindString
|
||||
|
||||
let haveNameChanges = false
|
||||
|
||||
let newOption = ''
|
||||
let newQuestion = ''
|
||||
|
||||
onDestroy(() => {
|
||||
handleExit()
|
||||
})
|
||||
|
||||
function handleExit (): void {
|
||||
void handleNameChange()
|
||||
}
|
||||
|
||||
async function updateParent (): Promise<void> {
|
||||
await client.updateDoc(parent._class, parent.space, parent._id, { questions: parent.questions })
|
||||
}
|
||||
|
||||
async function createQuestion (): Promise<void> {
|
||||
$: if (isNewQuestion && question.name.trim() !== '') {
|
||||
void createQuestion()
|
||||
}
|
||||
|
||||
function createQuestion (): Promise<void> {
|
||||
if (parent.questions === undefined) {
|
||||
parent.questions = []
|
||||
}
|
||||
parent.questions.push({
|
||||
name: newQuestion,
|
||||
kind: QuestionKind.STRING,
|
||||
isMandatory: false,
|
||||
hasCustomOption: false
|
||||
})
|
||||
await updateParent()
|
||||
newQuestion = ''
|
||||
parent.questions.push({ ...question })
|
||||
defaultQuestion = { ...defaultQuestion, name: '' }
|
||||
return updateParent()
|
||||
}
|
||||
|
||||
function handleNameChange (): Promise<void> | void {
|
||||
if (!haveNameChanges) return
|
||||
haveNameChanges = false
|
||||
|
||||
if (isNewQuestion) return createQuestion()
|
||||
return changeName()
|
||||
}
|
||||
|
||||
async function changeName (): Promise<void> {
|
||||
await updateParent()
|
||||
if (!isNewQuestion) {
|
||||
await updateParent()
|
||||
}
|
||||
}
|
||||
|
||||
async function changeKind (kind: QuestionKind): Promise<void> {
|
||||
@ -348,6 +373,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:beforeunload={handleExit} />
|
||||
<div
|
||||
bind:this={rootElement}
|
||||
class="question-container flex-col flex-gap-2"
|
||||
@ -357,27 +383,33 @@
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="flex-row-center flex-gap-3 text-base pr-2" on:click={focusQuestion}>
|
||||
{#if question === undefined}
|
||||
<ButtonIcon size={'small'} disabled icon={survey.icon.Question} />
|
||||
<EditBox
|
||||
bind:this={editQuestion}
|
||||
kind={'editbox'}
|
||||
placeholder={survey.string.QuestionPlaceholder}
|
||||
bind:value={newQuestion}
|
||||
on:change={createQuestion}
|
||||
/>
|
||||
{#if isNewQuestion}
|
||||
<div class="self-start">
|
||||
<ButtonIcon size={'small'} disabled icon={questionIcon} />
|
||||
</div>
|
||||
{:else}
|
||||
<div role="presentation" draggable={!readonly} on:dragstart={rootDragStart} on:dragend={rootDragEnd}>
|
||||
<div
|
||||
class="self-start"
|
||||
role="presentation"
|
||||
draggable={!readonly}
|
||||
on:dragstart={rootDragStart}
|
||||
on:dragend={rootDragEnd}
|
||||
>
|
||||
<ButtonIcon size={'small'} disabled={readonly} icon={questionIcon} on:click={showQuestionParams} />
|
||||
</div>
|
||||
<EditBox
|
||||
bind:this={editQuestion}
|
||||
kind={'editbox'}
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.QuestionPlaceholderEmpty}
|
||||
bind:value={question.name}
|
||||
on:change={changeName}
|
||||
/>
|
||||
{/if}
|
||||
<EditBox
|
||||
bind:this={editQuestion}
|
||||
format={'text-multiline'}
|
||||
disabled={readonly}
|
||||
placeholder={survey.string.QuestionPlaceholderEmpty}
|
||||
bind:value={question.name}
|
||||
on:input={() => {
|
||||
haveNameChanges = true
|
||||
}}
|
||||
on:change={handleNameChange}
|
||||
/>
|
||||
{#if !isNewQuestion}
|
||||
{#if question.hasCustomOption && question.kind !== QuestionKind.STRING}
|
||||
<div class="flex-no-shrink" use:tooltip={{ label: survey.string.QuestionTooltipCustomOption }}>
|
||||
<Icon icon={survey.icon.QuestionHasCustomOption} size={'small'} />
|
||||
@ -390,7 +422,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{#if question !== undefined && question.kind !== QuestionKind.STRING}
|
||||
{#if !isNewQuestion && question.kind !== QuestionKind.STRING}
|
||||
{#each options as option, index (index)}
|
||||
<div
|
||||
class="flex-row-center flex-gap-3 option"
|
||||
|
@ -29,6 +29,7 @@
|
||||
export let readonly: boolean = false
|
||||
|
||||
$: questions = object?.questions ?? []
|
||||
$: questionEditSlots = readonly ? questions : [...questions, {}]
|
||||
|
||||
async function nameChange (): Promise<void> {
|
||||
await client.updateDoc(object._class, object.space, object._id, { name: object.name })
|
||||
@ -114,7 +115,7 @@
|
||||
<Label label={survey.string.Questions} />
|
||||
</span>
|
||||
</div>
|
||||
{#each questions as question, index}
|
||||
{#each questionEditSlots as question, index}
|
||||
<div
|
||||
role="listitem"
|
||||
on:dragover={(ev) => {
|
||||
@ -129,35 +130,22 @@
|
||||
draggedOverIndex !== draggedIndex &&
|
||||
draggedOverIndex !== draggedIndex + 1}
|
||||
>
|
||||
<EditQuestion
|
||||
{index}
|
||||
{readonly}
|
||||
parent={object}
|
||||
on:dragStart={() => {
|
||||
draggedIndex = index
|
||||
}}
|
||||
on:dragEnd={() => {
|
||||
draggedIndex = undefined
|
||||
draggedOverIndex = undefined
|
||||
}}
|
||||
/>
|
||||
{#key index}
|
||||
<EditQuestion
|
||||
{index}
|
||||
{readonly}
|
||||
parent={object}
|
||||
on:dragStart={() => {
|
||||
draggedIndex = index
|
||||
}}
|
||||
on:dragEnd={() => {
|
||||
draggedIndex = undefined
|
||||
draggedOverIndex = undefined
|
||||
}}
|
||||
/>
|
||||
{/key}
|
||||
</div>
|
||||
{/each}
|
||||
{#if !readonly}
|
||||
<div
|
||||
role="listitem"
|
||||
on:dragover={(ev) => {
|
||||
dragOver(ev, questions.length)
|
||||
}}
|
||||
on:dragleave={(ev) => {
|
||||
dragLeave(ev, questions.length)
|
||||
}}
|
||||
on:drop={dragDrop}
|
||||
class:dragged-over={draggedOverIndex === questions.length && draggedIndex !== questions.length - 1}
|
||||
>
|
||||
<EditQuestion parent={object} index={-1} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
@ -137,7 +137,7 @@
|
||||
|
||||
<div class="question-answer-container flex-col flex-gap-3">
|
||||
<div class="flex-row-center flex-gap-1 flex-no-shrink">
|
||||
<span class="text-lg caption-color font-medium">{question.name}</span>
|
||||
<strong class="text-base caption-color font-medium pre-wrap">{question.name}</strong>
|
||||
{#if question.isMandatory && !readonly}
|
||||
<div
|
||||
class="flex-no-shrink"
|
||||
@ -151,9 +151,9 @@
|
||||
{#if readonly}
|
||||
{#each getReadonlyAnswers() as answer}
|
||||
{#if answer}
|
||||
<div class="pl-6">{answer}</div>
|
||||
<div class="pre-wrap">{answer}</div>
|
||||
{:else}
|
||||
<div class="pl-6 content-halfcontent-color">
|
||||
<div class="content-halfcontent-color">
|
||||
<Label label={survey.string.NoAnswer} />
|
||||
</div>
|
||||
{/if}
|
||||
@ -180,7 +180,6 @@
|
||||
{#if selectedOption === customOption}
|
||||
<div class="pl-6">
|
||||
<EditBox
|
||||
kind={'ghost-large'}
|
||||
bind:value={answer}
|
||||
placeholder={survey.string.AnswerPlaceholder}
|
||||
focusable
|
||||
@ -206,7 +205,6 @@
|
||||
{#if selectedOptions[customOption]}
|
||||
<div class="pl-6">
|
||||
<EditBox
|
||||
kind={'ghost-large'}
|
||||
bind:value={answer}
|
||||
placeholder={survey.string.AnswerPlaceholder}
|
||||
focusable
|
||||
@ -218,13 +216,14 @@
|
||||
{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<EditBox
|
||||
kind={'ghost-large'}
|
||||
bind:value={answer}
|
||||
placeholder={survey.string.AnswerPlaceholder}
|
||||
focusable
|
||||
on:change={answerChange}
|
||||
/>
|
||||
<div>
|
||||
<EditBox
|
||||
format={'text-multiline'}
|
||||
bind:value={answer}
|
||||
placeholder={survey.string.AnswerPlaceholder}
|
||||
on:change={answerChange}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@ -233,4 +232,7 @@
|
||||
padding-top: var(--spacing-2);
|
||||
border-top: 1px solid var(--theme-divider-color);
|
||||
}
|
||||
.pre-wrap {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
|
@ -95,7 +95,8 @@ const survey = plugin(surveyId, {
|
||||
SurveySubmitConfirm: '' as IntlString,
|
||||
ValidateFail: '' as IntlString,
|
||||
ValidateInfo: '' as IntlString,
|
||||
ValidateOk: '' as IntlString
|
||||
ValidateOk: '' as IntlString,
|
||||
EditAnswers: '' as IntlString
|
||||
},
|
||||
component: {
|
||||
CreateSurvey: '' as AnyComponent,
|
||||
|
Loading…
Reference in New Issue
Block a user