Skip to content

Commit

Permalink
feat: ImpersonatedNavigation
Browse files Browse the repository at this point in the history
  • Loading branch information
wzh425 committed Mar 13, 2024
1 parent aa5b611 commit af90dab
Show file tree
Hide file tree
Showing 7 changed files with 404 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
<PackageReference Include="Magicodes.IE.Csv" Version="2.6.4" />
<PackageReference Include="Masa.BuildingBlocks.Authentication.OpenIdConnect.Domain" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.BuildingBlocks.Authentication.OpenIdConnect.Models" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.BuildingBlocks.StackSdks.Auth.Contracts" Version="1.0.1-preview.10.1" />
<PackageReference Include="Masa.BuildingBlocks.StackSdks.Auth.Contracts" Version="1.0.1-preview.10.2" />
<!--<PackageReference Include="Masa.BuildingBlocks.StackSdks.Auth.Contracts" Version="$(MasaFrameworkPackageVersion)" />-->
<PackageReference Include="Masa.Contrib.Configuration.ConfigurationApi.Dcc" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.Contrib.Caching.Distributed.StackExchangeRedis" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.Contrib.SearchEngine.AutoComplete.ElasticSearch" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.Contrib.StackSdks.Auth" Version="1.0.1-preview.10.1" />
<PackageReference Include="Masa.Contrib.StackSdks.Auth" Version="1.0.1-preview.10.2" />
<PackageReference Include="Masa.Utils.Extensions.Enums" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.Utils.Extensions.Validations.FluentValidation" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="6.0.10" />
<PackageReference Include="AspNet.Security.OAuth.Weixin" Version="6.0.11" />
<PackageReference Include="Masa.BuildingBlocks.Authentication.OpenIdConnect.Models" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.BuildingBlocks.StackSdks.Auth.Contracts" Version="1.0.1-preview.10.1" />
<PackageReference Include="Masa.BuildingBlocks.StackSdks.Auth.Contracts" Version="1.0.1-preview.10.2" />
<PackageReference Include="Masa.Contrib.Exceptions" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.Contrib.Caching.Distributed.StackExchangeRedis" Version="$(MasaFrameworkPackageVersion)" />
<PackageReference Include="Masa.Utils.Extensions.DependencyInjection" Version="$(MasaFrameworkPackageVersion)" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
@using Masa.BuildingBlocks.StackSdks.Auth;
@using Masa.BuildingBlocks.StackSdks.Pm;
@using Microsoft.AspNetCore.Hosting;
@inherits AdminCompontentBase
@inject IMultiEnvironmentUserContext MultiEnvironmentUserContext
@inject IWebHostEnvironment WebHostEnvironment
@inject IMasaStackConfig MasaStackConfig
@inject IPmClient PmClient
@inject IAuthClient AuthClient

<MDialog Value="_visible"
ValueChanged="VisibleChanged"
Fullscreen
Transition="dialog-top-transition">
<ActivatorContent>
@ActivatorContent?.Invoke(context)
</ActivatorContent>
<ChildContent>
<MCard>
<div class="global-nav">
<div class="global-nav-left">
<div class="global-nav-left__content">
<div class="global-nav-left__group">
<div class="global-nav-left__title">
@T("Favorites")
</div>
<div class="full-width mt-3">
@if (_favorites == null)
{
<MSkeletonLoader Class="transparent" Type="list-item@3" />
}
else
{
@foreach (var item in _favorites)
{
<MListItem Dense
Class="mb-1 full-width rounded-2 masa-text-2-2"
OnClick="@(() => NavigateTo(item.GetData(MENU_URL_NAME)))">
<MListItemContent>
<MListItemTitle>@DT(item.Name)</MListItemTitle>
</MListItemContent>
<MListItemAction Class="ma-0">
<SAutoLoadingButton Icon Small Color="#FFB547"
OnClick="@(() => FavoriteRemoveAsync(item))"
OnClickStopPropagation>
<SIcon Small Tooltip="@T("CancelFavorite")">mdi-star</SIcon>
</SAutoLoadingButton>
</MListItemAction>
</MListItem>
}
}
</div>
</div>

<div class="global-nav-left__group">
<div class="global-nav-left__title">
@T("PlatformTools")
</div>
<div>
@if (_recommendApps == null)
{
<MSkeletonLoader Class="transparent" Type="list-item@3" />
}
else
{
foreach (var item in _recommendApps)
{
<MListItem Dense
Class="mb-1 full-width rounded-2 masa-text-2-2"
Href="@item.Value">
<MListItemContent>
<MListItemTitle>@DT(item.Key)</MListItemTitle>
</MListItemContent>
</MListItem>
}
}
</div>
</div>
</div>
</div>
<div class="global-nav-right">
<div class="global-nav-header">
<div class="d-flex">
<span class="global-nav-header__title">@T("GlobalNavigation")</span>
<MSpacer />
<SSearch Dense Class="mr-6" ValueChanged="SearchChanged" />
<MButton Icon OnClick="() => _visible = false">
<MIcon>mdi-close</MIcon>
</MButton>
</div>
<div class="mt-4">
<span class="masa-text-3-1 mb-2">@T("RecentVisits")</span>

@if (_recentVisits == null)
{
<MSkeletonLoader Class="d-flex transparent" Type="chip@3" />
}
else
{
foreach (var (name, url) in _recentVisits)
{
<MChip Class="masa-text-2-1 ml-4" Color="#F6F8FD" OnClick="() => NavigateTo(url)">@DT(name)</MChip>
}
}
</div>
</div>
<div class="global-nav-content">
@if (_menu is null)
{
<MSkeletonLoader Type="image,image,image" Class="global-nav-content__loader"></MSkeletonLoader>
<MSkeletonLoader Type="image" Class="global-nav-content__toc-loader"></MSkeletonLoader>
}
else
{
<ExpansionMenuWrapper Value="_menu" OnItemClick="MenuItemClickAsync" OnItemOperClick="MenuItemOperClickAsync" />
}
</div>
</div>
</div>
</MCard>
</ChildContent>
</MDialog>


@code {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
// Copyright (c) MASA Stack All rights reserved.
// Licensed under the Apache License. See LICENSE.txt in the project root for license information.

namespace Masa.Auth.Web.Admin.Rcl.Pages.Component.Subjects;

public partial class ImpersonatedNavigation : AdminCompontentBase
{
private const string MENU_URL_NAME = "url";

[Parameter]
public Guid UserId { get; set; }

[Parameter]
public RenderFragment<ActivatorProps> ActivatorContent { get; set; } = null!;

[Parameter]
public Func<string, Task>? OnFavoriteAdd { get; set; }

[Parameter]
public Func<string, Task>? OnFavoriteRemove { get; set; }

bool _visible;
private List<(string name, string url)>? _recentVisits;
private List<KeyValuePair<string, string>>? _recommendApps;
private List<ExpansionMenu> _favorites = new();
ExpansionMenu? _menu;
string impersonationToken = string.Empty;

private async Task GetMenuAndFavorites()
{
_menu = await GenerateMenuAsync();
_favorites = _menu.GetMenusByStates(ExpansionMenuState.Favorite) ?? new();
StateHasChanged();
}

private async Task GetRecommendApps()
{
//TODO pm config
var recommendAppIdentities = new List<string>()
{
MasaStackConfig.GetWebId(MasaStackProject.PM), MasaStackConfig.GetWebId(MasaStackProject.DCC),
MasaStackConfig.GetWebId(MasaStackProject.Auth)
};
var environment = MultiEnvironmentUserContext.Environment;
if (environment.IsNullOrEmpty())
{
environment = WebHostEnvironment.EnvironmentName;
}

var projects = await PmClient.ProjectService.GetProjectAppsAsync(environment);
_recommendApps = projects.SelectMany(p => p.Apps).Where(a => recommendAppIdentities.Contains(a.Identity))
.Select(a => new KeyValuePair<string, string>(a.Name, a.Url)).ToList();

StateHasChanged();
}

private async Task GetImpersonationToken()
{
var impersonate = await AuthClient.UserService.ImpersonateAsync(UserId);
if (impersonate != null)
{
impersonationToken = impersonate.ImpersonationToken;
}
}

private void VisibleChanged(bool visible)
{
if (visible && _menu == null)
{
_ = GetRecommendApps();
_ = GetRecentVisits();
_ = GetMenuAndFavorites();
}

if (visible && string.IsNullOrEmpty(impersonationToken))
{
_ = GetImpersonationToken();
}

_visible = visible;
}

private void SearchChanged(string? search)
{
_menu?.SetHiddenBySearch(search, TranslateProvider);
}

private void MenuItemClickAsync(ExpansionMenu menu)
{
var url = menu.GetData(MENU_URL_NAME);
if (string.IsNullOrWhiteSpace(url))
{
return;
}

NavigateTo(url);
}

private async Task MenuItemOperClickAsync(ExpansionMenu menu)
{
if (menu.State == ExpansionMenuState.Normal)
{
await FavoriteRemoveAsync(menu);
}
else if (menu.State == ExpansionMenuState.Favorite)
{
await FavoriteAddAsync(menu);
}
}

private async Task<ExpansionMenu> GenerateMenuAsync()
{
var menu = ExpansionMenu.CreateRootMenu(ExpansionMenuSituation.Favorite);
try
{
var apps = (await AuthClient.ProjectService.GetGlobalNavigations()).SelectMany(p => p.Apps).ToList();
var categories = apps.GroupBy(a => a.Tag).ToList();
var favorites = await FetchFavorites();

foreach (var category in categories)
{
var categoryMenu = new ExpansionMenu(category.Key, category.Key, ExpansionMenuType.Category, ExpansionMenuState.Normal, menu.MetaData,
parent: menu);
foreach (var app in category.Where(a => a.Navs.Any()))
{
var appMenu = new ExpansionMenu(app.Id.ToString(), app.Name, ExpansionMenuType.App, ExpansionMenuState.Normal, menu.MetaData,
parent: categoryMenu);
foreach (var nav in app.Navs)
{
appMenu.AddChild(ConvertForNav(nav, appMenu.Deep + 1, appMenu, favorites));
}

categoryMenu.AddChild(appMenu);
}

menu.AddChild(categoryMenu);
}
}
catch
{
}

return menu;
}

private ExpansionMenu ConvertForNav(NavModel navModel, int deep, ExpansionMenu parent, List<string> favorites)
{
var state = favorites.Any(favorite => favorite == navModel.Code) ? ExpansionMenuState.Favorite : ExpansionMenuState.Normal;
var menu = new ExpansionMenu(navModel.Code, navModel.Name, ExpansionMenuType.Nav, state, parent.MetaData, parent: parent)
.AddData(MENU_URL_NAME, navModel.Url);
foreach (var childrenNav in navModel.Children)
{
menu.AddChild(ConvertForNav(childrenNav, deep++, menu, favorites));
}

menu.Disabled = menu.Children.Count > 0;
return menu;
}

private async Task<List<string>> FetchFavorites()
{
return (await AuthClient.PermissionService.GetFavoriteMenuListAsync())
.Select(m => m.Value.ToString()).ToList();
}

private async Task GetRecentVisits()
{
var visitedList = await AuthClient.UserService.GetVisitedListAsync();
_recentVisits = visitedList.Select(v => new ValueTuple<string, string>(v.Name, v.Url)).ToList();

StateHasChanged();
}

private void NavigateTo(string? url)
{
if (url is null)
{
return;
}

if (url.IndexOf("http") > -1)
{
UriBuilder uriBuilder = new UriBuilder(url);
uriBuilder.Query = $"impersonationToken={impersonationToken}";
url = uriBuilder.Uri.ToString();
}
NavigationManager.NavigateTo(url, forceLoad: true);
}

private async Task FavoriteRemoveAsync(ExpansionMenu nav)
{
var favoriteNav = _favorites.FirstOrDefault(e => e.Id == nav.Id);
if (favoriteNav == null)
{
return;
}

_favorites.Remove(favoriteNav);
if (OnFavoriteRemove != null)
{
await OnFavoriteRemove.Invoke(favoriteNav.Id);
}
}

private async Task FavoriteAddAsync(ExpansionMenu nav)
{
if (_favorites.Any(e => e.Id == nav.Id))
{
return;
}

_favorites.Add(nav);
if (OnFavoriteAdd != null)
{
await OnFavoriteAdd.Invoke(nav.Id);
}
}

private async Task OnOutsideClick()
{
var a = 1;
}
}
Loading

0 comments on commit af90dab

Please sign in to comment.