tagliatelle

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

admin.html (14053B)


      1 {{template "_header" .}}
      2 <h1>Admin</h1>
      3 
      4 {{if .Data.Error}}
      5 <div class="admin-alert admin-alert--error">
      6     <strong>Error:</strong> {{.Data.Error}}
      7 </div>
      8 {{end}}
      9 
     10 {{if .Data.Success}}
     11 <div class="admin-alert admin-alert--success">
     12     <strong>Success:</strong> {{.Data.Success}}
     13 </div>
     14 {{end}}
     15 
     16 <!-- Tab Navigation -->
     17 <div class="admin-tab-nav">
     18     <button onclick="showAdminTab('settings')" id="admin-tab-settings" class="admin-tab-btn admin-tab-btn--active">
     19         Settings
     20     </button>
     21     <button onclick="showAdminTab('database')" id="admin-tab-database" class="admin-tab-btn">
     22         Database
     23     </button>
     24     <button onclick="showAdminTab('aliases')" id="admin-tab-aliases" class="admin-tab-btn">
     25         Aliases
     26     </button>
     27     <button onclick="showAdminTab('sedrules')" id="admin-tab-sedrules" class="admin-tab-btn">
     28         Sed Rules
     29     </button>
     30     <button onclick="showAdminTab('orphans')" id="admin-tab-orphans" class="admin-tab-btn">
     31         Orphans
     32     </button>
     33     <button onclick="showAdminTab('thumbnails')" id="admin-tab-thumbnails" class="admin-tab-btn">
     34         Thumbnails
     35     </button>
     36 </div>
     37 
     38 <!-- Settings Tab -->
     39 <div id="admin-content-settings">
     40 	<div class="config-container">
     41     <div class="config-split">
     42     <h2>Settings</h2>
     43     <form method="post" class="admin-form">
     44         <input type="hidden" name="active_tab" value="settings">
     45 
     46         <div class="admin-form-group">
     47             <label for="gallery_size" class="admin-form-label">Gallery Size:</label>
     48             <input type="text" id="gallery_size" name="gallery_size" value="{{.Data.Config.GallerySize}}" required
     49                    placeholder="400px">
     50             <small class="admin-hint">Size of previews used in galleries</small>
     51         </div>
     52 
     53         <div class="admin-form-group">
     54             <label for="items_per_page" class="admin-form-label">Items per Page:</label>
     55             <input type="text" id="items_per_page" name="items_per_page" value="{{.Data.Config.ItemsPerPage}}" required
     56                    placeholder="100">
     57             <small class="admin-hint">Items per page in galleries</small>
     58         </div>
     59 
     60         <button type="submit" class="admin-btn admin-btn--primary">
     61             Save Settings
     62         </button>
     63     </form>
     64 	</div>
     65 
     66     <div class="config-split">
     67         <h3>Current Configuration:</h3>
     68         <ul>
     69             <li><strong>Database:</strong> {{.Data.Config.DatabasePath}}</li>
     70             <li><strong>Upload Directory:</strong> {{.Data.Config.UploadDir}}</li>
     71             <li><strong>Server Port:</strong> {{.Data.Config.ServerPort}}</li>
     72             <li><strong>Gallery Size:</strong> {{.Data.Config.GallerySize}}</li>
     73             <li><strong>Items per Page:</strong> {{.Data.Config.ItemsPerPage}}</li>
     74         </ul>
     75 
     76         <h4>Configuration:</h4>
     77         <p>Working directory is specified via the <code>-d</code> flag on launch.</p>
     78         <p>Webserver port is specified via the <code>-p</code> flag on launch.</p>
     79     </div>
     80     </div>
     81 </div>
     82 
     83 <!-- Database Tab -->
     84 <div id="admin-content-database" class="admin-tab-content">
     85     <h2>Database Maintenance</h2>
     86 
     87     <form method="post" class="admin-form-inline">
     88         <input type="hidden" name="active_tab" value="database">
     89         <input type="hidden" name="action" value="backup">
     90         <button type="submit" class="admin-btn admin-btn--success">
     91             Backup Database
     92         </button>
     93         <small class="admin-hint admin-hint--inline">Creates a timestamped backup of the database file</small>
     94     </form>
     95 
     96     <form method="post">
     97         <input type="hidden" name="active_tab" value="database">
     98         <input type="hidden" name="action" value="vacuum">
     99         <button type="submit" class="admin-btn admin-btn--purple">
    100             Vacuum Database
    101         </button>
    102         <small class="admin-hint admin-hint--inline">Reclaims unused space and optimizes database performance</small>
    103     </form>
    104 
    105     <hr class="admin-divider">
    106     <h3>File Properties</h3>
    107     <p class="admin-hint">
    108         Compute auto-detected properties (filetype, duration, orientation, resolution) for any files that do not yet have them.
    109     </p>
    110     <form method="post">
    111         <input type="hidden" name="active_tab" value="database">
    112         <input type="hidden" name="action" value="compute_properties">
    113         <button type="submit" class="admin-btn admin-btn--teal">
    114             Compute Missing Properties
    115         </button>
    116         <small class="admin-hint admin-hint--inline">Processes only files with no existing properties</small>
    117     </form>
    118 </div>
    119 
    120 <!-- Aliases Tab -->
    121 <div id="admin-content-aliases" class="admin-tab-content">
    122     <h2>Tag Aliases</h2>
    123     <p>
    124         Define tag aliases so that multiple tag values are treated as equivalent when searching or filtering.
    125         For example, if you alias "colour/blue" with "colour/navy", searching for either will show files tagged with both.
    126     </p>
    127 
    128     <div id="aliases-section" class="admin-section">
    129         <div id="alias-groups"></div>
    130 
    131         <button onclick="addAliasGroup()" class="admin-btn admin-btn--success admin-btn--sm admin-btn--top">
    132             + Add Alias Group
    133         </button>
    134 
    135         <form method="post" id="aliases-form" class="admin-form-top">
    136             <input type="hidden" name="active_tab" value="aliases">
    137             <input type="hidden" name="action" value="save_aliases">
    138             <input type="hidden" name="aliases_json" id="aliases_json">
    139             <button type="submit" class="admin-btn admin-btn--primary">
    140                 Save Aliases
    141             </button>
    142         </form>
    143     </div>
    144 </div>
    145 
    146 <!-- Sed Rules Tab -->
    147 <div id="admin-content-sedrules" class="admin-tab-content">
    148 	<div class="config-container">
    149     <div class="config-split">
    150     <h2>Sed Rules for Notes</h2>
    151     <p>
    152         Define sed rules that can be applied to notes in the Notes editor.
    153         These rules will appear as buttons in the notes interface for quick text transformations.
    154     </p>
    155 
    156     <div id="sedrules-section" class="admin-section">
    157         <div id="sed-rules"></div>
    158 
    159         <button onclick="addSedRule()" class="admin-btn admin-btn--success admin-btn--sm admin-btn--top">
    160             + Add Sed Rule
    161         </button>
    162 
    163         <form method="post" action="/admin" id="sedrules-form" class="admin-form-top">
    164             <input type="hidden" name="active_tab" value="sedrules">
    165             <input type="hidden" name="action" value="save_sed_rules">
    166             <input type="hidden" name="sed_rules_json" id="sed_rules_json">
    167             <button type="submit" class="admin-btn admin-btn--primary">
    168                 Save Sed Rules
    169             </button>
    170         </form>
    171     </div>
    172     </div>
    173 
    174     <div class="config-split">
    175         <h4 class="admin-example-heading">Example Sed Commands:</h4>
    176         <ul class="admin-example-list">
    177             <li><code>s?[?&]brandIds=[0-9]\+&productId=[0-9]\+??g</code> - Remove URL parameters</li>
    178             <li><code>s/[[:space:]]*$//</code> - Remove trailing whitespace</li>
    179             <li><code>s/  \+/ /g</code> - Replace multiple spaces with single space</li>
    180             <li><code>s/https\?:\/\/[^ ]*//g</code> - Remove URLs</li>
    181             <li><code>/^$/d</code> - Delete empty lines</li>
    182         </ul>
    183     </div>
    184     </div>
    185 </div>
    186 
    187 <!-- Orphans Tab -->
    188 <div id="admin-content-orphans" class="admin-tab-content">
    189     <h2>Orphaned Files</h2>
    190 
    191     <!-- Files on disk, not in DB -->
    192     <h3 class="admin-orphan-heading">Disk Orphans</h3>
    193     <p class="admin-hint admin-hint--spaced">
    194         These files exist in the upload directory but are not tracked in the database.
    195     </p>
    196     {{if .Data.OrphanData.Orphans}}
    197     <ul class="admin-orphan-list">
    198       {{range .Data.OrphanData.Orphans}}
    199         <li class="admin-orphan-item">{{.}}</li>
    200       {{end}}
    201     </ul>
    202     {{else}}
    203     <div class="admin-alert admin-alert--success">
    204         <strong>✓ No disk orphans found!</strong>
    205     </div>
    206     {{end}}
    207 
    208     <!-- Files in DB, not on disk -->
    209     <h3 class="admin-orphan-heading admin-orphan-heading--db">Database Orphans</h3>
    210     <p class="admin-hint admin-hint--spaced">
    211         These files are tracked in the database but are missing from the upload directory.
    212     </p>
    213     {{if .Data.OrphanData.ReverseOrphans}}
    214     <ul class="admin-orphan-list">
    215       {{range .Data.OrphanData.ReverseOrphans}}
    216         <li class="admin-orphan-item">{{.}}</li>
    217       {{end}}
    218     </ul>
    219     {{else}}
    220     <div class="admin-alert admin-alert--success">
    221         <strong>✓ No database orphans found!</strong>
    222     </div>
    223     {{end}}
    224 </div>
    225 
    226 <!-- Thumbnails Tab -->
    227 <div id="admin-content-thumbnails" class="admin-tab-content">
    228     <h2>Thumbnail Management</h2>
    229 
    230     <!-- Sub-tab Navigation -->
    231     <div class="admin-subtab-nav">
    232         <button onclick="showThumbnailSubTab('missing')" id="thumb-subtab-missing" class="thumb-subtab-btn thumb-subtab-btn--active">
    233             Missing ({{len .Data.MissingThumbnails}})
    234         </button>
    235         <button onclick="showThumbnailSubTab('regenerate')" id="thumb-subtab-regenerate" class="thumb-subtab-btn">
    236             Regenerate
    237         </button>
    238     </div>
    239 
    240     <!-- Missing Thumbnails Sub-tab -->
    241     <div id="thumb-content-missing">
    242         <h3>Missing Thumbnails ({{len .Data.MissingThumbnails}})</h3>
    243 
    244         {{if .Data.MissingThumbnails}}
    245             <form method="post" action="/thumbnails/generate" class="admin-form-inline">
    246                 <input type="hidden" name="action" value="generate_all">
    247                 <button type="submit" onclick="return confirm('Generate thumbnails for all {{len .Data.MissingThumbnails}} videos? This may take a while.');" class="admin-btn admin-btn--success">
    248                     Generate All Missing Thumbnails
    249                 </button>
    250                 <small class="admin-hint admin-hint--inline">Uses timestamp 00:00:05 for all videos</small>
    251             </form>
    252 
    253             <div class="admin-thumb-grid">
    254                 {{range .Data.MissingThumbnails}}
    255                 <div class="admin-thumb-card">
    256                     <h4 class="admin-thumb-card__title">
    257                         <a href="/file/{{.ID}}" target="_blank">{{.Filename}}</a>
    258                     </h4>
    259                     <p class="admin-thumb-card__id">ID: {{.ID}}</p>
    260 
    261                     <video class="admin-thumb-card__video" title="Click to capture frame">
    262                         <source src="/uploads/{{.EscapedFilename}}">
    263                     </video>
    264 
    265                     <form method="post" action="/thumbnails/generate" class="admin-thumb-card__form">
    266                         <input type="hidden" name="action" value="generate_single">
    267                         <input type="hidden" name="file_id" value="{{.ID}}">
    268                         <input type="hidden" name="redirect" value="admin">
    269 
    270                         <div class="admin-thumb-card__timestamp-row">
    271                             <label class="admin-thumb-card__timestamp-label">Timestamp:</label>
    272                             <input type="text" name="timestamp" value="00:00:05" placeholder="00:00:05"
    273                                    class="admin-thumb-card__timestamp-input">
    274                         </div>
    275 
    276                         <button type="submit" class="admin-btn admin-btn--primary admin-btn--full">
    277                             Generate Thumbnail
    278                         </button>
    279                     </form>
    280                 </div>
    281                 {{end}}
    282             </div>
    283         {{else}}
    284             <div class="admin-alert admin-alert--success">
    285                 <strong>✓ All videos have thumbnails!</strong>
    286             </div>
    287         {{end}}
    288     </div>
    289 
    290     <!-- Regenerate Sub-tab -->
    291     <div id="thumb-content-regenerate" class="admin-tab-content">
    292         <h3>Regenerate Thumbnail</h3>
    293 
    294         <div class="admin-regen-layout">
    295 
    296             <div class="admin-regen-form-col">
    297                 <div class="admin-tip-box">
    298                     <strong>Tip:</strong> Enter a file ID to regenerate its thumbnail with a custom timestamp. You can find file IDs in the URL when viewing a file (e.g., /file/312).
    299                 </div>
    300 
    301                 <form method="post" action="/thumbnails/generate" class="admin-regen-form">
    302                     <input type="hidden" name="action" value="generate_single">
    303                     <input type="hidden" name="redirect" value="admin">
    304 
    305                     <div class="admin-form-group">
    306                         <label for="file_id" class="admin-form-label">File ID:</label>
    307                         <input type="text" id="file_id" name="file_id" required
    308                                class="admin-mono-input"
    309                                placeholder="e.g., 312">
    310                         <small class="admin-hint">Enter the ID of the video file</small>
    311                     </div>
    312 
    313                     <div class="admin-form-group">
    314                         <label for="timestamp" class="admin-form-label">Timestamp:</label>
    315                         <input type="text" id="timestamp" name="timestamp" value="00:00:05" required
    316                                class="admin-mono-input"
    317                                placeholder="00:00:05">
    318                         <small class="admin-hint">Format: HH:MM:SS (e.g., 00:00:05 for 5 seconds)</small>
    319                     </div>
    320 
    321                     <button type="submit" class="admin-btn admin-btn--primary admin-btn--full">
    322                         Generate/Regenerate Thumbnail
    323                     </button>
    324                 </form>
    325             </div>
    326 
    327             {{template "_recent" .}}
    328 
    329         </div>
    330     </div>
    331 </div>
    332 
    333 <script>window.initialAliasGroups = {{.Data.Config.TagAliases}};</script>
    334 <script>window.initialSedRules = {{.Data.Config.SedRules}};</script>
    335 <script>window.activeAdminTab = "{{.Data.ActiveTab}}";</script>
    336 <script src="/static/tag-alias.js" defer></script>
    337 <script src="/static/sed-rules.js" defer></script>
    338 <script src="/static/admin-tabs.js"></script>
    339 <script src="/static/common.js" defer></script>
    340 <script src="/static/hover-preview.js" defer></script>
    341 
    342 {{template "_footer"}}