Files
meguri/static/generation-modals.html
Ultradesu 5260c2828b
Checks / test (push) Failing after 2m25s
NEXT
2026-10-07 15:30:31 +01:00

91 lines
28 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template x-if="modal==='variable'"><div>
<label><span x-text="t('variable_name_39179c')"></span><input x-model="form.name" required maxlength="80" :placeholder="t('responsible_37926b')"></label>
<div class="section-line data-mode"><span class="badge" x-text="label(form.node.kind)"></span><button type="button" class="text" @click="dataAdvanced=!dataAdvanced" x-text="dataAdvanced?t('data_values_mode'):t('data_structure_mode')"></button></div>
<template x-if="!dataAdvanced && simpleData(form.node)"><div class="simple-data">
<template x-if="form.node.kind==='list'"><div><template x-for="(entry,index) in form.node.entries" :key="entry.id"><div class="simple-list-row"><span class="step-number" x-text="index+1"></span><template x-if="entry.kind==='text'"><input :aria-label="t('list_value_4318c3')" x-model="entry.value" :placeholder="t('value_8dce17')"></template><template x-if="entry.kind==='person'"><button type="button" class="grow person-select" @click="editDataPeople(form.node,entry)" x-text="dataPersonName(entry.value)"></button></template><button type="button" :aria-label="t('move_entry_up_647a57')" @click="moveNode(form.node,index,-1)" :disabled="!index"><span x-text="t('symbol_9555ff')"></span></button><button type="button" :aria-label="t('move_entry_down_bc86af')" @click="moveNode(form.node,index,1)" :disabled="index===form.node.entries.length-1"><span x-text="t('symbol_fc4866')"></span></button><button type="button" class="text danger" :aria-label="t('remove_entry_18ffc8')" @click="form.node.entries.splice(index,1)"><span x-text="t('symbol_67fba2')"></span></button></div></template><div class="actions"><button type="button" @click="form.node.entries[0]?.kind==='person'?editDataPeople(form.node):addNode(form.node)"><span x-text="t('add_item_51e41d')"></span></button><button type="button" @click="openBulk(form.node)"><span x-text="t('paste_rows_24d667')"></span></button></div></div></template>
<template x-if="form.node.kind!=='list'"><div><div class="matrix-head"><span><span x-text="t('project_key_1c60ec')"></span></span><span><span x-text="t('responsible_people_in_order_d69f7b')"></span></span></div><template x-for="(group,index) in form.node.entries" :key="group.id"><div class="matrix-row"><input :aria-label="t('dictionary_key_9777bd')" x-model="group.key" :placeholder="t('project_name_ab9773')"><div class="matrix-people"><template x-for="(entry,i) in group.entries" :key="entry.id"><span class="matrix-person"><b x-text="i+1"></b><span x-text="dataPersonName(entry.value)"></span><button type="button" :aria-label="t('move_person_earlier_52af52')" x-show="i>0" @click="moveNode(group,i,-1)"><span x-text="t('symbol_817964')"></span></button><button type="button" :aria-label="t('remove_person_2ea467')" @click="group.entries.splice(i,1)"><span x-text="t('symbol_67fba2')"></span></button></span></template><button type="button" class="text" @click="editDataPeople(group)" :aria-label="t('add_person_to_4670b9')+group.key"><span x-text="t('person_485c1d')"></span></button></div><button type="button" class="text danger" :aria-label="t('remove_project_333b0c')" @click="form.node.entries.splice(index,1)"><span x-text="t('symbol_67fba2')"></span></button></div></template><div class="actions"><button type="button" @click="addDataGroup()"><span x-text="t('add_project_key_71d0f2')"></span></button><button type="button" @click="openBulk(form.node)"><span x-text="t('paste_spreadsheet_rows_e07917')"></span></button></div></div></template>
<div class="inline-people" x-show="dataPersonTarget"><div class="section-line"><strong x-text="t('add_to_10956d')+(dataPersonTarget?.key || form.name)"></strong><button type="button" @click="dataPersonTarget=null"><span x-text="t('done_e9b450')"></span></button></div><input type="search" :aria-label="t('find_person_or_email_b640f7')" x-model="dataPersonQuery" :placeholder="t('search_name_or_enter_email_863139')"><div class="cover-options"><template x-for="p in people.filter(p=>[p.display_name,p.email,p.username].some(v=>v?.toLowerCase().includes(dataPersonQuery.toLowerCase())))" :key="p.id"><button type="button" @click="addDataPerson(p.id)" :disabled="dataPersonTarget?.entries.some(e=>e.value===p.id)" x-text="p.display_name"></button></template><button type="button" x-show="/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(dataPersonQuery)" @click="addDataPerson(dataPersonQuery.toLowerCase())" x-text="t('add_e2b431')+dataPersonQuery"></button></div></div>
</div></template>
<div class="data-tree compact-data-tree" :class="{'structure-mode':dataAdvanced}" x-show="dataAdvanced || !simpleData(form.node)"><template x-for="row in nodeRows(form.node)" :key="row.node.id"><div class="data-row" :class="['data-depth-'+row.depth,{'container-row':dataContainer(row.node)}]">
<div class="data-key"><button type="button" class="data-disclosure" x-show="dataContainer(row.node)" :aria-expanded="!!dataExpanded[row.node.id]" :aria-label="t('data_toggle',{name:row.node.key || nodeSummary(row.node)})" @click="toggleDataNode(row.node)" x-text="dataExpanded[row.node.id]?t('data_expanded_symbol'):t('data_collapsed_symbol')"></button><template x-if="row.parent && row.parent.kind!=='list'"><input x-show="dataAdvanced" :aria-label="t('dictionary_key_9777bd')" x-model="row.node.key" :placeholder="t('project_key_98f3fa')" maxlength="120"></template><span x-show="row.parent && row.parent.kind!=='list' && !dataAdvanced" x-text="row.node.key"></span><span x-show="!row.parent || row.parent.kind==='list'" x-text="row.parent?(row.node.kind==='dictionary'?nodeSummary(row.node):t('item_284e12')+(row.index+1)):form.name"></span></div>
<select x-show="dataAdvanced" class="data-type" :aria-label="t('value_type_a95648')" :value="row.node.kind" @change="setNodeKind(row.node,$event.target.value)"><template x-for="kind in nodeKinds"><option :value="kind" :selected="row.node.kind===kind" x-text="kind==='duration'?t('duration_minutes_77d597'):label(kind)"></option></template></select>
<div class="data-value">
<template x-if="['list','dictionary'].includes(row.node.kind)"><div class="actions"><span class="data-container-preview" :title="dataCaption(row.node)" x-text="dataCaption(row.node)"></span><span class="badge" x-text="row.node.entries.length"></span><button type="button" @click="addNode(row.node)"><span x-text="t('entry_dd9298')"></span></button><button type="button" x-show="row.node.entries.every(n=>!dataContainer(n))" @click="openBulk(row.node)"><span x-text="t('paste_rows_24d667')"></span></button></div></template>
<template x-if="row.node.kind==='text'"><input :aria-label="t('text_value_9fe378')" x-model="row.node.value" :placeholder="t('value_8dce17')" maxlength="2000"></template>
<template x-if="row.node.kind==='person'"><div class="person-value"><select :aria-label="t('registered_person_734f05')" :value="people.some(p=>p.id===row.node.value)?row.node.value:''" @change="row.node.value=$event.target.value"><option value="" x-text="t('use_email_address_c12ddf')"></option><template x-for="person in people" :key="person.id"><option :value="person.id" :selected="row.node.value===person.id" x-text="person.display_name"></option></template></select><input :aria-label="t('person_email_1ed8a9')" :type="people.some(p=>p.id===row.node.value)?'text':'email'" x-show="!people.some(p=>p.id===row.node.value)" x-model="row.node.value" :placeholder="t('person_example_com_371ab9')"></div></template>
<template x-if="['number','duration'].includes(row.node.kind)"><input :aria-label="t('number_value_f84357')" type="number" step="any" :value="row.node.value" @input="row.node.value=$event.target.value===''?null:Number($event.target.value)"></template>
<template x-if="row.node.kind==='boolean'"><select :aria-label="t('boolean_value_4d92eb')" :value="String(row.node.value)" @change="row.node.value=$event.target.value==='true'"><option value="true" x-text="t('true_88b33e')"></option><option value="false" x-text="t('false_97cdbd')"></option></select></template>
<template x-if="row.node.kind==='time'"><input :aria-label="t('time_value_1072a0')" type="time" x-model="row.node.value"></template>
<template x-if="row.node.kind==='date'"><span class="date-field" x-data="dateField" x-modelable="value" x-model="row.node.value"><input type="text" :aria-label="t('date_value_1f290a')" x-ref="textDate" :value="text" @input="edit($event.target)" :placeholder="t('dd_mm_yyyy_d7e5fe')" inputmode="numeric" maxlength="10"><button type="button" :aria-label="t('open_calendar_41547e')" @click="$refs.calendar.showPicker()"><span x-text="t('symbol_21887f')"></span></button><input class="native-date" type="date" x-ref="calendar" x-model="value" @input="picked()" tabindex="-1" aria-hidden="true"></span></template>
</div>
<div class="data-actions" x-show="row.parent"><button type="button" :aria-label="t('data_duplicate')" @click="duplicateDataNode(row.parent,row.index)" x-text="t('data_duplicate_symbol')"></button><button type="button" :aria-label="t('move_entry_up_647a57')" @click="moveNode(row.parent,row.index,-1)" :disabled="row.index===0"><span x-text="t('symbol_9555ff')"></span></button><button type="button" :aria-label="t('move_entry_down_bc86af')" @click="moveNode(row.parent,row.index,1)" :disabled="!row.parent || row.index===row.parent.entries.length-1"><span x-text="t('symbol_fc4866')"></span></button><button type="button" class="text danger" :aria-label="t('remove_entry_18ffc8')" @click="row.parent.entries.splice(row.index,1)"><span x-text="t('symbol_67fba2')"></span></button></div>
</div></template></div>
<template x-if="bulkNode"><div class="bulk-editor"><h3><span x-text="t('append_rows_03d5d2')"></span></h3><p class="muted" x-text="bulkNode.kind==='list'?t('one_value_per_line_existing_entries_are_kept_244563'):t('paste_two_spreadsheet_columns_project_key_then_comma_9b3966')"></p><textarea :aria-label="t('rows_to_append_2ddee4')" x-model="bulkText" rows="5"></textarea><div class="actions"><button type="button" @click="try{appendBulk()}catch(e){error=e.message}"><span x-text="t('append_rows_03d5d2')"></span></button><button type="button" @click="bulkNode=null"><span x-text="t('cancel_paste_fbbf61')"></span></button></div></div></template>
<div x-show="!rulePeopleTarget"><!-- GENERATION_PREVIEW --></div>
</div></template>
<template x-if="modal==='generation-rule'"><div><div class="rule-constructor" x-show="!rulePeopleTarget">
<div class="two-columns rule-identity"><label><span x-text="t('rule_name_9e84d7')"></span><input x-model="form.name" required maxlength="120" :placeholder="t('builder_rule_name')"></label><label class="check"><input type="checkbox" x-model="form.enabled"><span x-text="t('enabled_df174a')"></span></label></div>
<div class="constructor-layout"><aside class="constructor-inputs">
<section class="constructor-section"><div class="section-line"><h3 x-text="t('builder_iterations')"></h3><button type="button" @click="addIteration()" :disabled="form.iterations.length>=4" x-text="t('iteration_3b56cf')"></button></div>
<p class="constructor-empty" x-show="!form.iterations.length" x-text="t('builder_once')"></p>
<template x-for="(iteration,index) in form.iterations" :key="iteration.id"><div class="constructor-loop">
<div class="constructor-loop-title"><span class="logic-key" x-text="index?t('then_for_each_4ca48c'):t('for_each_fb4174')"></span><button type="button" class="text danger" :aria-label="t('builder_remove_iteration',{name:iteration.name})" @click="form.iterations.splice(index,1)" x-text="t('remove_e96390')"></button></div>
<label><span x-text="t('builder_alias')"></span><input :aria-label="t('iteration_name_fc3d26')" x-model="iteration.name" :placeholder="t('builder_alias_placeholder')"></label>
<label><span x-text="t('iteration_collection_bd6344')"></span><select :aria-label="t('iteration_collection_bd6344')" :value="simpleSource(iteration.source,'collection')" @change="selectSimpleSource(iteration.source,$event.target.value,'collection')"><option value="literal" x-text="t('builder_choose_collection')"></option><template x-for="option in sourceOptions('collection')" :key="option.id"><option :value="option.id" :selected="simpleSource(iteration.source,'collection')===option.id" x-text="option.name"></option></template><option value="advanced" x-text="t('custom_binding')"></option></select></label>
<button type="button" class="binding-button constructor-binding" @click="editBinding(iteration.source,'collection',t('iteration_collection_bd6344'))" x-text="bindingSummary(iteration.source)"></button>
</div></template>
</section>
<section class="constructor-section constructor-filter"><h3 x-text="t('builder_filter')"></h3><label class="check"><input type="checkbox" :checked="!!form.when" @change="toggleGenCondition($event.target.checked)"><span x-text="t('only_generate_when_a_condition_matches_78d185')"></span></label>
<template x-if="form.when"><div class="constructor-predicate"><button type="button" class="binding-button" @click="editBinding(form.when.left,'text',t('condition_left_value_cc4063'))" x-text="bindingSummary(form.when.left)"></button><select :aria-label="t('generation_condition_424e30')" x-model="form.when.operation"><option value="equals" x-text="t('equals_09b6a6')"></option><option value="not_equals" x-text="t('does_not_equal_86e30f')"></option><option value="contains" x-text="t('contains_33e15d')"></option><option value="not_empty" x-text="t('is_not_empty_414a30')"></option></select><button type="button" class="binding-button" x-show="form.when.operation!=='not_empty'" @click="editBinding(form.when.right,'text',t('condition_right_value_5e741f'))" x-text="bindingSummary(form.when.right)"></button></div></template>
</section></aside><main class="constructor-outputs">
<section class="recipe-section"><div class="section-line"><h3><span x-text="t('builder_outputs')"></span></h3><select :aria-label="t('add_output_block_00047b')" @change="if($event.target.value)addBlock($event.target.value);$event.target.value=''"><option value="" x-text="t('add_another_resource')"></option><optgroup :label="t('schedules_26d9d0')"><template x-for="kind in ['priority','rotation']"><option :value="kind" x-text="label(kind)"></option></template></optgroup><optgroup :label="t('escalation_policies_ad128e')"><option value="escalation" x-text="label('escalation')"></option></optgroup><optgroup :label="t('routing_rules_49ce36')"><option value="route" x-text="label('route')"></option></optgroup></select></div>
<p class="constructor-empty" x-show="!form.blocks.length" x-text="t('builder_add_output')"></p><template x-for="(block,index) in form.blocks" :key="block.id"><section class="generation-block" :data-block-id="block.id">
<div class="route-heading"><span class="badge" x-text="(index+1)+' · '+label(block.kind)"></span><strong class="grow" :class="{'template-token':block.fields.name?.kind!=='literal'}" x-text="bindingSummary(block.fields.name)"></strong><button type="button" :aria-label="t('move_block_up_b67b5b')" :disabled="index===0" @click="moveBlock(index,-1)"><span x-text="t('symbol_9555ff')"></span></button><button type="button" :aria-label="t('move_block_down_714fea')" :disabled="index===form.blocks.length-1" @click="moveBlock(index,1)"><span x-text="t('symbol_fc4866')"></span></button><button type="button" class="text danger" @click="form.blocks.splice(index,1)"><span x-text="t('remove_e96390')"></span></button></div>
<div class="binding-grid"><template x-for="field in fieldsFor(block.kind)" :key="field.key"><div class="recipe-field" :class="{'compact-scalar-field':['number','date','time','boolean'].includes(field.type) && block.fields[field.key]?.kind==='literal','compact-number-field':field.type==='number','compact-time-field':field.type==='time'}"><label :for="block.id+'-'+field.key" x-text="field.label"></label>
<template x-if="field.key==='name'"><input class="block-name-input" :id="block.id+'-'+field.key" :aria-label="field.label" :value="bindingSummary(block.fields.name)" :readonly="block.fields.name.kind!=='literal' || !!block.fields.name.prefix || !!block.fields.name.suffix || !!block.fields.name.path?.length" @input="block.fields.name.value=$event.target.value"></template>
<template x-if="field.key!=='name'"><div><select x-show="['list','schedule','policy'].includes(field.type) || block.fields[field.key]?.kind!=='literal'" :id="block.id+'-'+field.key" :aria-label="field.label" :value="simpleSource(block.fields[field.key],field.type)" @change="selectSimpleSource(block.fields[field.key],$event.target.value,field.type)"><option value="literal" x-text="t('fixed_value_191429')"></option><template x-for="option in sourceOptions(field.type)" :key="option.id"><option :value="option.id" :selected="simpleSource(block.fields[field.key],field.type)===option.id" x-text="option.name"></option></template><option value="advanced" x-text="simpleSource(block.fields[field.key],field.type)==='advanced'?bindingSummary(block.fields[field.key]):t('custom_binding')"></option></select>
<template x-if="block.fields[field.key]?.kind==='literal' && !['schedule','policy'].includes(field.type)"><div>
<template x-if="['text','time','number','person'].includes(field.type)"><input class="inline-value" :aria-label="field.label+' · '+t('fixed_value_191429')" :type="field.type==='number'?'number':field.type==='time'?'time':'text'" :value="block.fields[field.key].value" @input="block.fields[field.key].value=field.type==='number'?($event.target.value===''?null:Number($event.target.value)):$event.target.value"></template>
<template x-if="field.type==='date'"><span class="date-field" x-data="dateField" x-modelable="value" x-model="block.fields[field.key].value"><input type="text" :aria-label="field.label+' · '+t('fixed_value_191429')" x-ref="textDate" :value="text" @input="edit($event.target)" :placeholder="t('dd_mm_yyyy_d7e5fe')" maxlength="10"><button type="button" :aria-label="t('open_calendar_41547e')" @click="$refs.calendar.showPicker()"><span x-text="t('symbol_21887f')"></span></button><input class="native-date" type="date" x-ref="calendar" x-model="value" @input="picked()" tabindex="-1" aria-hidden="true"></span></template>
<template x-if="field.type==='boolean'"><label class="check"><input type="checkbox" x-model="block.fields[field.key].value"><span x-text="t('enabled_df174a')"></span></label></template>
<template x-if="field.type==='list'"><div><div class="people-row"><template x-for="(id,personIndex) in block.fields[field.key].value"><button type="button" class="person-chip" @click="block.fields[field.key].value.splice(personIndex,1)" :aria-label="t('remove_e96390')+' '+dataPersonName(id)" x-text="(personIndex+1)+'. '+dataPersonName(id)+' ×'"></button></template></div><button type="button" class="text" @click="openRulePeople(block.fields[field.key])" x-text="t('add_person_c126e2')"></button></div></template>
</div></template>
</div></template><button type="button" class="text binding-tweak" @click="editBinding(block.fields[field.key] ||= literal(''),field.type,field.label)" :aria-label="t('bind_891f4e')+field.label" x-text="t('binding_picker_button')" :title="t('value_source_c0ae15')"></button>
</div></template></div>
<template x-if="block.kind==='escalation'"><div><template x-for="(step,stepIndex) in block.steps" :key="stepIndex"><div class="generation-step"><span class="flow-arrow"><span x-text="t('symbol_fc4866')"></span></span><div class="inline-binding inline-delay"><template x-if="step.delay.kind==='literal'"><input type="number" min="0" :aria-label="t('delay_in_minutes_e18c95')" :value="step.delay.value" @input="step.delay.value=$event.target.value===''?null:Number($event.target.value)"></template><button type="button" class="binding-button" x-show="step.delay.kind!=='literal'" @click="editBinding(step.delay,'number',t('delay_in_minutes_e18c95'))" x-text="bindingSummary(step.delay)"></button><span x-text="t('min_f4e8a8')"></span><button type="button" class="binding-popup-trigger" :aria-label="t('bind_891f4e')+t('delay_in_minutes_e18c95')" @click="editBinding(step.delay,'number',t('delay_in_minutes_e18c95'))" x-text="t('binding_picker_button')"></button></div><select :aria-label="t('escalation_condition_5b4c13')" x-model="step.condition"><option value="if-not-acked" x-text="t('if_not_acknowledged_5fc93a')"></option><option value="if-not-closed" x-text="t('if_not_closed_4369ad')"></option></select><select :aria-label="t('recipient_type_32b1f5')" :value="step.team_all?'team_all':step.team_random?'team_random':step.user?'person':'schedule'" @change="step.team_all=$event.target.value==='team_all';step.team_random=$event.target.value==='team_random';step.user=$event.target.value==='person'"><option value="schedule" x-text="t('schedule_0a8ada')"></option><option value="person" x-text="t('person_8c41ae')"></option><option value="team_all" x-text="t('everyone_on_the_team_235b55')"></option><option value="team_random" x-text="t('a_random_team_member_8f35f3')"></option></select><button x-show="!step.team_all&&!step.team_random" type="button" class="binding-button grow" @click="editBinding(step.recipient,step.user?'person':'schedule',t('escalation_recipient_9dfd31'))" x-text="bindingSummary(step.recipient)"></button><button type="button" class="text danger" @click="block.steps.splice(stepIndex,1)"><span x-text="t('symbol_67fba2')"></span></button></div></template><button type="button" class="text" @click="addGenStep(block)"><span x-text="t('escalation_step_72b706')"></span></button></div></template>
<template x-if="block.kind==='route'"><div><p class="muted" x-show="!block.conditions.length"><span x-text="t('matches_any_alert_add_conditions_to_target_this_proj_299abf')"></span></p><template x-for="(condition,conditionIndex) in block.conditions" :key="conditionIndex"><div class="generation-step"><span class="logic-key" x-text="conditionIndex?t('and_c2f934'):t('if_7be63e')"></span><select :aria-label="t('routing_field_a63fdc')" x-model="condition.field"><option value="tags" x-text="t('tags_848eed')"></option><option value="message" x-text="t('message_68f414')"></option><option value="priority" x-text="t('priority_886cbf')"></option><option value="description" x-text="t('description_55f8eb')"></option><option value="source" x-text="t('source_6da13a')"></option></select><select :aria-label="t('routing_operation_01689c')" x-model="condition.operation"><option value="greater-than" x-text="t('routing_greater_than')"></option><option value="less-than" x-text="t('routing_less_than')"></option><option value="contains" x-text="t('contains_33e15d')"></option><option value="equals" x-text="t('equals_09b6a6')"></option><option value="starts-with" x-text="t('starts_with_2a61f5')"></option><option value="matches" x-text="t('matches_ee2dbd')"></option></select><button type="button" class="binding-button grow" @click="editBinding(condition.value,'text',t('routing_condition_value_f76e2d'))" x-text="bindingSummary(condition.value)"></button><label class="check"><input type="checkbox" x-model="condition.negate"><span x-text="t('not_ca1dd3')"></span></label><button type="button" class="text danger" @click="block.conditions.splice(conditionIndex,1)"><span x-text="t('symbol_67fba2')"></span></button></div></template><button type="button" class="text" @click="addGenCondition(block)"><span x-text="t('and_condition_63ce48')"></span></button></div></template>
</section></template>
</section>
<details class="recipe-section rule-result" open>
<summary><strong x-text="t('rule_result_title')"></strong><small :class="{'danger':generationError || generationResult?.issues.length}" x-text="ruleResultStatus()" aria-live="polite"></small></summary>
<div class="rule-result-list" x-show="!generationLoading && ruleResultDocument()">
<template x-for="entry in ruleResultResources()" :key="entry.id"><div class="rule-result-row">
<svg class="resource-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path :d="resourceIcon(entry.kind)"></path></svg>
<div><div class="rule-result-name"><span class="badge" x-text="label(entry.kind)"></span><strong x-text="entry.resource.name"></strong></div><small x-text="resourceBrief(entry.resource,entry.kind,ruleResultDocument())"></small></div>
</div></template></div>
</details>
</main></div></div><template x-if="rulePeopleTarget"><section class="binding-editor"><div class="section-line"><input type="search" :aria-label="t('search_people_or_email')" :placeholder="t('search_people_or_email')" x-model="rulePeopleQuery"><button type="button" @click="closeRuleEditor()" x-text="t('back_c32ae9')"></button></div><div class="people-row"><template x-for="person in people.filter(p=>[p.display_name,p.email,p.username].some(v=>v?.toLowerCase().includes(rulePeopleQuery.toLowerCase())) && !rulePeopleTarget.value.includes(p.id))"><button type="button" @click="addRulePerson(person.id)" x-text="person.display_name"></button></template><button type="button" x-show="/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(rulePeopleQuery)" @click="addRulePerson(rulePeopleQuery.trim())" x-text="rulePeopleQuery"></button></div></section></template>
<!-- BINDING_POPOVER -->
<div x-show="!rulePeopleTarget"><!-- GENERATION_PREVIEW --></div>
</div></template>
<template x-if="modal==='generation-transfer'"><div class="config-transfer">
<p class="muted" x-text="t('transfer_hint')"></p>
<div class="actions"><button type="button" :class="{primary:transferMode==='export'}" @click="transferSwitch('export')" x-text="t('transfer_export')"></button><button type="button" :class="{primary:transferMode==='import'}" @click="transferSwitch('import')" x-text="t('transfer_import')"></button><button type="button" :class="{primary:transferMode==='guide'}" :aria-pressed="transferMode==='guide'" @click="transferSwitch('guide')" x-text="t('transfer_guide')"></button></div>
<section class="config-guide" x-show="transferMode==='guide'" :aria-label="t('transfer_guide')"><div class="section-line"><p class="muted" x-text="t('transfer_guide_hint')"></p><button type="button" @click="copyTransferGuide()" x-text="t('transfer_guide_copy')"></button></div><template x-for="section in transferGuideSections()" :key="section.id"><section><h3 x-text="section.title"></h3><pre :class="{'guide-example':section.code}" x-text="section.body"></pre></section></template></section>
<div x-show="transferMode==='export'"><label><span x-text="t('transfer_document')"></span><textarea class="config-text" rows="16" readonly :value="transferExport" spellcheck="false"></textarea></label><div class="actions"><button type="button" @click="copyTransfer()" :disabled="!transferExport || transferLoading" x-text="t('transfer_copy')"></button><button type="button" @click="downloadTransfer()" :disabled="!transferExport || transferLoading" x-text="t('transfer_download')"></button></div></div>
<div x-show="transferMode==='import'"><label><span x-text="t('transfer_paste')"></span><textarea class="config-text" rows="16" x-model="transferText" @input="transferChanged()" :disabled="busy" spellcheck="false"></textarea></label>
<p class="muted" x-text="t('transfer_identity_hint')"></p>
<div class="transfer-preview" aria-live="polite"><template x-if="transferResult"><div>
<h3 x-text="t('transfer_inputs')"></h3><template x-for="(change,index) in transferResult.inputs" :key="index"><div class="compact-change"><span class="badge" x-text="label(change.action)"></span><strong x-text="change.name"></strong><small x-text="t(change.kind==='variable'?'map_variables':'map_generators')"></small></div></template>
<div x-show="transferResult.contacts?.length"><h3 x-text="t('transfer_contacts')"></h3><template x-for="contact in transferResult.contacts" :key="contact.id"><p x-text="contact.email"></p></template></div>
<h3 x-text="t('map_generated_resources')"></h3><p x-show="!transferResult.preview.changes.length" x-text="t('transfer_no_resources')"></p><template x-for="change in transferResult.preview.changes" :key="change.id"><div class="compact-change"><span class="badge" x-text="label(change.action)"></span><strong x-text="change.name"></strong><small x-text="label(change.kind)"></small></div></template>
<template x-for="(issue,index) in transferResult.preview.issues" :key="index"><p class="validation-error"><strong x-text="issue.path"></strong><span x-text="l(issue.message)"></span></p></template>
<p class="validation-warning" x-show="transferResult.preview.cancelled_requests" x-text="transferResult.preview.cancelled_requests+t('pending_requests_will_be_cancelled_because_their_sch_ea9b18')"></p>
</div></template></div></div>
<p role="status" x-show="transferLoading" x-text="t('cover_checking')"></p><p role="alert" class="validation-error" x-show="transferError" x-text="l(transferError)"></p>
<div class="modal-footer"><button type="button" @click="modal=''" x-text="t('close_dialog_7b2902')"></button><button type="button" class="primary" x-show="transferMode==='import'" :disabled="busy || !transferCanApply()" @click="applyTransfer()" x-text="t('transfer_apply')"></button></div>
</div></template>