Browse Source

Merge pull request #16551 from abpframework/EngincanV/change-theme-step

Refactor ChangeThemeStep
pull/16562/head
liangshiwei 3 years ago
committed by GitHub
parent
commit
42c1619593
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 724
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs

724
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ChangeThemeStep.cs

@ -10,6 +10,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps;
public class ChangeThemeStep : ProjectBuildPipelineStep public class ChangeThemeStep : ProjectBuildPipelineStep
{ {
private const string Basic = "Basic";
private const string LeptonXLite = "LeptonXLite";
private const string LeptonX = "LeptonX";
private const string Lepton = "Lepton";
public override void Execute(ProjectBuildContext context) public override void Execute(ProjectBuildContext context)
{ {
if (!context.BuildArgs.Theme.HasValue) if (!context.BuildArgs.Theme.HasValue)
@ -28,50 +33,65 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
} }
} }
protected void ChangeToBasicTheme(ProjectBuildContext context) protected virtual void ChangeToBasicTheme(ProjectBuildContext context)
{ {
var defaultThemeName = context.BuildArgs.TemplateName is AppTemplate.TemplateName or AppNoLayersTemplate.TemplateName var defaultThemeName = context.BuildArgs.TemplateName is AppTemplate.TemplateName or AppNoLayersTemplate.TemplateName
? "LeptonXLite" ? LeptonXLite : LeptonX;
: "LeptonX";
#region MVC Projects
ChangeThemeToBasicForMvcProjects(context, defaultThemeName); ChangeThemeToBasicForMvcProjects(context, defaultThemeName);
ChangeThemeToBasicForBlazorProjects(context, defaultThemeName);
ChangeThemeToBasicForBlazorServerProjects(context, defaultThemeName);
ChangeThemeForAngularProjects(context, defaultThemeName, Basic, GetAngularPackageName(context.BuildArgs.Theme!.Value), GetAngularPackageName(Theme.Basic));
}
#endregion protected virtual void ChangeToLeptonTheme(ProjectBuildContext context)
{
//common
RenameFolders(context, oldFolderName: LeptonX , newFolderName: Lepton);
AddLeptonThemeManagementReferenceToProjects(context);
#region MyCompanyName.MyProjectName.Blazor ChangeThemeToLeptonForMvcProjects(context);
ChangeThemeToLeptonForBlazorProjects(context);
ChangeThemeToLeptonForBlazorServerProjects(context);
ChangeThemeForAngularProjects(context, oldThemeName: LeptonX, Lepton, GetAngularPackageName(Theme.LeptonX), GetAngularPackageName(Theme.Lepton));
ConfigureLeptonManagementPackagesForNoLayersMvc(context, "/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.csproj", new[] { "Web", "HttpApi", "Application" });
ChangeThemeToLeptonForNoLayersBlazorServerProjects(context);
ChangeThemeToLeptonForMauiBlazorProjects(context);
}
private static string GetAngularPackageName(Theme theme)
{
return theme switch
{
Theme.LeptonX => "@volosoft/abp.ng.theme.lepton-x",
Theme.LeptonXLite => "@abp/ng.theme.lepton-x",
Theme.Basic => "@abp/ng.theme.basic",
_ => string.Empty
};
}
private static void ChangeThemeToBasicForBlazorProjects(ProjectBuildContext context, string defaultThemeName)
{
ReplacePackageReferenceWithProjectReference( ReplacePackageReferenceWithProjectReference(
context, context,
"/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj", "/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj",
$"Volo.Abp.AspNetCore.Components.WebAssembly.{defaultThemeName}Theme", $"Volo.Abp.AspNetCore.Components.WebAssembly.{defaultThemeName}Theme",
@"..\..\..\..\..\modules\basic-theme\src\Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme\Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.csproj" @"..\..\..\..\..\modules\basic-theme\src\Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme\Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme.csproj"
);
ChangeNamespaceAndKeyword(
context,
"/MyCompanyName.MyProjectName.Blazor/MyProjectNameBlazorModule.cs",
$"Volo.Abp.AspNetCore.Components.WebAssembly.{defaultThemeName}Theme",
"Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme",
$"AbpAspNetCoreComponentsWebAssembly{defaultThemeName}ThemeModule",
"AbpAspNetCoreComponentsWebAssemblyBasicThemeModule"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context, context,
"/MyCompanyName.MyProjectName.Blazor/MyProjectNameBlazorModule.cs", "/MyCompanyName.MyProjectName.Blazor/MyProjectNameBlazorModule.cs",
$"Volo.Abp.AspNetCore.Components.Web.{defaultThemeName}Theme.Themes.{defaultThemeName}", $"{defaultThemeName}Theme.Components",
"Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic", "BasicTheme.Themes.Basic"
$"AbpAspNetCoreComponentsWebAssembly{defaultThemeName}ThemeModule",
"AbpAspNetCoreComponentsWebAssemblyBasicThemeModule"
); );
ChangeNamespace( ReplaceAllKeywords(
context, context,
"/MyCompanyName.MyProjectName.Blazor/MyProjectNameBlazorModule.cs", "/MyCompanyName.MyProjectName.Blazor/MyProjectNameBlazorModule.cs",
$"Volo.Abp.AspNetCore.Components.Web.{defaultThemeName}Theme.Components", defaultThemeName,
"Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic" Basic
); );
ReplacePackageReferenceWithProjectReference( ReplacePackageReferenceWithProjectReference(
@ -81,209 +101,94 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
@"..\..\..\..\..\modules\basic-theme\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj" @"..\..\..\..\..\modules\basic-theme\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context,
"/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs",
$"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}.Bundling",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling",
$"{defaultThemeName}ThemeBundles.Styles.Global",
"BasicThemeBundles.Styles.Global"
);
ChangeNamespaceAndKeyword(
context, context,
"/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs", "/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs",
$"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}", defaultThemeName,
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic", Basic
$"AbpAspNetCoreMvcUi{defaultThemeName}ThemeModule",
"AbpAspNetCoreMvcUiBasicThemeModule"
); );
}
#endregion private static void ChangeThemeForAngularProjects(ProjectBuildContext context, string oldThemeName, string newThemeName, string oldPackageName, string newPackageName)
{
#region Blazor.Server Projects if (context.BuildArgs.UiFramework != UiFramework.Angular)
{
ChangeThemeToBasicForBlazorProjects(context, defaultThemeName); return;
}
#endregion
#region Angular
var angularPackageName = context.BuildArgs.TemplateName is AppTemplate.TemplateName or AppNoLayersTemplate.TemplateName
? "@abp/ng.theme.lepton-x"
: "@volosoft/abp.ng.theme.lepton-x";
ReplaceImportPackage( ReplaceImportPackage(
context, context,
"/angular/src/app/app.module.ts", "/angular/src/app/app.module.ts",
angularPackageName, oldPackageName,
"@abp/ng.theme.basic" newPackageName
); );
RemoveLinesByStatement( RemoveLinesByStatement(
context, context,
"/angular/src/app/app.module.ts", "/angular/src/app/app.module.ts",
"SideMenuLayoutModule" "SideMenuLayoutModule"
); );
ReplaceMethodNames( ReplaceAllKeywords(
context, context,
"/angular/src/app/app.module.ts", "/angular/src/app/app.module.ts",
"ThemeLeptonXModule", $"Theme{oldThemeName}Module",
"ThemeBasicModule" $"Theme{newThemeName}Module"
);
RemoveLinesByStatement(
context,
"/angular/angular.json",
"node_modules/bootstrap-icons/font/bootstrap-icons.css"
); );
if(defaultThemeName == "LeptonX") if (oldThemeName != LeptonX)
{ {
ReplaceMethodNames( return;
context,
"/angular/src/app/app.module.ts",
"HttpErrorComponent, ",
""
);
ChangeModuleImportBetweenStatements(
context,
"/angular/src/app/app.module.ts",
"ThemeSharedModule.forRoot",
"AccountAdminConfigModule.forRoot",
"ThemeSharedModule.forRoot(),"
);
} }
#endregion ReplaceAllKeywords(
context,
"/angular/src/app/app.module.ts",
"HttpErrorComponent, ",
""
);
ChangeModuleImportBetweenStatements(
context,
"/angular/src/app/app.module.ts",
"ThemeSharedModule.forRoot",
"AccountAdminConfigModule.forRoot",
"ThemeSharedModule.forRoot(),"
);
} }
protected void ChangeToLeptonTheme(ProjectBuildContext context) private static void ChangeThemeToLeptonForBlazorProjects(ProjectBuildContext context)
{ {
#region Common
RenameLeptonXFolders(context, folderName: "Lepton");
AddLeptonThemeManagementReferenceToProjects(context);
#endregion
#region MVC Projects
ChangeThemeToLeptonForMvcProjects(context);
#endregion
#region MyCompanyName.MyProjectName.Blazor
ReplacePackageReferenceWithProjectReference( ReplacePackageReferenceWithProjectReference(
context, context,
"/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj", "/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj",
"Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXTheme", "Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXTheme",
@"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Components.WebAssembly.LeptonTheme\Volo.Abp.AspNetCore.Components.WebAssembly.LeptonTheme.csproj" @"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Components.WebAssembly.LeptonTheme\Volo.Abp.AspNetCore.Components.WebAssembly.LeptonTheme.csproj"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context, context,
"/MyCompanyName.MyProjectName.Blazor/MyProjectNameBlazorModule.cs", "/MyCompanyName.MyProjectName.Blazor/MyProjectNameBlazorModule.cs",
"Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components", LeptonX,
"Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components", Lepton
"AbpAspNetCoreComponentsWebAssemblyLeptonXThemeModule",
"AbpAspNetCoreComponentsWebAssemblyLeptonThemeModule"
); );
ChangeNamespace(
context,
"/MyCompanyName.MyProjectName.Blazor/MyProjectNameBlazorModule.cs",
"Volo.Abp.AspNetCore.Components.WebAssembly.LeptonXTheme",
"Volo.Abp.AspNetCore.Components.WebAssembly.LeptonTheme"
);
ReplacePackageReferenceWithProjectReference( ReplacePackageReferenceWithProjectReference(
context, context,
"/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj", "/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX", "Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX",
@"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton\Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.csproj" @"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton\Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.csproj"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context,
"/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Bundling",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling",
"LeptonXThemeBundles.Styles.Global",
"LeptonThemeBundles.Styles.Global"
);
ChangeNamespaceAndKeyword(
context, context,
"/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs", "/MyCompanyName.MyProjectName.Host/MyProjectNameHostModule.cs",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX", LeptonX,
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton", Lepton
"AbpAspNetCoreMvcUiLeptonXThemeModule",
"AbpAspNetCoreMvcUiLeptonThemeModule"
);
#endregion
#region MyCompanyName.MyProjectName.Blazor.Server && MyCompanyName.MyProjectName.Blazor.Server.Tiered
ChangeThemeToLeptonForBlazorServerProjects(context);
#endregion
#region Angular
ReplaceImportPackage(
context,
"/angular/src/app/app.module.ts",
"@volosoft/abp.ng.theme.lepton-x",
"@volo/abp.ng.theme.lepton"
);
RemoveLinesByStatement(
context,
"/angular/src/app/app.module.ts",
"SideMenuLayoutModule"
);
ReplaceMethodNames(
context,
"/angular/src/app/app.module.ts",
"ThemeLeptonXModule",
"ThemeLeptonModule"
);
RemoveLinesByStatement(
context,
"/angular/angular.json",
"node_modules/bootstrap-icons/font/bootstrap-icons.css"
); );
#endregion
#region MyCompanyName.MyProjectName.Mvc && MyCompanyName.MyProjectName.Mvc.Mongo
var projectNames = new[] {"Web", "HttpApi", "Application"};
ConfigureLeptonManagementPackagesForNoLayersMvc(context, @"/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.csproj", projectNames);
#endregion
#region MyCompanyName.MyProjectName.Blazor.Server && MyCompanyName.MyProjectName.Blazor.Server.Mongo - (app-nolayers)
ChangeThemeToLeptonForNoLayersBlazorServerProjects(context);
#endregion
#region MyCompanyName.MyProjectName.MauiBlazor
ChangeThemeToLeptonForMauiBlazorProjects(context);
#endregion
} }
private void ConfigureLeptonManagementPackagesForNoLayersMvc(ProjectBuildContext context, string targetProjectPath, string[] projectNames) private static void ConfigureLeptonManagementPackagesForNoLayersMvc(ProjectBuildContext context, string targetProjectPath, IEnumerable<string> projectNames)
{ {
var file = context.Files.FirstOrDefault(f => !f.Name.Contains("Test") && f.Name.Contains(targetProjectPath) && f.Name.Contains(".csproj")); var file = context.Files.FirstOrDefault(f => !f.Name.Contains("Test") && f.Name.Contains(targetProjectPath) && f.Name.Contains(".csproj"));
if (file == null) if (file == null)
@ -304,7 +209,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
} }
} }
private void ChangeThemeToLeptonForMvcProjects(ProjectBuildContext context) private static void ChangeThemeToLeptonForMvcProjects(ProjectBuildContext context)
{ {
var projectNames = new[] var projectNames = new[]
{ {
@ -333,23 +238,12 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX", "Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX",
@"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton\Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.csproj" @"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton\Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.csproj"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context,
moduleFile.Name,
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Bundling",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling",
"LeptonXThemeBundles.Styles.Global",
"LeptonThemeBundles.Styles.Global"
);
ChangeNamespaceAndKeyword(
context, context,
moduleFile.Name, moduleFile.Name,
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX", LeptonX,
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton", Lepton
"AbpAspNetCoreMvcUiLeptonXThemeModule",
"AbpAspNetCoreMvcUiLeptonThemeModule"
); );
RemoveLinesByStatement( RemoveLinesByStatement(
@ -360,7 +254,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
} }
} }
private void AddLeptonThemeManagementReferenceToProjects(ProjectBuildContext context) private static void AddLeptonThemeManagementReferenceToProjects(ProjectBuildContext context)
{ {
var projects = new Dictionary<string, string> var projects = new Dictionary<string, string>
{ {
@ -396,7 +290,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
} }
} }
private void AddUiProjectToProjects(Dictionary<string, string> projects, ProjectBuildContext context) private static void AddUiProjectToProjects(Dictionary<string, string> projects, ProjectBuildContext context)
{ {
if (projects.IsNullOrEmpty()) if (projects.IsNullOrEmpty())
{ {
@ -418,7 +312,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
} }
} }
private void AddLeptonThemeManagementReference(ProjectBuildContext context, KeyValuePair<string, string> projectInfo) private static void AddLeptonThemeManagementReference(ProjectBuildContext context, KeyValuePair<string, string> projectInfo)
{ {
var reference = $@"..\..\..\..\..\lepton-theme\src\Volo.Abp.LeptonTheme.Management.{projectInfo.Key}\Volo.Abp.LeptonTheme.Management.{projectInfo.Key}.csproj"; var reference = $@"..\..\..\..\..\lepton-theme\src\Volo.Abp.LeptonTheme.Management.{projectInfo.Key}\Volo.Abp.LeptonTheme.Management.{projectInfo.Key}.csproj";
var projectFile = context.Files.FirstOrDefault(f => !f.Name.Contains("Test") && f.Name.Contains(projectInfo.Value) && f.Name.Contains(".csproj")); var projectFile = context.Files.FirstOrDefault(f => !f.Name.Contains("Test") && f.Name.Contains(projectInfo.Value) && f.Name.Contains(".csproj"));
@ -439,7 +333,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
underManagementFolder: projectInfo.Key != "HttpApi"); underManagementFolder: projectInfo.Key != "HttpApi");
} }
private void AddModuleDependency(FileEntry moduleFile, string projectName, string dependency, bool underManagementFolder = true) private static void AddModuleDependency(FileEntry moduleFile, string projectName, string dependency, bool underManagementFolder = true)
{ {
var projectNames = new[] { "Blazor", "Blazor.Server", "Blazor.WebAssembly" }; var projectNames = new[] { "Blazor", "Blazor.Server", "Blazor.WebAssembly" };
@ -460,11 +354,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
moduleFile.SetLines(lines); moduleFile.SetLines(lines);
} }
protected void ReplacePackageReferenceWithProjectReference( private static void ReplacePackageReferenceWithProjectReference(ProjectBuildContext context, string targetProjectFilePath, string packageReference, string projectReference)
ProjectBuildContext context,
string targetProjectFilePath,
string packageReference,
string projectReference)
{ {
var file = context.Files.FirstOrDefault(x => x.Name.Contains(targetProjectFilePath)); var file = context.Files.FirstOrDefault(x => x.Name.Contains(targetProjectFilePath));
if (file == null) if (file == null)
@ -485,97 +375,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
file.SetLines(lines); file.SetLines(lines);
} }
protected void ChangeNamespaceAndKeyword( private static void ReplaceImportPackage(ProjectBuildContext context, string filePath, string oldImportPackage, string newImportPackage)
ProjectBuildContext context,
string targetModuleFilePath,
string oldNamespace,
string newNamespace,
string oldKeyword,
string newKeyword)
{
var file = context.Files.FirstOrDefault(x => x.Name.Contains(targetModuleFilePath));
if (file == null)
{
return;
}
file.NormalizeLineEndings();
var lines = file.GetLines();
for (var i = 0; i < lines.Length; i++)
{
if (lines[i].Contains($"using {oldNamespace}"))
{
lines[i] = lines[i].Replace($"using {oldNamespace}", $"using {newNamespace}");
}
else if (lines[i].Contains(oldKeyword))
{
lines[i] = lines[i].Replace(oldKeyword, newKeyword);
}
}
file.SetLines(lines);
}
protected void ChangeNamespace(
ProjectBuildContext context,
string targetModuleFilePath,
string oldNamespace,
string newNamespace)
{
var file = context.Files.FirstOrDefault(x => x.Name.Contains(targetModuleFilePath));
if (file == null)
{
return;
}
file.NormalizeLineEndings();
var lines = file.GetLines();
for (var i = 0; i < lines.Length; i++)
{
if (lines[i].Contains($"using {oldNamespace}"))
{
lines[i] = lines[i].Replace($"using {oldNamespace}", $"using {newNamespace}");
}
}
file.SetLines(lines);
}
protected void ChangeKeyword(
ProjectBuildContext context,
string targetModuleFilePath,
string oldKeyword,
string newKeyword)
{
var file = context.Files.FirstOrDefault(x => x.Name.Contains(targetModuleFilePath));
if (file == null)
{
return;
}
file.NormalizeLineEndings();
var lines = file.GetLines();
for (var i = 0; i < lines.Length; i++)
{
if (lines[i].Contains(oldKeyword))
{
lines[i] = lines[i].Replace(oldKeyword, newKeyword);
}
}
file.SetLines(lines);
}
protected void ReplaceImportPackage(
ProjectBuildContext context,
string filePath,
string oldImportPackage,
string newImportPackage)
{ {
var file = context.Files.FirstOrDefault(x => x.Name.Contains(filePath)); var file = context.Files.FirstOrDefault(x => x.Name.Contains(filePath));
if (file == null) if (file == null)
@ -584,6 +384,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
} }
file.NormalizeLineEndings(); file.NormalizeLineEndings();
var lines = file.GetLines(); var lines = file.GetLines();
var lineIndex = lines.FindIndex(line => line.Contains($"from '{oldImportPackage}'")); var lineIndex = lines.FindIndex(line => line.Contains($"from '{oldImportPackage}'"));
if (lineIndex == -1) if (lineIndex == -1)
@ -595,10 +396,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
file.SetLines(lines); file.SetLines(lines);
} }
protected void RemoveLinesByStatement( private static void RemoveLinesByStatement(ProjectBuildContext context, string filePath, string statement)
ProjectBuildContext context,
string filePath,
string statement)
{ {
var file = context.Files.FirstOrDefault(x => x.Name.Contains(filePath)); var file = context.Files.FirstOrDefault(x => x.Name.Contains(filePath));
if (file == null) if (file == null)
@ -620,12 +418,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
file.SetLines(lines.Where(x => x != null)); file.SetLines(lines.Where(x => x != null));
} }
private void ChangeModuleImportBetweenStatements( private static void ChangeModuleImportBetweenStatements(ProjectBuildContext context, string filePath, string firstStatement, string lastStatement, string newStatement)
ProjectBuildContext context,
string filePath,
string firstStatement,
string lastStatement,
string newStatement)
{ {
var file = context.Files.FirstOrDefault(x => x.Name.Contains(filePath)); var file = context.Files.FirstOrDefault(x => x.Name.Contains(filePath));
if (file == null) if (file == null)
@ -651,36 +444,9 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
lines[i] = null; lines[i] = null;
} }
file.SetLines(lines.Where(x => x != null)); file.SetLines(lines.Where(x => x != null));
} }
protected void ReplaceMethodNames(
ProjectBuildContext context,
string filePath,
string oldMethodName,
string newMethodName)
{
var file = context.Files.FirstOrDefault(x => x.Name.Contains(filePath));
if (file == null)
{
return;
}
file.NormalizeLineEndings();
var lines = file.GetLines();
for (var i = 0; i < lines.Length; i++)
{
if (lines[i].Contains(oldMethodName))
{
lines[i] = lines[i].Replace(oldMethodName, newMethodName);
}
}
file.SetLines(lines);
}
private static void AddProjectReference(FileEntry file, string reference) private static void AddProjectReference(FileEntry file, string reference)
{ {
if (!file.Name.Contains(".csproj")) if (!file.Name.Contains(".csproj"))
@ -746,7 +512,7 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
splittedProjectFileName = splittedProjectFileName.Take(splittedProjectFileName.Length - 1).ToArray(); splittedProjectFileName = splittedProjectFileName.Take(splittedProjectFileName.Length - 1).ToArray();
var fileName = splittedProjectFileName?.Last(); var fileName = splittedProjectFileName.Last();
if (fileName == null) if (fileName == null)
{ {
return null; return null;
@ -765,16 +531,40 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
return moduleName.Replace(".", ""); return moduleName.Replace(".", "");
} }
private static void RenameLeptonXFolders(ProjectBuildContext context, string folderName) private static void RenameFolders(ProjectBuildContext context, string oldFolderName, string newFolderName)
{ {
var leptonXFiles = context.Files.Where(x => x.Name.Contains("LeptonX") && x.IsDirectory); foreach (var file in context.Files.Where(x => x.Name.Contains(oldFolderName) && x.IsDirectory))
foreach (var file in leptonXFiles)
{ {
new MoveFolderStep(file.Name, file.Name.Replace("LeptonX", folderName)).Execute(context); new MoveFolderStep(file.Name, file.Name.Replace(oldFolderName, newFolderName)).Execute(context);
} }
} }
private void ChangeThemeToBasicForMvcProjects(ProjectBuildContext context, string defaultThemeName) private static void ReplaceAllKeywords(ProjectBuildContext context, string targetModuleFilePath, string oldKeyword, string newKeyword)
{
var file = context.Files.FirstOrDefault(x => x.Name.Contains(targetModuleFilePath));
if (file == null)
{
return;
}
file.NormalizeLineEndings();
var lines = file.GetLines();
for (var i = 0; i < lines.Length; i++)
{
if (!lines[i].Contains(oldKeyword))
{
continue;;
}
lines[i] = lines[i].Replace(oldKeyword, newKeyword);
}
file.SetLines(lines);
}
private static void ChangeThemeToBasicForMvcProjects(ProjectBuildContext context, string defaultThemeName)
{ {
var projects = new Dictionary<string, string> var projects = new Dictionary<string, string>
{ {
@ -794,28 +584,17 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
$"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}", $"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}",
@"..\..\..\..\..\modules\basic-theme\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj" @"..\..\..\..\..\modules\basic-theme\src\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic\Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.csproj"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context, context,
$"/MyCompanyName.MyProjectName{project.Key}/{project.Value}.cs", $"/MyCompanyName.MyProjectName{project.Key}/{project.Value}.cs",
$"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}", defaultThemeName,
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic", Basic
$"AbpAspNetCoreMvcUi{defaultThemeName}ThemeModule",
"AbpAspNetCoreMvcUiBasicThemeModule"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName{project.Key}/{project.Value}.cs",
$"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}.Bundling",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling",
$"{defaultThemeName}ThemeBundles.Styles.Global",
"BasicThemeBundles.Styles.Global"
); );
} }
} }
private void ChangeThemeToBasicForBlazorProjects(ProjectBuildContext context, string defaultThemeName) private static void ChangeThemeToBasicForBlazorServerProjects(ProjectBuildContext context, string defaultThemeName)
{ {
var projects = new Dictionary<string, string> var projects = new Dictionary<string, string>
{ {
@ -840,73 +619,34 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
$"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}", $"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}",
@"..\..\..\..\..\modules\basic-theme\src\Volo.Abp.AspNetCore.Components.Server.BasicTheme\Volo.Abp.AspNetCore.Components.Server.BasicTheme.csproj" @"..\..\..\..\..\modules\basic-theme\src\Volo.Abp.AspNetCore.Components.Server.BasicTheme\Volo.Abp.AspNetCore.Components.Server.BasicTheme.csproj"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context,
$"/MyCompanyName.MyProjectName.{project.Key}/{project.Value}.cs",
$"Volo.Abp.AspNetCore.Components.Server.{defaultThemeName}Theme",
"Volo.Abp.AspNetCore.Components.Server.BasicTheme",
$"AbpAspNetCoreComponentsServer{defaultThemeName}ThemeModule",
"AbpAspNetCoreComponentsServerBasicThemeModule"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{project.Key}/{project.Value}.cs",
$"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic",
$"AbpAspNetCoreMvcUi{defaultThemeName}ThemeModule",
"AbpAspNetCoreMvcUiBasicThemeModule"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{project.Key}/{project.Value}.cs",
$"Volo.Abp.AspNetCore.Components.Server.{defaultThemeName}Theme.Bundling",
"Volo.Abp.AspNetCore.Components.Server.BasicTheme.Bundling",
$"{defaultThemeName}ThemeBundles.Styles.Global",
"BasicThemeBundles.Styles.Global"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{project.Key}/{project.Value}.cs",
$"Volo.Abp.AspNetCore.Mvc.UI.Theme.{defaultThemeName}.Bundling",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling",
$"Blazor{defaultThemeName}ThemeBundles.Styles.Global",
"BlazorBasicThemeBundles.Styles.Global"
);
ChangeNamespaceAndKeyword(
context, context,
$"/MyCompanyName.MyProjectName.{project.Key}/Pages/_Host.cshtml", $"/MyCompanyName.MyProjectName.{project.Key}/Pages/_Host.cshtml",
$"Volo.Abp.AspNetCore.Components.Web.{defaultThemeName}Theme.Components", $"{defaultThemeName}Theme.Components",
"Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic", Basic
$"Blazor{defaultThemeName}ThemeBundles.Styles.Global",
"BlazorBasicThemeBundles.Styles.Global"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context, context,
$"/MyCompanyName.MyProjectName.{project.Key}/Pages/_Host.cshtml", $"/MyCompanyName.MyProjectName.{project.Key}/{project.Value}.cs",
$"Volo.Abp.AspNetCore.Components.Server.{defaultThemeName}Theme.Bundling", defaultThemeName,
"Volo.Abp.AspNetCore.Components.Server.BasicTheme.Bundling", Basic
$"Blazor{defaultThemeName}ThemeBundles.Scripts.Global",
"BlazorBasicThemeBundles.Scripts.Global"
); );
ChangeNamespace( ReplaceAllKeywords(
context, context,
$"/MyCompanyName.MyProjectName.{project.Key}/Pages/_Host.cshtml", $"/MyCompanyName.MyProjectName.{project.Key}/Pages/_Host.cshtml",
$"Volo.Abp.AspNetCore.Components.Web.{defaultThemeName}Theme.Themes.{defaultThemeName}", defaultThemeName,
"Volo.Abp.AspNetCore.Components.Web.BasicTheme.Themes.Basic" Basic
); );
} }
} }
private void ChangeThemeToLeptonForBlazorServerProjects(ProjectBuildContext context) private static void ChangeThemeToLeptonForBlazorServerProjects(ProjectBuildContext context)
{ {
var projectNames = new[] {"Blazor", "Blazor.Server.Tiered"}; var projectNames = new[] { "Blazor", "Blazor.Server.Tiered" };
foreach (var projectName in projectNames) foreach (var projectName in projectNames)
{ {
ReplacePackageReferenceWithProjectReference( ReplacePackageReferenceWithProjectReference(
@ -922,59 +662,19 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
"Volo.Abp.AspNetCore.Components.Server.LeptonXTheme", "Volo.Abp.AspNetCore.Components.Server.LeptonXTheme",
@"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Components.Server.LeptonTheme\Volo.Abp.AspNetCore.Components.Server.LeptonTheme.csproj" @"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Components.Server.LeptonTheme\Volo.Abp.AspNetCore.Components.Server.LeptonTheme.csproj"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context,
$"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameBlazorModule.cs",
"Volo.Abp.AspNetCore.Components.Server.LeptonXTheme",
"Volo.Abp.AspNetCore.Components.Server.LeptonTheme",
"AbpAspNetCoreComponentsServerLeptonXThemeModule",
"AbpAspNetCoreComponentsServerLeptonThemeModule"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameBlazorModule.cs",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton",
"AbpAspNetCoreMvcUiLeptonXThemeModule",
"AbpAspNetCoreMvcUiLeptonThemeModule"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameBlazorModule.cs",
"Volo.Abp.AspNetCore.Components.Server.LeptonXTheme.Bundling",
"Volo.Abp.AspNetCore.Components.Server.LeptonTheme.Bundling",
"LeptonXThemeBundles.Styles.Global",
"LeptonThemeBundles.Styles.Global"
);
ChangeNamespaceAndKeyword(
context, context,
$"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameBlazorModule.cs", $"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameBlazorModule.cs",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Bundling", LeptonX,
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling", Lepton
"BlazorLeptonXThemeBundles.Styles.Global",
"BlazorLeptonThemeBundles.Styles.Global"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{projectName}/Pages/_Host.cshtml",
"Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components",
"Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components",
"BlazorLeptonXThemeBundles.Styles.Global",
"BlazorLeptonThemeBundles.Styles.Global"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context, context,
$"/MyCompanyName.MyProjectName.{projectName}/Pages/_Host.cshtml", $"/MyCompanyName.MyProjectName.{projectName}/Pages/_Host.cshtml",
"Volo.Abp.AspNetCore.Components.Server.LeptonXTheme.Bundling", LeptonX,
"Volo.Abp.AspNetCore.Components.Server.LeptonTheme.Bundling", Lepton
"BlazorLeptonXThemeBundles.Scripts.Global",
"BlazorLeptonThemeBundles.Scripts.Global"
); );
RemoveLinesByStatement( RemoveLinesByStatement(
@ -985,11 +685,11 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
} }
} }
private void ChangeThemeToLeptonForNoLayersBlazorServerProjects(ProjectBuildContext context) private static void ChangeThemeToLeptonForNoLayersBlazorServerProjects(ProjectBuildContext context)
{ {
var blazorServerProjects = new[] { "Blazor.Server", "HttpApi", "Application" }; var blazorServerProjects = new[] { "Blazor.Server", "HttpApi", "Application" };
var projectNames = new[] { "Blazor.Server", "Blazor.Server.Mongo" }; var projectNames = new[] { "Blazor.Server", "Blazor.Server.Mongo" };
foreach (var projectName in projectNames) foreach (var projectName in projectNames)
{ {
ReplacePackageReferenceWithProjectReference( ReplacePackageReferenceWithProjectReference(
@ -1006,67 +706,29 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
@"..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Components.Server.LeptonTheme\Volo.Abp.AspNetCore.Components.Server.LeptonTheme.csproj" @"..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Components.Server.LeptonTheme\Volo.Abp.AspNetCore.Components.Server.LeptonTheme.csproj"
); );
ConfigureLeptonManagementPackagesForNoLayersMvc(context, ConfigureLeptonManagementPackagesForNoLayersMvc(
$@"/MyCompanyName.MyProjectName.{projectName}/MyCompanyName.MyProjectName.{projectName}.csproj",
blazorServerProjects);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameModule.cs",
"Volo.Abp.AspNetCore.Components.Server.LeptonXTheme",
"Volo.Abp.AspNetCore.Components.Server.LeptonTheme",
"AbpAspNetCoreComponentsServerLeptonXThemeModule",
"AbpAspNetCoreComponentsServerLeptonThemeModule"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameModule.cs",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton",
"AbpAspNetCoreMvcUiLeptonXThemeModule",
"AbpAspNetCoreMvcUiLeptonThemeModule"
);
ChangeNamespaceAndKeyword(
context, context,
$"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameModule.cs", $@"/MyCompanyName.MyProjectName.{projectName}/MyCompanyName.MyProjectName.{projectName}.csproj",
"Volo.Abp.AspNetCore.Components.Server.LeptonXTheme.Bundling", blazorServerProjects
"Volo.Abp.AspNetCore.Components.Server.LeptonTheme.Bundling",
"LeptonXThemeBundles.Styles.Global",
"LeptonThemeBundles.Styles.Global"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context, context,
$"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameModule.cs", $"/MyCompanyName.MyProjectName.{projectName}/MyProjectNameModule.cs",
"Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX.Bundling", LeptonX,
"Volo.Abp.AspNetCore.Mvc.UI.Theme.Lepton.Bundling", Lepton
"BlazorLeptonXThemeBundles.Styles.Global",
"BlazorLeptonThemeBundles.Styles.Global"
);
ChangeNamespaceAndKeyword(
context,
$"/MyCompanyName.MyProjectName.{projectName}/Pages/_Host.cshtml",
"Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components",
"Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components",
"BlazorLeptonXThemeBundles.Styles.Global",
"BlazorLeptonThemeBundles.Styles.Global"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context, context,
$"/MyCompanyName.MyProjectName.{projectName}/Pages/_Host.cshtml", $"/MyCompanyName.MyProjectName.{projectName}/Pages/_Host.cshtml",
"Volo.Abp.AspNetCore.Components.Server.LeptonXTheme.Bundling", LeptonX,
"Volo.Abp.AspNetCore.Components.Server.LeptonTheme.Bundling", Lepton
"BlazorLeptonXThemeBundles.Scripts.Global",
"BlazorLeptonThemeBundles.Scripts.Global"
); );
} }
} }
private void ChangeThemeToLeptonForMauiBlazorProjects(ProjectBuildContext context) private static void ChangeThemeToLeptonForMauiBlazorProjects(ProjectBuildContext context)
{ {
ReplacePackageReferenceWithProjectReference( ReplacePackageReferenceWithProjectReference(
context, context,
@ -1074,44 +736,42 @@ public class ChangeThemeStep : ProjectBuildPipelineStep
"Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonXTheme", "Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonXTheme",
@"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonTheme\Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonTheme.csproj" @"..\..\..\..\..\lepton-theme\src\Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonTheme\Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonTheme.csproj"
); );
ChangeNamespaceAndKeyword( ReplaceAllKeywords(
context,
"/MyCompanyName.MyProjectName.MauiBlazor/MyProjectNameMauiBlazorModule.cs",
"Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonXTheme",
"Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonTheme",
"AbpAspNetCoreComponentsMauiBlazorLeptonXThemeModule",
"AbpAspNetCoreComponentsMauiBlazorLeptonThemeModule"
);
ChangeKeyword(
context, context,
"/MyCompanyName.MyProjectName.MauiBlazor/MainPage.xaml", "/MyCompanyName.MyProjectName.MauiBlazor/MainPage.xaml",
"clr-namespace:Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components;assembly=Volo.Abp.AspNetCore.Components.Web.LeptonXTheme", "clr-namespace:Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components;assembly=Volo.Abp.AspNetCore.Components.Web.LeptonXTheme",
"clr-namespace:Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components;assembly=Volo.Abp.AspNetCore.Components.Web.LeptonTheme"); "clr-namespace:Volo.Abp.AspNetCore.Components.Web.LeptonTheme.Components;assembly=Volo.Abp.AspNetCore.Components.Web.LeptonTheme");
ChangeKeyword( ReplaceAllKeywords(
context, context,
"/MyCompanyName.MyProjectName.MauiBlazor/MainPage.xaml", "/MyCompanyName.MyProjectName.MauiBlazor/MainPage.xaml",
"leptonXTheme", "leptonXTheme",
"leptonTheme"); "leptonTheme");
ChangeKeyword( ReplaceAllKeywords(
context, context,
"/MyCompanyName.MyProjectName.MauiBlazor/Pages/Account/Login.razor", "/MyCompanyName.MyProjectName.MauiBlazor/Pages/Account/Login.razor",
"Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonXTheme.Components.AccountLayout", "Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonXTheme.Components.AccountLayout",
"Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonTheme.Components.AccountLayout"); "Volo.Abp.AspNetCore.Components.MauiBlazor.LeptonTheme.Components.AccountLayout");
ChangeKeyword( ReplaceAllKeywords(
context, context,
"/MyCompanyName.MyProjectName.MauiBlazor/Pages/Account/RedirectToLogout.razor", "/MyCompanyName.MyProjectName.MauiBlazor/Pages/Account/RedirectToLogout.razor",
"LeptonXResource", "LeptonXResource",
"LeptonThemeManagementResource"); "LeptonThemeManagementResource");
ChangeKeyword( ReplaceAllKeywords(
context, context,
"/MyCompanyName.MyProjectName.MauiBlazor/Pages/Account/RedirectToLogout.razor", "/MyCompanyName.MyProjectName.MauiBlazor/Pages/Account/RedirectToLogout.razor",
"Volo.Abp.LeptonX.Shared.Localization", "Volo.Abp.LeptonX.Shared.Localization",
"Volo.Abp.LeptonTheme.Management.Localization"); "Volo.Abp.LeptonTheme.Management.Localization");
ReplaceAllKeywords(
context,
"/MyCompanyName.MyProjectName.MauiBlazor/MyProjectNameMauiBlazorModule.cs",
LeptonX,
Lepton
);
} }
} }
Loading…
Cancel
Save