AiBot Tenantlı ve MenuManager düzenlendi
This commit is contained in:
parent
50cb3eaf97
commit
b53a4243ab
4 changed files with 108 additions and 12 deletions
|
|
@ -6,6 +6,7 @@ using Volo.Abp.Application.Services;
|
|||
using Volo.Abp.Domain.Repositories;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Sozsoft.Platform.AiBots;
|
||||
|
||||
|
|
@ -25,16 +26,31 @@ public class AiBotAppService : CrudAppService<
|
|||
{
|
||||
await CheckGetListPolicyAsync();
|
||||
|
||||
var query = await CreateFilteredQueryAsync(input);
|
||||
|
||||
if (CurrentTenant.IsAvailable && !string.IsNullOrWhiteSpace(CurrentTenant.Name))
|
||||
{
|
||||
var tenantName = CurrentTenant.Name;
|
||||
query = query.Where(aiBot =>
|
||||
string.IsNullOrWhiteSpace(aiBot.Tenants) ||
|
||||
aiBot.Tenants.Contains($"\"{tenantName}\""));
|
||||
List<AiBot> tenantEntities;
|
||||
|
||||
using (CurrentTenant.Change(null))
|
||||
{
|
||||
var hostQuery = await CreateFilteredQueryAsync(input);
|
||||
tenantEntities = await AsyncExecuter.ToListAsync(hostQuery);
|
||||
}
|
||||
|
||||
var filteredQuery = tenantEntities
|
||||
.Where(aiBot => IsAvailableForTenant(aiBot.Tenants, tenantName))
|
||||
.AsQueryable();
|
||||
|
||||
var tenantTotalCount = filteredQuery.LongCount();
|
||||
filteredQuery = ApplySorting(filteredQuery, input);
|
||||
filteredQuery = ApplyPaging(filteredQuery, input);
|
||||
|
||||
var tenantDtos = await MapToGetListOutputDtosAsync(filteredQuery.ToList());
|
||||
|
||||
return new PagedResultDto<AiBotDto>(tenantTotalCount, tenantDtos);
|
||||
}
|
||||
|
||||
var query = await CreateFilteredQueryAsync(input);
|
||||
var totalCount = await AsyncExecuter.CountAsync(query);
|
||||
query = ApplySorting(query, input);
|
||||
query = ApplyPaging(query, input);
|
||||
|
|
@ -44,5 +60,17 @@ public class AiBotAppService : CrudAppService<
|
|||
|
||||
return new PagedResultDto<AiBotDto>(totalCount, dtos);
|
||||
}
|
||||
|
||||
private static bool IsAvailableForTenant(string tenants, string tenantName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(tenants))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return tenants
|
||||
.Split('|', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Any(name => string.Equals(name, tenantName, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useSortable } from '@dnd-kit/sortable'
|
||||
import { CSS } from '@dnd-kit/utilities'
|
||||
import { MenuItem } from '@/proxy/menus/menu'
|
||||
|
|
@ -19,7 +19,7 @@ import {
|
|||
import { Field, FieldProps, Form, Formik } from 'formik'
|
||||
import { SelectBoxOption } from '@/types/shared'
|
||||
import * as Yup from 'yup'
|
||||
import { FaQuestionCircle, FaPlus, FaTrashAlt } from 'react-icons/fa'
|
||||
import { FaChevronDown, FaChevronRight, FaQuestionCircle, FaPlus, FaTrashAlt } from 'react-icons/fa'
|
||||
import { MenuDto } from '@/proxy/menus/models'
|
||||
|
||||
interface MenuItemComponentProps {
|
||||
|
|
@ -30,6 +30,7 @@ interface MenuItemComponentProps {
|
|||
isDragOverlay?: boolean
|
||||
refetch: () => void
|
||||
permissions: SelectBoxOption[]
|
||||
expansionCommand: { expanded: boolean; version: number }
|
||||
}
|
||||
|
||||
export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
|
||||
|
|
@ -40,6 +41,7 @@ export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
|
|||
isDragOverlay = false,
|
||||
refetch,
|
||||
permissions,
|
||||
expansionCommand,
|
||||
}) => {
|
||||
const { translate } = useLocalization()
|
||||
|
||||
|
|
@ -75,6 +77,10 @@ export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
|
|||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const [modalMode, setModalMode] = useState<'create' | 'edit'>('create')
|
||||
|
||||
useEffect(() => {
|
||||
setIsExpanded(expansionCommand.expanded)
|
||||
}, [expansionCommand.expanded, expansionCommand.version])
|
||||
|
||||
const getCreateInitialValues = (): Partial<MenuDto> => ({
|
||||
code: '',
|
||||
displayName: '',
|
||||
|
|
@ -106,8 +112,9 @@ export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
|
|||
|
||||
const [formData, setFormData] = useState<Partial<MenuDto>>(getCreateInitialValues())
|
||||
|
||||
const toggleExpanded = () => {
|
||||
if (!isDesignMode) setIsExpanded(!isExpanded)
|
||||
const toggleExpanded = (event?: React.MouseEvent) => {
|
||||
event?.stopPropagation()
|
||||
setIsExpanded((current) => !current)
|
||||
}
|
||||
|
||||
const openCreateModal = () => {
|
||||
|
|
@ -146,6 +153,23 @@ export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
|
|||
`}
|
||||
{...(isDesignMode ? { ...attributes, ...listeners } : { onClick: toggleExpanded })}
|
||||
>
|
||||
{isDesignMode &&
|
||||
(item.children && item.children.length > 0 ? (
|
||||
<Button
|
||||
aria-label={isExpanded ? 'Collapse menu item' : 'Expand menu item'}
|
||||
className="!h-6 !w-6 !px-0"
|
||||
icon={isExpanded ? <FaChevronDown size={12} /> : <FaChevronRight size={12} />}
|
||||
shape="circle"
|
||||
size="xs"
|
||||
title={isExpanded ? 'Collapse' : 'Expand'}
|
||||
variant="plain"
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
onClick={toggleExpanded}
|
||||
/>
|
||||
) : (
|
||||
<span aria-hidden="true" className="h-6 w-6 flex-shrink-0" />
|
||||
))}
|
||||
|
||||
{isDesignMode && (
|
||||
<div className="flex gap-2 items-center mr-2">
|
||||
<Button
|
||||
|
|
@ -220,7 +244,7 @@ export const MenuItemComponent: React.FC<MenuItemComponentProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{children && (!isDesignMode ? isExpanded : true) && <div className="mt-1">{children}</div>}
|
||||
{children && isExpanded && <div className="mt-1">{children}</div>}
|
||||
|
||||
{isModalOpen && (
|
||||
<Dialog
|
||||
|
|
|
|||
|
|
@ -1,7 +1,14 @@
|
|||
import { useState } from 'react'
|
||||
import { SortableMenuTree } from './SortableMenuTree'
|
||||
import { useMenuData } from '@/utils/hooks/useMenuData'
|
||||
import { FaRegBell, FaSpinner, FaBars, FaRegSave } from 'react-icons/fa'
|
||||
import {
|
||||
FaRegBell,
|
||||
FaSpinner,
|
||||
FaBars,
|
||||
FaRegSave,
|
||||
FaChevronRight,
|
||||
FaChevronDown,
|
||||
} from 'react-icons/fa'
|
||||
import { Container } from '@/components/shared'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
|
|
@ -12,6 +19,7 @@ export const MenuManager = () => {
|
|||
const { menuItems, setMenuItems, loading, error, refetch, saveMenuData } = useMenuData()
|
||||
const [isDesignMode, setIsDesignMode] = useState(true)
|
||||
const [isSaving, setIsSaving] = useState(false)
|
||||
const [expansionCommand, setExpansionCommand] = useState({ expanded: true, version: 0 })
|
||||
const { translate } = useLocalization()
|
||||
|
||||
const handleSave = async () => {
|
||||
|
|
@ -33,6 +41,10 @@ export const MenuManager = () => {
|
|||
setIsDesignMode((current) => !current)
|
||||
}
|
||||
|
||||
const setAllExpanded = (expanded: boolean) => {
|
||||
setExpansionCommand((current) => ({ expanded, version: current.version + 1 }))
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex items-center justify-center">
|
||||
|
|
@ -113,6 +125,27 @@ export const MenuManager = () => {
|
|||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="plain"
|
||||
className="!h-auto !rounded-lg !px-2 !py-1"
|
||||
icon={<FaChevronRight size={10} />}
|
||||
onClick={() => setAllExpanded(true)}
|
||||
>
|
||||
{translate('::ListForms.ListFormEdit.ExpandAll')}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="plain"
|
||||
className="!h-auto !rounded-lg !px-2 !py-1"
|
||||
icon={<FaChevronDown size={10} />}
|
||||
onClick={() => setAllExpanded(false)}
|
||||
>
|
||||
{translate('::ListForms.ListFormEdit.CollapseAll')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
disabled={!isDesignMode || isSaving}
|
||||
size="sm"
|
||||
|
|
@ -141,6 +174,7 @@ export const MenuManager = () => {
|
|||
|
||||
{menuItems.length > 0 ? (
|
||||
<SortableMenuTree
|
||||
expansionCommand={expansionCommand}
|
||||
items={menuItems}
|
||||
isDesignMode={isDesignMode}
|
||||
refetch={refetch}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ interface SortableMenuTreeProps {
|
|||
onItemsChange: (items: MenuItem[]) => void
|
||||
isDesignMode: boolean
|
||||
refetch: () => void
|
||||
expansionCommand: { expanded: boolean; version: number }
|
||||
}
|
||||
|
||||
export const SortableMenuTree: React.FC<SortableMenuTreeProps> = ({
|
||||
|
|
@ -33,6 +34,7 @@ export const SortableMenuTree: React.FC<SortableMenuTreeProps> = ({
|
|||
onItemsChange,
|
||||
isDesignMode,
|
||||
refetch,
|
||||
expansionCommand,
|
||||
}) => {
|
||||
const [permissions, setPermissions] = useState<SelectBoxOption[]>([])
|
||||
const [activeItem, setActiveItem] = React.useState<MenuItem | null>(null)
|
||||
|
|
@ -193,7 +195,14 @@ export const SortableMenuTree: React.FC<SortableMenuTreeProps> = ({
|
|||
const renderMenuItem = (item: MenuItem, depth: number = 0): React.ReactNode => {
|
||||
return (
|
||||
<div key={item.id} className="bg-white dark:bg-gray-800 rounded-md">
|
||||
<MenuItemComponent item={item} isDesignMode={isDesignMode} depth={depth} refetch={refetch} permissions={permissions}>
|
||||
<MenuItemComponent
|
||||
item={item}
|
||||
isDesignMode={isDesignMode}
|
||||
depth={depth}
|
||||
refetch={refetch}
|
||||
permissions={permissions}
|
||||
expansionCommand={expansionCommand}
|
||||
>
|
||||
{Array.isArray(item.children) && item.children.length > 0 && (
|
||||
<SortableContext
|
||||
items={item.children
|
||||
|
|
@ -230,6 +239,7 @@ export const SortableMenuTree: React.FC<SortableMenuTreeProps> = ({
|
|||
isDragOverlay={true}
|
||||
refetch={refetch}
|
||||
permissions={permissions}
|
||||
expansionCommand={expansionCommand}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
|||
Loading…
Reference in a new issue