Browse Source

Converted large views into multiple partial views to leverage parts in other sections.

tags/2.0.6
Teknikode 3 years ago
parent
commit
009adccd2f

+ 23
- 3
Teknik/Areas/Vault/Controllers/VaultController.cs View File

@@ -47,6 +47,11 @@ namespace Teknik.Areas.Vault.Controllers
{
foreach (VaultItem item in foundVault.Items)
{
VaultItemViewModel itemModel = new VaultItemViewModel();
itemModel.Title = item.Title;
itemModel.Description = item.Description;
itemModel.DateAdded = item.DateAdded;

if (item.GetType().BaseType == typeof(UploadItem))
{
UploadItem upload = (UploadItem)item;
@@ -54,6 +59,13 @@ namespace Teknik.Areas.Vault.Controllers
upload.Upload.Downloads += 1;
db.Entry(upload.Upload).State = EntityState.Modified;
db.SaveChanges();

UploadItemViewModel uploadModel = new UploadItemViewModel();
uploadModel.Title = item.Title;
uploadModel.Description = item.Description;
uploadModel.DateAdded = item.DateAdded;
uploadModel.Upload = upload.Upload;
model.Items.Add(uploadModel);
}
else if (item.GetType().BaseType == typeof(PasteItem))
{
@@ -70,12 +82,16 @@ namespace Teknik.Areas.Vault.Controllers
db.SaveChanges();
break;
}
}

model.Items.Add(item);
PasteItemViewModel pasteModel = new PasteItemViewModel();
pasteModel.Title = item.Title;
pasteModel.Description = item.Description;
pasteModel.DateAdded = item.DateAdded;
pasteModel.Paste = paste.Paste;
model.Items.Add(pasteModel);
}
}
}
model.Items = foundVault.Items.ToList();

return View(model);
}
@@ -99,6 +115,7 @@ namespace Teknik.Areas.Vault.Controllers
NewVaultViewModel model = new NewVaultViewModel();

string[] allURLs = urls.Split(',');
int index = 0;
foreach (string url in allURLs)
{
string[] urlInfo = url.Split(':');
@@ -112,10 +129,13 @@ namespace Teknik.Areas.Vault.Controllers
if (IsValidItem(type, uploadId))
{
NewVaultItemViewModel item = new NewVaultItemViewModel();
item.isTemplate = false;
item.index = index;
item.title = title;
item.url = uploadId;
item.type = type;
model.items.Add(item);
index++;
}
}


+ 4
- 0
Teknik/Areas/Vault/ViewModels/NewVaultItemViewModel.cs View File

@@ -8,6 +8,8 @@ namespace Teknik.Areas.Vault.ViewModels
{
public class NewVaultItemViewModel : ViewModelBase
{
public bool isTemplate { get; set; }
public int index { get; set; }
public string title { get; set; }
public string description { get; set; }
public string type { get; set; }
@@ -15,6 +17,8 @@ namespace Teknik.Areas.Vault.ViewModels

public NewVaultItemViewModel()
{
isTemplate = true;
index = 0;
title = string.Empty;
description = string.Empty;
type = "Upload";

+ 13
- 0
Teknik/Areas/Vault/ViewModels/PasteItemViewModel.cs View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Teknik.ViewModels;

namespace Teknik.Areas.Vault.ViewModels
{
public class PasteItemViewModel : VaultItemViewModel
{
public Paste.Models.Paste Paste { get; set; }
}
}

+ 13
- 0
Teknik/Areas/Vault/ViewModels/UploadItemViewModel.cs View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Teknik.ViewModels;

namespace Teknik.Areas.Vault.ViewModels
{
public class UploadItemViewModel : VaultItemViewModel
{
public Upload.Models.Upload Upload { get; set; }
}
}

+ 16
- 0
Teknik/Areas/Vault/ViewModels/VaultItemViewModel.cs View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Teknik.ViewModels;

namespace Teknik.Areas.Vault.ViewModels
{
public class VaultItemViewModel : ViewModelBase
{
public int VaultItemId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime DateAdded { get; set; }
}
}

+ 2
- 2
Teknik/Areas/Vault/ViewModels/VaultViewModel.cs View File

@@ -16,7 +16,7 @@ namespace Teknik.Areas.Vault.ViewModels
public string Description { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateEdited { get; set; }
public List<VaultItem> Items { get; set; }
public List<VaultItemViewModel> Items { get; set; }

public VaultViewModel()
{
@@ -24,7 +24,7 @@ namespace Teknik.Areas.Vault.ViewModels
Description = string.Empty;
DateCreated = DateTime.Now;
DateEdited = DateTime.Now;
Items = new List<VaultItem>();
Items = new List<VaultItemViewModel>();
}
}
}

+ 4
- 108
Teknik/Areas/Vault/Views/Vault/NewVault.cshtml View File

@@ -10,7 +10,7 @@
var validateItemURL = '@Url.SubRouteUrl("vault", "Vault.Action", new { action = "ValidateItem" })';
var createVaultURL = '@Url.SubRouteUrl("vault", "Vault.Action", new { action = "CreateVault" })';

var itemCount = 0;
var itemCount = @Model.items.Count();

</script>

@@ -156,121 +156,17 @@
<div class="col-sm-10" id="vault-items">
@if (Model.items.Any())
{
int index = 0;
foreach (NewVaultItemViewModel item in Model.items)
{
<div class="row vault-item" id="vault-item-@index">
<div class="col-sm-9 col-sm-offset-1">
<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-sm-8 text-left">
<h4><b id="item-title">@item.title</b></h4>
</div>
<div class="col-sm-4">
<div class="btn-group pull-right" role="group">
<button type="button" class="btn btn-default" id="@index" data-toggle="modal" data-target="#editItem">Edit</button>
<button type="button" class="btn btn-danger" id="remove-item">Remove</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<dl class="dl-horizontal pull-left">
<dt>Type</dt>
<dd id="item-type">@item.type</dd>
<dt>Url</dt>
<dd id="item-url">@item.url</dd>
</dl>
</div>
<div class="panel-footer">
<p id="item-description">@item.description</p>
</div>
</div>
</div>
<div class="col-sm-1">
<div class="row">
<div class="col-sm-12">
<button type="button" class="btn btn-default" id="move-up"><i class="fa fa-chevron-up"></i></button>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-12">
<button type="button" class="btn btn-default" id="move-down"><i class="fa fa-chevron-down"></i></button>
</div>
</div>
</div>
<script type="text/javascript">
itemCount++;
$(document).ready(function () {
var itemDiv = $('#vault-item-@index');

linkRemove(itemDiv);
linkMoveUp(itemDiv);
linkMoveDown(itemDiv);

@if (string.IsNullOrEmpty(item.description))
{
@:itemDiv.find('.panel-footer').hide();
}
});
</script>
</div>
{
index++;
}
@Html.Partial("~/Areas/Vault/Views/Vault/NewVaultItem.cshtml", item)
}
}
</div>
</div>
</form>
</div>

<div id="templates" style="display: none">
<div class="row" id="item-template">
<div class="col-sm-9 col-sm-offset-1">
<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-sm-8 text-left">
<h4><b id="item-title"></b></h4>
</div>
<div class="col-sm-4">
<div class="btn-group pull-right" role="group">
<button type="button" class="btn btn-default" id="edit-item" data-toggle="modal" data-target="#editItem">Edit</button>
<button type="button" class="btn btn-danger" id="remove-item">Remove</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<dl class="dl-horizontal">
<dt>Type</dt>
<dd id="item-type"></dd>
<dt>Url</dt>
<dd id="item-url"></dd>
</dl>
</div>
<div class="panel-footer">
<p id="item-description"></p>
</div>
</div>
</div>
<div class="col-sm-1">
<div class="row">
<div class="col-sm-12">
<button type="button" class="btn btn-default" id="move-up"><i class="fa fa-chevron-up"></i></button>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-12">
<button type="button" class="btn btn-default" id="move-down"><i class="fa fa-chevron-down"></i></button>
</div>
</div>
</div>
</div>
@Html.Partial("~/Areas/Vault/Views/Vault/NewVaultItem.cshtml", new NewVaultItemViewModel())
</div>

@Scripts.Render("~/bundles/vault")
@Scripts.Render("~/bundles/vault")

+ 65
- 0
Teknik/Areas/Vault/Views/Vault/NewVaultItem.cshtml View File

@@ -0,0 +1,65 @@
@model Teknik.Areas.Vault.ViewModels.NewVaultItemViewModel
@{
bool isTemplate = (Model.isTemplate);
}

<div class="row @(isTemplate ? string.Empty : "vault-item")" id="@(isTemplate ? "item-template" : "vault-item-" + Model.index)">
<div class="col-sm-9 col-sm-offset-1">
<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-sm-8 text-left">
<h4><b id="item-title">@(isTemplate ? string.Empty : Model.title)</b></h4>
</div>
<div class="col-sm-4">
<div class="btn-group pull-right" role="group">
<button type="button" class="btn btn-default" id="@(isTemplate ? "edit-item" : Model.index.ToString())" data-toggle="modal" data-target="#editItem">Edit</button>
<button type="button" class="btn btn-danger" id="remove-item">Remove</button>
</div>
</div>
</div>
</div>
<div class="panel-body">
<dl class="dl-horizontal">
<dt>Type</dt>
<dd id="item-type">@(isTemplate ? string.Empty : Model.type)</dd>
<dt>Url</dt>
<dd id="item-url">@(isTemplate ? string.Empty : Model.url)</dd>
</dl>
</div>
<div class="panel-footer">
<p id="item-description">@(isTemplate ? string.Empty : Model.description)</p>
</div>
</div>
</div>
<div class="col-sm-1">
<div class="row">
<div class="col-sm-12">
<button type="button" class="btn btn-default" id="move-up"><i class="fa fa-chevron-up"></i></button>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-12">
<button type="button" class="btn btn-default" id="move-down"><i class="fa fa-chevron-down"></i></button>
</div>
</div>
</div>
@if (!isTemplate)
{
<script type="text/javascript">
$(document).ready(function () {
var itemDiv = $('#vault-item-@Model.index');

linkRemove(itemDiv);
linkMoveUp(itemDiv);
linkMoveDown(itemDiv);

@if (string.IsNullOrEmpty(Model.description))
{
@:itemDiv.find('.panel-footer').hide();
}
});
</script>
}
</div>

+ 61
- 0
Teknik/Areas/Vault/Views/Vault/PasteItem.cshtml View File

@@ -0,0 +1,61 @@
@model Teknik.Areas.Vault.ViewModels.PasteItemViewModel

@using Teknik.Utilities
@using Teknik.Pygments

@{
// Transform content into HTML
if (!Highlighter.Lexers.ToList().Exists(l => l.Aliases.Contains(Model.Paste.Syntax)))
{
Model.Paste.Syntax = "text";
}
Highlighter highlighter = new Highlighter();
// Add a space in front of the content due to bug with pygment (No idea why yet)
Model.Paste.Content = highlighter.HighlightToHtml(" " + Model.Paste.Content, Model.Paste.Syntax, Model.Config.PasteConfig.SyntaxVisualStyle, generateInlineStyles: true, fragment: true);
}

<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-sm-10 text-left">
<h4><b>@((string.IsNullOrEmpty(Model.Title)) ? "Paste" : Model.Title)</b> <small>Pasted on <time datetime="@Model.Paste.DatePosted.ToString("s")">@Model.Paste.DatePosted.ToString("dddd, MMMM d, yyyy") at @Model.Paste.DatePosted.ToString("h:mm:ss tt")</time> - Format: <b id="syntaxLanguage">@Model.Paste.Syntax</b></small></h4>
</div>
<div class="col-sm-2 text-right">
<h4><small><a href="@Url.SubRouteUrl("p", "Paste.View", new { url = Model.Paste.Url })" target="_blank">Direct Link</a></small></h4>
</div>
</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-12 pull-left">
<div class="btn-group" role="group">
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Simple", new { url = Model.Paste.Url })" target="_blank">Simple</a>
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Raw", new { url = Model.Paste.Url })" target="_blank">Raw</a>
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Download", new { url = Model.Paste.Url })">Download</a>
</div>
</div>
</div>
<br />
<div class="row paste-item">
<div class="col-sm-12 paste-content hideContent">
@if (!string.IsNullOrEmpty(Model.Paste.HashedPassword))
{
<p class="text-center">Password Required</p>
}
else
{
@Html.Raw(Model.Paste.Content)
}
</div>
<div class="show-more">
<button class="btn btn-default btn-sm" id="show-more-button">Show More</button>
</div>
</div>
</div>
@if (!string.IsNullOrEmpty(Model.Description))
{
<div class="panel-footer">
<p>@Model.Description</p>
</div>
}
</div>

+ 68
- 0
Teknik/Areas/Vault/Views/Vault/UploadItem.cshtml View File

@@ -0,0 +1,68 @@
@model Teknik.Areas.Vault.ViewModels.UploadItemViewModel

@using Teknik.Utilities
@{
bool needsKey = (string.IsNullOrEmpty(Model.Upload.Key) && !string.IsNullOrEmpty(Model.Upload.IV));
}

<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-sm-10 text-left">
<h4><b>@((string.IsNullOrEmpty(Model.Title)) ? "Upload" : Model.Title)</b> <small>Uploaded on <time datetime="@Model.Upload.DateUploaded.ToString("s")">@Model.Upload.DateUploaded.ToString("dddd, MMMM d, yyyy") at @Model.Upload.DateUploaded.ToString("h:mm:ss tt")</time></small></h4>
</div>
<div class="col-sm-2 text-right">
<h4><small><a href="@Url.SubRouteUrl("u", "Upload.Download", new { file = Model.Upload.Url })" target="_blank">Direct Link</a></small></h4>
</div>
</div>
</div>
<div class="panel-body">
@if (Model.Upload.ContentType.StartsWith("image") && !needsKey)
{
<a href="@Url.SubRouteUrl("u", "Upload.Download", new { file = Model.Upload.Url })" target="_blank">
<img src="@Url.SubRouteUrl("u", "Upload.Download", new { file = Model.Upload.Url })" class="img-thumbnail center-block" />
</a>
}
else if (Model.Upload.ContentType.StartsWith("audio") && !needsKey)
{
<div class="text-center">
<audio preload="none" controls>
<source src="@Url.SubRouteUrl("u", "Upload.Download", new { file = Model.Upload.Url })" type="@Model.Upload.ContentType" />
</audio>
</div>
}
else if (Model.Upload.ContentType.StartsWith("video") && !needsKey)
{
<div class="text-center">
<video preload="none" controls>
<source src="@Url.SubRouteUrl("u", "Upload.Download", new { file = Model.Upload.Url })" type="@Model.Upload.ContentType" />
</video>
</div>
}
else
{
<div class="row">
<div class="col-sm-4 text-center">
<label for="size">Size</label>
<p id="size">@StringHelper.GetBytesReadable(Model.Upload.ContentLength)</p>
</div>
<div class="col-sm-4 text-center">
<label for="type">Type</label>
<p id="type">@Model.Upload.ContentType</p>
</div>
<div class="col-sm-4 text-center">
<label for="dateUploaded">Date Uploaded</label>
<p id="dateUploaded"><time datetime="@Model.Upload.DateUploaded.ToString("s")">@Model.Upload.DateUploaded.ToString("MMMM dd, yyyy")</time></p>
</div>
</div>
}
</div>
@if (!string.IsNullOrEmpty(Model.Description))
{
<div class="panel-footer">
<p>@Model.Description</p>
</div>
}
</div>


+ 8
- 121
Teknik/Areas/Vault/Views/Vault/ViewVault.cshtml View File

@@ -1,6 +1,6 @@
@model Teknik.Areas.Vault.ViewModels.VaultViewModel

@using Teknik.Areas.Vault.Models;
@using Teknik.Areas.Vault.ViewModels
@using Teknik.Utilities
@using Teknik.Pygments

@@ -23,133 +23,20 @@
}
<br />

@foreach (VaultItem item in Model.Items)
@foreach (VaultItemViewModel item in Model.Items)
{
Type itemType = item.GetType();
if (itemType.BaseType == typeof(PasteItem))
if (itemType == typeof(PasteItemViewModel))
{
PasteItem paste = (PasteItem)item;
PasteItemViewModel pasteModel = (PasteItemViewModel)item;

// Transform content into HTML
if (!Highlighter.Lexers.ToList().Exists(l => l.Aliases.Contains(paste.Paste.Syntax)))
{
paste.Paste.Syntax = "text";
}
Highlighter highlighter = new Highlighter();
// Add a space in front of the content due to bug with pygment (No idea why yet)
paste.Paste.Content = highlighter.HighlightToHtml(" " + paste.Paste.Content, paste.Paste.Syntax, Model.Config.PasteConfig.SyntaxVisualStyle, generateInlineStyles: true, fragment: true);

<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-sm-10 text-left">
<h4><b>@((string.IsNullOrEmpty(paste.Title)) ? "Paste" : paste.Title)</b> <small>Pasted on <time datetime="@paste.Paste.DatePosted.ToString("s")">@paste.Paste.DatePosted.ToString("dddd, MMMM d, yyyy") at @paste.Paste.DatePosted.ToString("h:mm:ss tt")</time> - Format: <b id="syntaxLanguage">@paste.Paste.Syntax</b></small></h4>
</div>
<div class="col-sm-2 text-right">
<h4><small><a href="@Url.SubRouteUrl("p", "Paste.View", new { url = paste.Paste.Url })" target="_blank">Direct Link</a></small></h4>
</div>
</div>
</div>
<div class="panel-body">
<div class="row">
<div class="col-sm-12 pull-left">
<div class="btn-group" role="group">
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Simple", new { url = paste.Paste.Url })" target="_blank">Simple</a>
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Raw", new { url = paste.Paste.Url })" target="_blank">Raw</a>
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Download", new { url = paste.Paste.Url })">Download</a>
</div>
</div>
</div>
<br />
<div class="row paste-item">
<div class="col-sm-12 paste-content hideContent">
@if (!string.IsNullOrEmpty(paste.Paste.HashedPassword))
{
<p class="text-center">Password Required</p>
}
else
{
@Html.Raw(paste.Paste.Content)
}
</div>
<div class="show-more">
<button class="btn btn-default btn-sm" id="show-more-button">Show More</button>
</div>
</div>
</div>
@if (!string.IsNullOrEmpty(paste.Description))
{
<div class="panel-footer">
<p>@paste.Description</p>
</div>
}
</div>
@Html.Partial("~/Areas/Vault/Views/Vault/PasteItem.cshtml", pasteModel)
}
else if (itemType.BaseType == typeof(UploadItem))
else if (itemType == typeof(UploadItemViewModel))
{
UploadItem upload = (UploadItem)item;
UploadItemViewModel uploadModel = (UploadItemViewModel)item;

bool needsKey = (string.IsNullOrEmpty(upload.Upload.Key) && !string.IsNullOrEmpty(upload.Upload.IV));

<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-sm-10 text-left">
<h4><b>@((string.IsNullOrEmpty(upload.Title)) ? "Upload" : upload.Title)</b> <small>Uploaded on <time datetime="@upload.Upload.DateUploaded.ToString("s")">@upload.Upload.DateUploaded.ToString("dddd, MMMM d, yyyy") at @upload.Upload.DateUploaded.ToString("h:mm:ss tt")</time></small></h4>
</div>
<div class="col-sm-2 text-right">
<h4><small><a href="@Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Upload.Url })" target="_blank">Direct Link</a></small></h4>
</div>
</div>
</div>
<div class="panel-body">
@if (upload.Upload.ContentType.StartsWith("image") && !needsKey)
{
<a href="@Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Upload.Url })" target="_blank">
<img src="@Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Upload.Url })" class="img-thumbnail center-block" />
</a>
}
else if (upload.Upload.ContentType.StartsWith("audio") && !needsKey)
{
<div class="text-center">
<audio preload="none" controls>
<source src="@Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Upload.Url })" type="@upload.Upload.ContentType" />
</audio>
</div>
}
else if (upload.Upload.ContentType.StartsWith("video") && !needsKey)
{
<div class="text-center">
<video preload="none" controls>
<source src="@Url.SubRouteUrl("u", "Upload.Download", new { file = upload.Upload.Url })" type="@upload.Upload.ContentType" />
</video>
</div>
}
else
{
<div class="row">
<div class="col-sm-4 text-center">
<label for="size">Size</label>
<p id="size">@StringHelper.GetBytesReadable(upload.Upload.ContentLength)</p>
</div>
<div class="col-sm-4 text-center">
<label for="type">Type</label>
<p id="type">@upload.Upload.ContentType</p>
</div>
<div class="col-sm-4 text-center">
<label for="dateUploaded">Date Uploaded</label>
<p id="dateUploaded"><time datetime="@upload.Upload.DateUploaded.ToString("s")">@upload.Upload.DateUploaded.ToString("MMMM dd, yyyy")</time></p>
</div>
</div>
}
</div>
@if (!string.IsNullOrEmpty(upload.Description))
{
<div class="panel-footer">
<p>@upload.Description</p>
</div>
}
</div>
@Html.Partial("~/Areas/Vault/Views/Vault/UploadItem.cshtml", uploadModel)
}
else
{

+ 6
- 0
Teknik/Teknik.csproj View File

@@ -244,6 +244,9 @@
<Compile Include="Areas\User\ViewModels\TwoFactorViewModel.cs" />
<Compile Include="Areas\Vault\ViewModels\NewVaultViewModel.cs" />
<Compile Include="Areas\Vault\ViewModels\NewVaultItemViewModel.cs" />
<Compile Include="Areas\Vault\ViewModels\UploadItemViewModel.cs" />
<Compile Include="Areas\Vault\ViewModels\PasteItemViewModel.cs" />
<Compile Include="Areas\Vault\ViewModels\VaultItemViewModel.cs" />
<Compile Include="Attributes\TeknikAuthorizeAttribute.cs" />
<Compile Include="Filters\CORSActionFilter.cs" />
<Compile Include="Models\TransferTypes.cs" />
@@ -578,6 +581,9 @@
<Content Include="Areas\Error\Views\Error\Http401.cshtml" />
<Content Include="Areas\Transparency\Views\_ViewStart.cshtml" />
<Content Include="Areas\Vault\Views\Vault\NewVault.cshtml" />
<Content Include="Areas\Vault\Views\Vault\NewVaultItem.cshtml" />
<Content Include="Areas\Vault\Views\Vault\PasteItem.cshtml" />
<Content Include="Areas\Vault\Views\Vault\UploadItem.cshtml" />
<None Include="Properties\PublishProfiles\Teknik Dev.pubxml" />
<None Include="Properties\PublishProfiles\Teknik Production.pubxml" />
<None Include="Scripts\jquery-2.1.4.intellisense.js" />

Loading…
Cancel
Save