feat: Discord/Slack/ntfy/Matrix targets, command templates, delete protection, email/matrix bots
- Discord, Slack, ntfy, Matrix notification target types with clients and dispatch - MatrixBot model + API + frontend in Bots tab - Command template system fully wired into all handler commands - Default command templates seeded (EN/RU, 14 slots each) - Command template editor with variables reference including child fields - Delete protection on all 10 entity types (409 with consumer details) - Provider type selector on template config forms - Target type selector as dropdown with all 7 types - Response template selector on command config form - CLAUDE.md: mandatory server restart rule, child properties rule
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
import { snackSuccess, snackError } from '$lib/stores/snackbar.svelte';
|
||||
|
||||
let configs = $state<any[]>([]);
|
||||
let cmdTemplateConfigs = $state<any[]>([]);
|
||||
let loaded = $state(false);
|
||||
let showForm = $state(false);
|
||||
let editing = $state<number | null>(null);
|
||||
@@ -46,13 +47,17 @@
|
||||
response_mode: 'media',
|
||||
default_count: 5,
|
||||
rate_limits: { search: 30, default: 10 },
|
||||
command_template_config_id: null as number | null,
|
||||
});
|
||||
let form = $state(defaultForm());
|
||||
|
||||
onMount(load);
|
||||
async function load() {
|
||||
try {
|
||||
configs = await api('/command-configs');
|
||||
[configs, cmdTemplateConfigs] = await Promise.all([
|
||||
api('/command-configs'),
|
||||
api('/command-template-configs'),
|
||||
]);
|
||||
} catch (err: any) { error = err.message || t('common.loadError'); snackError(error); }
|
||||
finally { loaded = true; }
|
||||
}
|
||||
@@ -68,6 +73,7 @@
|
||||
response_mode: cfg.response_mode || 'media',
|
||||
default_count: cfg.default_count || 5,
|
||||
rate_limits: { search: cfg.rate_limits?.search || 30, default: cfg.rate_limits?.default || 10 },
|
||||
command_template_config_id: cfg.command_template_config_id || null,
|
||||
};
|
||||
editing = cfg.id;
|
||||
showForm = true;
|
||||
@@ -157,6 +163,17 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="cc-template" class="block text-sm font-medium mb-1">{t('commandConfig.responseTemplate')}</label>
|
||||
<select id="cc-template" bind:value={form.command_template_config_id}
|
||||
class="w-full px-3 py-2 border border-[var(--color-border)] rounded-md text-sm bg-[var(--color-background)]">
|
||||
<option value={null}>— {t('commandConfig.noTemplate')} —</option>
|
||||
{#each cmdTemplateConfigs.filter((c: any) => c.provider_type === form.provider_type) as tpl}
|
||||
<option value={tpl.id}>{tpl.name}{tpl.user_id === 0 ? ' (System)' : ''}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs mb-1">{t('commandConfig.locale')}</label>
|
||||
|
||||
Reference in New Issue
Block a user