tagliatelle

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

admin.html (13676B)


      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">
    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 
    190     <h2>Orphaned Files</h2>
    191 
    192 	<div class="config-container">
    193     <div class="config-split">
    194     <h3 class="admin-orphan-heading">Untracked Files</h3>
    195     {{if .Data.OrphanData.Orphans}}
    196     <ul class="admin-orphan-list">
    197     {{range .Data.OrphanData.Orphans}}<li class="admin-orphan-item">{{.Filename}}</li>
    198     {{end}}
    199     </ul>
    200     {{else}}<strong>✓ No untracked files found!</strong>
    201     {{end}}
    202 
    203     </div>
    204     <div class="config-split">
    205 
    206     <h3 class="admin-orphan-heading">Missing Files</h3>
    207     {{if .Data.OrphanData.ReverseOrphans}}
    208     <ul class="admin-orphan-list">
    209     {{range .Data.OrphanData.ReverseOrphans}}<li class="admin-orphan-item"><a href="/file/{{.ID}}" target="_blank">{{.Filename}}</a></li>
    210     {{end}}
    211     </ul>
    212     {{else}}<strong>✓ No missing files found!</strong>
    213     {{end}}
    214 
    215     </div>
    216     </div>
    217 </div>
    218 
    219 <!-- Thumbnails Tab -->
    220 <div id="admin-content-thumbnails" class="admin-tab-content">
    221     <h2>Thumbnail Management</h2>
    222 
    223     <!-- Sub-tab Navigation -->
    224     <div class="admin-subtab-nav">
    225         <button onclick="showThumbnailSubTab('missing')" id="thumb-subtab-missing" class="thumb-subtab-btn thumb-subtab-btn--active">
    226             Missing ({{len .Data.MissingThumbnails}})
    227         </button>
    228         <button onclick="showThumbnailSubTab('regenerate')" id="thumb-subtab-regenerate" class="thumb-subtab-btn">
    229             Regenerate
    230         </button>
    231     </div>
    232 
    233     <!-- Missing Thumbnails Sub-tab -->
    234     <div id="thumb-content-missing">
    235         <h3>Missing Thumbnails ({{len .Data.MissingThumbnails}})</h3>
    236 
    237         {{if .Data.MissingThumbnails}}
    238             <form method="post" action="/thumbnails/generate" class="admin-form-inline">
    239                 <input type="hidden" name="action" value="generate_all">
    240                 <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">
    241                     Generate All Missing Thumbnails
    242                 </button>
    243                 <small class="admin-hint admin-hint--inline">Uses timestamp 00:00:05 for all videos</small>
    244             </form>
    245 
    246             <div class="admin-thumb-grid">
    247                 {{range .Data.MissingThumbnails}}
    248                 <div class="admin-thumb-card">
    249                     <h4 class="admin-thumb-card__title">
    250                         <a href="/file/{{.ID}}" target="_blank">{{.Filename}}</a>
    251                     </h4>
    252                     <p class="admin-thumb-card__id">ID: {{.ID}}</p>
    253 
    254                     <video class="admin-thumb-card__video" title="Click to capture frame">
    255                         <source src="/uploads/{{.EscapedFilename}}">
    256                     </video>
    257 
    258                     <form method="post" action="/thumbnails/generate" class="admin-thumb-card__form">
    259                         <input type="hidden" name="action" value="generate_single">
    260                         <input type="hidden" name="file_id" value="{{.ID}}">
    261                         <input type="hidden" name="redirect" value="admin">
    262 
    263                         <div class="admin-thumb-card__timestamp-row">
    264                             <label class="admin-thumb-card__timestamp-label">Timestamp:</label>
    265                             <input type="text" name="timestamp" value="00:00:05" placeholder="00:00:05"
    266                                    class="admin-thumb-card__timestamp-input">
    267                         </div>
    268 
    269                         <button type="submit" class="admin-btn admin-btn--primary admin-btn--full">
    270                             Generate Thumbnail
    271                         </button>
    272                     </form>
    273                 </div>
    274                 {{end}}
    275             </div>
    276         {{else}}
    277             <div class="admin-alert admin-alert--success">
    278                 <strong>✓ All videos have thumbnails!</strong>
    279             </div>
    280         {{end}}
    281     </div>
    282 
    283     <!-- Regenerate Sub-tab -->
    284     <div id="thumb-content-regenerate" class="admin-tab-content">
    285         <h3>Regenerate Thumbnail</h3>
    286 
    287         <div class="admin-regen-layout">
    288 
    289             <div class="admin-regen-form-col">
    290                 <div class="admin-tip-box">
    291                     <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).
    292                 </div>
    293 
    294                 <form method="post" action="/thumbnails/generate" class="admin-regen-form">
    295                     <input type="hidden" name="action" value="generate_single">
    296                     <input type="hidden" name="redirect" value="admin">
    297 
    298                     <div class="admin-form-group">
    299                         <label for="file_id" class="admin-form-label">File ID:</label>
    300                         <input type="text" id="file_id" name="file_id" required
    301                                class="admin-mono-input"
    302                                placeholder="e.g., 312">
    303                         <small class="admin-hint">Enter the ID of the video file</small>
    304                     </div>
    305 
    306                     <div class="admin-form-group">
    307                         <label for="timestamp" class="admin-form-label">Timestamp:</label>
    308                         <input type="text" id="timestamp" name="timestamp" value="00:00:05" required
    309                                class="admin-mono-input"
    310                                placeholder="00:00:05">
    311                         <small class="admin-hint">Format: HH:MM:SS (e.g., 00:00:05 for 5 seconds)</small>
    312                     </div>
    313 
    314                     <button type="submit" class="admin-btn admin-btn--primary admin-btn--full">
    315                         Generate/Regenerate Thumbnail
    316                     </button>
    317                 </form>
    318             </div>
    319 
    320             {{template "_recent" .}}
    321 
    322         </div>
    323     </div>
    324 </div>
    325 
    326 <script>window.initialAliasGroups = {{.Data.Config.TagAliases}};</script>
    327 <script>window.initialSedRules = {{.Data.Config.SedRules}};</script>
    328 <script>window.activeAdminTab = "{{.Data.ActiveTab}}";</script>
    329 <script src="/static/admin-tag-alias.js" defer></script>
    330 <script src="/static/admin-sed-rules.js" defer></script>
    331 <script src="/static/admin-tabs.js"></script>
    332 <script src="/static/common.js" defer></script>
    333 <script src="/static/hover-preview.js" defer></script>
    334 
    335 {{template "_footer"}}