From 0aa5986c1267367183fcfff8af0269ebce454bf4 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Tue, 17 Feb 2026 13:15:19 -0600 Subject: [PATCH] Enhancement: Reorganized the form into collapsible accordion sections (Pattern Configuration, Output Templates, Upcoming/Ended Templates, Fallback Templates, EPG Settings) for better organization. Field descriptions now appear in info icon popovers instead of taking up vertical space, making the form more compact and easier to navigate while keeping help text accessible. --- CHANGELOG.md | 1 + frontend/src/components/forms/DummyEPG.jsx | 821 +++++++++++++-------- 2 files changed, 497 insertions(+), 325 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da99fb5c..f7c10fbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Custom Dummy EPG form UI improvements: Reorganized the form into collapsible accordion sections (Pattern Configuration, Output Templates, Upcoming/Ended Templates, Fallback Templates, EPG Settings) for better organization. Field descriptions now appear in info icon popovers instead of taking up vertical space, making the form more compact and easier to navigate while keeping help text accessible. - XC API M3U stream URLs: M3U generation for Xtream Codes API endpoints now use proper XC-style stream URLs (`/live/username/password/channel_id`) instead of UUID-based stream endpoints, ensuring full compatibility with XC clients. (Fixes #839) ### Fixed diff --git a/frontend/src/components/forms/DummyEPG.jsx b/frontend/src/components/forms/DummyEPG.jsx index 06731ac9..701dafd7 100644 --- a/frontend/src/components/forms/DummyEPG.jsx +++ b/frontend/src/components/forms/DummyEPG.jsx @@ -1,5 +1,7 @@ import React, { useEffect, useMemo, useState } from 'react'; import { + Accordion, + ActionIcon, Box, Button, Checkbox, @@ -8,12 +10,14 @@ import { Modal, NumberInput, Paper, + Popover, Select, Stack, Text, TextInput, Textarea, } from '@mantine/core'; +import { Info } from 'lucide-react'; import { useForm } from '@mantine/form'; import { notifications } from '@mantine/notifications'; import API from '../../api'; @@ -26,6 +30,30 @@ import timezone from 'dayjs/plugin/timezone'; dayjs.extend(utc); dayjs.extend(timezone); +// Helper component for labels with info popover +const LabelWithInfo = ({ label, info, required }) => ( + + + {label} + {required && ( + + * + + )} + + + + + + + + + {info} + + + +); + const DummyEPGForm = ({ epg, isOpen, onClose }) => { // Get all EPGs from the store const epgs = useEPGsStore((state) => state.epgs); @@ -822,355 +850,494 @@ const DummyEPGForm = ({ epg, isOpen, onClose }) => { {...form.getInputProps('name')} /> - {/* Pattern Configuration */} - + {/* Accordion for organized sections */} + + + Pattern Configuration + + + + Define regex patterns to extract information from channel + titles or stream names. Use named capture groups like + (?<groupname>pattern). + - - Define regex patterns to extract information from channel titles or - stream names. Use named capture groups like - (?<groupname>pattern). - + + {form.values.custom_properties?.name_source === 'stream' && ( + + } + placeholder="1" + min={1} + max={100} + {...form.getInputProps('custom_properties.stream_index')} + /> + )} - {form.values.custom_properties?.name_source === 'stream' && ( - - )} + + } + placeholder="(?\w+) \d+: (?.*) VS (?.*)" + required + withAsterisk={false} + value={titlePattern} + onChange={(e) => { + const value = e.target.value; + setTitlePattern(value); + form.setFieldValue( + 'custom_properties.title_pattern', + value + ); + }} + error={form.errors['custom_properties.title_pattern']} + /> - { - const value = e.target.value; - setTitlePattern(value); - form.setFieldValue('custom_properties.title_pattern', value); - }} - error={form.errors['custom_properties.title_pattern']} - /> + + } + placeholder="@ (?\d+):(?\d+)(?AM|PM)" + value={timePattern} + onChange={(e) => { + const value = e.target.value; + setTimePattern(value); + form.setFieldValue( + 'custom_properties.time_pattern', + value + ); + }} + /> - { - const value = e.target.value; - setTimePattern(value); - form.setFieldValue('custom_properties.time_pattern', value); - }} - /> + + } + placeholder="@ (?\w+) (?\d+)" + value={datePattern} + onChange={(e) => { + const value = e.target.value; + setDatePattern(value); + form.setFieldValue( + 'custom_properties.date_pattern', + value + ); + }} + /> + + + - { - const value = e.target.value; - setDatePattern(value); - form.setFieldValue('custom_properties.date_pattern', value); - }} - /> + + Output Templates + + + + Use extracted groups from your patterns to format EPG titles + and descriptions. Reference groups using {'{groupname}'}{' '} + syntax. For cleaner URLs, use {'{groupname_normalize}'} to + get alphanumeric-only lowercase versions. + - {/* Output Templates */} - + + } + placeholder="{league} - {team1} vs {team2}" + value={titleTemplate} + onChange={(e) => { + const value = e.target.value; + setTitleTemplate(value); + form.setFieldValue( + 'custom_properties.title_template', + value + ); + }} + /> - - Use extracted groups from your patterns to format EPG titles and - descriptions. Reference groups using {'{groupname}'} syntax. For - cleaner URLs, use {'{groupname_normalize}'} to get alphanumeric-only - lowercase versions. - + + } + placeholder="{starttime} - {endtime}" + value={subtitleTemplate} + onChange={(e) => { + const value = e.target.value; + setSubtitleTemplate(value); + form.setFieldValue( + 'custom_properties.subtitle_template', + value + ); + }} + /> - { - const value = e.target.value; - setTitleTemplate(value); - form.setFieldValue('custom_properties.title_template', value); - }} - /> +