|
1 | 1 | @page "/admin/system/customisation" |
2 | 2 |
|
| 3 | +@using System.Text.Json |
3 | 4 | @using Microsoft.AspNetCore.Authorization |
4 | 5 | @using MoonCore.Blazor.FlyonUi.DataTables |
| 6 | +@using MoonCore.Blazor.FlyonUi.Helpers |
| 7 | +@using MoonCore.Helpers |
5 | 8 | @using MoonCore.Models |
| 9 | +@using Moonlight.Client.Models |
6 | 10 | @using Moonlight.Client.Services |
| 11 | +@using Moonlight.Shared.Http.Requests.Admin.Sys.Theme |
7 | 12 | @using Moonlight.Shared.Http.Responses.Admin |
8 | 13 |
|
9 | 14 | @attribute [Authorize(Policy = "permissions:admin.system.theme")] |
10 | 15 |
|
11 | 16 | @inject ThemeService ThemeService |
12 | 17 | @inject AlertService AlertService |
13 | 18 | @inject ToastService ToastService |
| 19 | +@inject DownloadService DownloadService |
| 20 | +@inject ILogger<Index> Logger |
14 | 21 |
|
15 | 22 | <NavTabs Index="1" Names="UiConstants.AdminNavNames" Links="UiConstants.AdminNavLinks"/> |
16 | 23 |
|
|
24 | 31 | <i class="icon-file-up"></i> |
25 | 32 | Import |
26 | 33 | </label> |
27 | | - <InputFile id="import-theme" class="hidden" /> |
| 34 | + <InputFile OnChange="Import" id="import-theme" class="hidden" multiple /> |
28 | 35 | <a href="/admin/system/customisation/themes/create" class="btn btn-primary">Create</a> |
29 | 36 | </div> |
30 | 37 | </div> |
31 | 38 |
|
32 | 39 | <div class="my-2.5"> |
33 | | - <DataTable TItem="ThemeResponse"> |
| 40 | + <DataTable @ref="Table" TItem="ThemeResponse"> |
34 | 41 | <Configuration> |
35 | 42 | <DataTableColumn TItem="ThemeResponse" Field="@(x => x.Id)" Name="Id"/> |
36 | 43 | <DataTableColumn TItem="ThemeResponse" Field="@(x => x.Name)" Name="Name"> |
|
66 | 73 | </a> |
67 | 74 | } |
68 | 75 |
|
| 76 | + <a @onclick="() => Export(context)" @onclick:preventDefault href="#" class="flex items-center mr-2 sm:mr-3"> |
| 77 | + <i class="text-success icon-download me-1"></i> |
| 78 | + <span class="text-success">Export</span> |
| 79 | + </a> |
| 80 | + |
69 | 81 | <a href="/admin/system/customisation/themes/@(context.Id)" class="mr-2 sm:mr-3"> |
70 | 82 | <i class="icon-pencil text-primary"></i> |
71 | 83 | </a> |
|
92 | 104 |
|
93 | 105 | private async Task<IPagedData<ThemeResponse>> LoadItems(PaginationOptions options) |
94 | 106 | => await ThemeService.Get(options.Page, options.PerPage); |
| 107 | + |
| 108 | + private async Task Import(InputFileChangeEventArgs eventArgs) |
| 109 | + { |
| 110 | + if(eventArgs.FileCount < 1) |
| 111 | + return; |
| 112 | + |
| 113 | + var files = eventArgs.GetMultipleFiles(); |
| 114 | + |
| 115 | + var maxFileSize = ByteConverter.FromMegaBytes(1).Bytes; |
| 116 | + |
| 117 | + foreach (var file in files) |
| 118 | + { |
| 119 | + try |
| 120 | + { |
| 121 | + if (!file.Name.EndsWith(".json")) |
| 122 | + { |
| 123 | + await ToastService.Error($"Unable to import {file.Name}", "Only .json files are supported"); |
| 124 | + continue; |
| 125 | + } |
| 126 | + |
| 127 | + if (file.Size > maxFileSize) |
| 128 | + { |
| 129 | + await ToastService.Error($"Unable to import {file.Name}", "Exceeded the maximum file limit of 1MB"); |
| 130 | + continue; |
| 131 | + } |
| 132 | + |
| 133 | + await using var stream = file.OpenReadStream(maxFileSize); |
| 134 | + var themeTransfer = await JsonSerializer.DeserializeAsync<ThemeTransferModel>(stream); |
| 135 | + |
| 136 | + stream.Close(); |
| 137 | + |
| 138 | + if (themeTransfer == null) |
| 139 | + { |
| 140 | + await ToastService.Error($"Unable to import {file.Name}", "Failed to deserialize the content"); |
| 141 | + continue; |
| 142 | + } |
| 143 | + |
| 144 | + var theme = await ThemeService.Create(new CreateThemeRequest() |
| 145 | + { |
| 146 | + Name = themeTransfer.Name, |
| 147 | + Author = themeTransfer.Author, |
| 148 | + Content = themeTransfer.Content, |
| 149 | + DonateUrl = themeTransfer.DonateUrl, |
| 150 | + UpdateUrl = themeTransfer.UpdateUrl, |
| 151 | + Version = themeTransfer.Version |
| 152 | + }); |
| 153 | + |
| 154 | + await ToastService.Success("Successfully imported theme", theme.Name); |
| 155 | + |
| 156 | + await Table.Refresh(); |
| 157 | + } |
| 158 | + catch (Exception e) |
| 159 | + { |
| 160 | + Logger.LogError(e, "An unhandled error occured while importing file {file} as theme", file.Name); |
| 161 | + } |
| 162 | + } |
| 163 | + } |
| 164 | + |
| 165 | + private async Task Export(ThemeResponse theme) |
| 166 | + { |
| 167 | + var transfer = new ThemeTransferModel() |
| 168 | + { |
| 169 | + Name = theme.Name, |
| 170 | + Author = theme.Author, |
| 171 | + Content = theme.Content, |
| 172 | + DonateUrl = theme.DonateUrl, |
| 173 | + UpdateUrl = theme.UpdateUrl, |
| 174 | + Version = theme.Version |
| 175 | + }; |
| 176 | + |
| 177 | + var json = JsonSerializer.Serialize(transfer, new JsonSerializerOptions() |
| 178 | + { |
| 179 | + WriteIndented = true |
| 180 | + }); |
| 181 | + |
| 182 | + var fileName = $"{transfer.Name.Replace(" ", string.Empty).Trim()}.json"; |
| 183 | + |
| 184 | + await DownloadService.Download(fileName, json); |
| 185 | + } |
95 | 186 |
|
96 | 187 | private async Task Delete(ThemeResponse response) |
97 | 188 | { |
|
0 commit comments