mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-03-14 12:23:33 +00:00
196 lines
8.1 KiB
PHP
196 lines
8.1 KiB
PHP
<?php
|
||
|
||
use App\Models\Plugin;
|
||
use Illuminate\Validation\Rule;
|
||
use Livewire\Component;
|
||
use Symfony\Component\Yaml\Exception\ParseException;
|
||
use Symfony\Component\Yaml\Yaml;
|
||
|
||
/*
|
||
* This component contains the TRMNL Plugin Settings modal.
|
||
*/
|
||
new class extends Component
|
||
{
|
||
public Plugin $plugin;
|
||
|
||
public ?string $trmnlp_id = null;
|
||
|
||
public ?string $uuid = null;
|
||
|
||
public bool $alias = false;
|
||
|
||
public bool $use_trmnl_liquid_renderer = false;
|
||
|
||
public string $configurationTemplateYaml = '';
|
||
|
||
public int $resetIndex = 0;
|
||
|
||
public function mount(): void
|
||
{
|
||
$this->resetErrorBag();
|
||
$this->plugin = $this->plugin->fresh();
|
||
$this->trmnlp_id = $this->plugin->trmnlp_id;
|
||
$this->uuid = $this->plugin->uuid;
|
||
$this->alias = $this->plugin->alias ?? false;
|
||
$this->use_trmnl_liquid_renderer = $this->plugin->preferred_renderer === 'trmnl-liquid';
|
||
$this->configurationTemplateYaml = $this->plugin->getCustomFieldsEditorYaml();
|
||
}
|
||
|
||
public function saveTrmnlpId(): void
|
||
{
|
||
abort_unless(auth()->user()->plugins->contains($this->plugin), 403);
|
||
|
||
$this->validate([
|
||
'trmnlp_id' => [
|
||
'nullable',
|
||
'string',
|
||
'max:255',
|
||
Rule::unique('plugins', 'trmnlp_id')
|
||
->where('user_id', auth()->id())
|
||
->ignore($this->plugin->id),
|
||
],
|
||
'alias' => 'boolean',
|
||
'use_trmnl_liquid_renderer' => 'boolean',
|
||
'configurationTemplateYaml' => [
|
||
'nullable',
|
||
'string',
|
||
function (string $attribute, mixed $value, \Closure $fail): void {
|
||
if ($value === '') {
|
||
return;
|
||
}
|
||
try {
|
||
$parsed = Yaml::parse($value);
|
||
if (! is_array($parsed)) {
|
||
$fail('The configuration must be valid YAML and evaluate to an object/array.');
|
||
return;
|
||
}
|
||
Plugin::validateCustomFieldsList($parsed);
|
||
} catch (ParseException) {
|
||
$fail('The configuration must be valid YAML.');
|
||
} catch (\Illuminate\Validation\ValidationException $e) {
|
||
foreach ($e->errors() as $messages) {
|
||
foreach ($messages as $message) {
|
||
$fail($message);
|
||
}
|
||
}
|
||
}
|
||
},
|
||
],
|
||
]);
|
||
|
||
$configurationTemplate = Plugin::configurationTemplateFromCustomFieldsYaml(
|
||
$this->configurationTemplateYaml,
|
||
$this->plugin->configuration_template
|
||
);
|
||
|
||
$this->plugin->update([
|
||
'trmnlp_id' => empty($this->trmnlp_id) ? null : $this->trmnlp_id,
|
||
'alias' => $this->alias,
|
||
'preferred_renderer' => $this->use_trmnl_liquid_renderer ? 'trmnl-liquid' : null,
|
||
'configuration_template' => $configurationTemplate,
|
||
]);
|
||
|
||
$this->dispatch('config-updated');
|
||
Flux::modal('trmnlp-settings')->close();
|
||
}
|
||
|
||
public function getAliasUrlProperty(): string
|
||
{
|
||
return url("/api/display/{$this->uuid}/alias");
|
||
}
|
||
}; ?>
|
||
|
||
<flux:modal name="trmnlp-settings" class="min-w-[600px] max-w-2xl space-y-6">
|
||
<div wire:key="trmnlp-settings-form-{{ $resetIndex }}" class="space-y-6">
|
||
<div>
|
||
<flux:heading size="lg">Recipe Settings</flux:heading>
|
||
</div>
|
||
|
||
<form wire:submit="saveTrmnlpId">
|
||
<div class="grid gap-6">
|
||
{{-- <flux:input label="UUID" wire:model="uuid" readonly copyable /> --}}
|
||
<flux:field>
|
||
<flux:label>TRMNLP Recipe ID</flux:label>
|
||
<flux:input
|
||
wire:model="trmnlp_id"
|
||
placeholder="TRMNL Recipe ID"
|
||
/>
|
||
<flux:error name="trmnlp_id" />
|
||
<flux:description>Recipe ID in the TRMNL Recipe Catalog. If set, it can be used with <code>trmnlp</code>. </flux:description>
|
||
</flux:field>
|
||
|
||
<flux:field>
|
||
<flux:checkbox wire:model.live="alias" label="Enable Alias" />
|
||
<flux:description>Enable an Alias URL for this recipe. Your server does not need to be exposed to the internet, but your device must be able to reach the URL. <a href="https://help.usetrmnl.com/en/articles/10701448-alias-plugin">Docs</a></flux:description>
|
||
</flux:field>
|
||
|
||
@if(config('services.trmnl.liquid_enabled') && $plugin->markup_language === 'liquid')
|
||
<flux:field>
|
||
<flux:checkbox
|
||
wire:model.live="use_trmnl_liquid_renderer"
|
||
label="Use trmnl-liquid renderer"
|
||
/>
|
||
<flux:description>trmnl-liquid is a Ruby-based renderer that matches the Core service’s Liquid behavior for better compatibility.</flux:description>
|
||
</flux:field>
|
||
@endif
|
||
|
||
<flux:field>
|
||
<flux:label>Configuration template</flux:label>
|
||
<flux:description>
|
||
Build forms visually in the <a href="https://usetrmnl.github.io/trmnl-form-builder/" target="_blank" rel="noopener noreferrer">TRMNL YML Form Builder</a>.
|
||
Check the <a href="https://help.trmnl.com/en/articles/10513740-custom-plugin-form-builder" target="_blank" rel="noopener noreferrer">docs</a> for more information.
|
||
</flux:description>
|
||
@php
|
||
$configTemplateTextareaId = 'config-template-' . uniqid();
|
||
@endphp
|
||
<flux:textarea
|
||
wire:model="configurationTemplateYaml"
|
||
id="{{ $configTemplateTextareaId }}"
|
||
placeholder="[]"
|
||
rows="12"
|
||
hidden
|
||
/>
|
||
<div
|
||
x-data="codeEditorFormComponent({
|
||
isDisabled: false,
|
||
language: 'yaml',
|
||
state: $wire.entangle('configurationTemplateYaml'),
|
||
textareaId: @js($configTemplateTextareaId)
|
||
})"
|
||
wire:ignore
|
||
wire:key="cm-{{ $configTemplateTextareaId }}"
|
||
class="min-h-[200px] h-[300px] overflow-hidden resize-y"
|
||
>
|
||
<div x-show="isLoading" class="flex items-center justify-center h-full">
|
||
<div class="flex items-center space-x-2">
|
||
<flux:icon.loading />
|
||
</div>
|
||
</div>
|
||
<div x-show="!isLoading" x-ref="editor" class="h-full"></div>
|
||
</div>
|
||
<flux:error name="configurationTemplateYaml" />
|
||
</flux:field>
|
||
|
||
@if($alias)
|
||
<flux:field>
|
||
<flux:label>Alias URL</flux:label>
|
||
<flux:input
|
||
value="{{ $this->aliasUrl }}"
|
||
readonly
|
||
copyable
|
||
/>
|
||
<flux:description>Copy this URL to your TRMNL Dashboard. By default, image is created for TRMNL OG; use parameter <code>?device-model=</code> to specify a device model.</flux:description>
|
||
</flux:field>
|
||
@endif
|
||
</div>
|
||
|
||
<div class="flex gap-2 mt-4">
|
||
<flux:spacer/>
|
||
<flux:modal.close>
|
||
<flux:button variant="ghost">Cancel</flux:button>
|
||
</flux:modal.close>
|
||
<flux:button type="submit" variant="primary">Save</flux:button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</flux:modal>
|