feat: 實現版本號自動化更新與修復側邊欄 RWD 問題
This commit is contained in:
@@ -92,6 +92,10 @@ jobs:
|
|||||||
key: ${{ secrets.DEMO_SSH_KEY }}
|
key: ${{ secrets.DEMO_SSH_KEY }}
|
||||||
script: |
|
script: |
|
||||||
docker exec -u 1000:1000 -w /var/www/html star-erp-laravel sh -c "
|
docker exec -u 1000:1000 -w /var/www/html star-erp-laravel sh -c "
|
||||||
|
# 0. 更新版本號 (使用 Git Hash)
|
||||||
|
VERSION=\"v1.0-\$(git rev-parse --short HEAD)\"
|
||||||
|
sed -i \"s/^APP_VERSION=.*/APP_VERSION=\$VERSION/\" .env || echo \"APP_VERSION=\$VERSION\" >> .env
|
||||||
|
|
||||||
# 1. 後端依賴 (Demo 環境建議加上 --no-interaction 避免卡住)
|
# 1. 後端依賴 (Demo 環境建議加上 --no-interaction 避免卡住)
|
||||||
composer install --no-dev --optimize-autoloader --no-interaction &&
|
composer install --no-dev --optimize-autoloader --no-interaction &&
|
||||||
|
|
||||||
@@ -191,6 +195,10 @@ jobs:
|
|||||||
echo "容器狀態:" && docker ps --filter "name=star-erp-laravel"
|
echo "容器狀態:" && docker ps --filter "name=star-erp-laravel"
|
||||||
|
|
||||||
docker exec -u 1000:1000 -w /var/www/html star-erp-laravel sh -c "
|
docker exec -u 1000:1000 -w /var/www/html star-erp-laravel sh -c "
|
||||||
|
# 0. 更新版本號
|
||||||
|
VERSION=\"v1.0-\$(git rev-parse --short HEAD)\"
|
||||||
|
sed -i \"s/^APP_VERSION=.*/APP_VERSION=\$VERSION/\" .env || echo \"APP_VERSION=\$VERSION\" >> .env
|
||||||
|
|
||||||
composer install --no-dev --optimize-autoloader &&
|
composer install --no-dev --optimize-autoloader &&
|
||||||
npm install &&
|
npm install &&
|
||||||
npm run build
|
npm run build
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class HandleInertiaRequests extends Middleware
|
|||||||
return [
|
return [
|
||||||
...parent::share($request),
|
...parent::share($request),
|
||||||
'appName' => $appName,
|
'appName' => $appName,
|
||||||
|
'app_version' => config('app.version'),
|
||||||
'auth' => [
|
'auth' => [
|
||||||
'user' => $user ? [
|
'user' => $user ? [
|
||||||
'id' => $user->id,
|
'id' => $user->id,
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ return [
|
|||||||
|
|
||||||
'name' => env('APP_NAME', 'Laravel'),
|
'name' => env('APP_NAME', 'Laravel'),
|
||||||
|
|
||||||
|
'version' => env('APP_VERSION', '1.0.0'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Application Environment
|
| Application Environment
|
||||||
|
|||||||
@@ -386,13 +386,15 @@ export default function AuthenticatedLayout({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderMenuItem = (item: MenuItem, level: number = 0) => {
|
const renderMenuItem = (item: MenuItem, level: number = 0, forceExpand: boolean = false) => {
|
||||||
const hasChildren = item.children && item.children.length > 0;
|
const hasChildren = item.children && item.children.length > 0;
|
||||||
const isExpanded = expandedItems.includes(item.id);
|
const isExpanded = expandedItems.includes(item.id);
|
||||||
const isActive = item.route
|
const isActive = item.route
|
||||||
? (item.route === '/' ? url === '/' : url.startsWith(item.route))
|
? (item.route === '/' ? url === '/' : url.startsWith(item.route))
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
|
const effectivelyCollapsed = isCollapsed && !forceExpand;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={item.id} className="mb-1">
|
<div key={item.id} className="mb-1">
|
||||||
{hasChildren ? (
|
{hasChildren ? (
|
||||||
@@ -401,21 +403,21 @@ export default function AuthenticatedLayout({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"w-full flex items-center transition-all rounded-lg group",
|
"w-full flex items-center transition-all rounded-lg group",
|
||||||
level === 0 ? "px-3 py-2.5" : "px-3 py-2 pl-10",
|
level === 0 ? "px-3 py-2.5" : "px-3 py-2 pl-10",
|
||||||
level === 0 && !isCollapsed && "hover:bg-slate-100",
|
level === 0 && !effectivelyCollapsed && "hover:bg-slate-100",
|
||||||
isCollapsed && level === 0 && "justify-center px-0 h-10 w-10 mx-auto hover:bg-slate-100"
|
effectivelyCollapsed && level === 0 && "justify-center px-0 h-10 w-10 mx-auto hover:bg-slate-100"
|
||||||
)}
|
)}
|
||||||
title={isCollapsed ? item.label : ""}
|
title={effectivelyCollapsed ? item.label : ""}
|
||||||
>
|
>
|
||||||
{level === 0 && (
|
{level === 0 && (
|
||||||
<span className={cn(
|
<span className={cn(
|
||||||
"flex-shrink-0 transition-all",
|
"flex-shrink-0 transition-all",
|
||||||
isCollapsed ? "mr-0" : "mr-3 text-slate-500 group-hover:text-slate-900"
|
effectivelyCollapsed ? "mr-0" : "mr-3 text-slate-500 group-hover:text-slate-900"
|
||||||
)}>
|
)}>
|
||||||
{item.icon}
|
{item.icon}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isCollapsed && (
|
{!effectivelyCollapsed && (
|
||||||
<>
|
<>
|
||||||
<span className="flex-1 text-left text-base font-medium text-slate-700 group-hover:text-slate-900 truncate">
|
<span className="flex-1 text-left text-base font-medium text-slate-700 group-hover:text-slate-900 truncate">
|
||||||
{item.label}
|
{item.label}
|
||||||
@@ -438,22 +440,22 @@ export default function AuthenticatedLayout({
|
|||||||
className={cn(
|
className={cn(
|
||||||
"w-full flex items-center transition-all rounded-lg group",
|
"w-full flex items-center transition-all rounded-lg group",
|
||||||
level === 0 ? "px-3 py-2.5" : "px-3 py-2",
|
level === 0 ? "px-3 py-2.5" : "px-3 py-2",
|
||||||
level > 0 && !isCollapsed && "pl-11",
|
level > 0 && !effectivelyCollapsed && "pl-11",
|
||||||
isActive ? "bg-primary-lightest text-primary-main" : "text-slate-600 hover:bg-slate-100 hover:text-slate-900",
|
isActive ? "bg-primary-lightest text-primary-main" : "text-slate-600 hover:bg-slate-100 hover:text-slate-900",
|
||||||
isCollapsed && level === 0 && "justify-center px-0 h-10 w-10 mx-auto"
|
effectivelyCollapsed && level === 0 && "justify-center px-0 h-10 w-10 mx-auto"
|
||||||
)}
|
)}
|
||||||
title={isCollapsed ? item.label : ""}
|
title={effectivelyCollapsed ? item.label : ""}
|
||||||
>
|
>
|
||||||
{item.icon && (
|
{item.icon && (
|
||||||
<span className={cn(
|
<span className={cn(
|
||||||
"flex-shrink-0 transition-all",
|
"flex-shrink-0 transition-all",
|
||||||
isCollapsed ? "mr-0" : "mr-3",
|
effectivelyCollapsed ? "mr-0" : "mr-3",
|
||||||
isActive ? "text-primary-main" : "text-slate-500 group-hover:text-slate-900"
|
isActive ? "text-primary-main" : "text-slate-500 group-hover:text-slate-900"
|
||||||
)}>
|
)}>
|
||||||
{item.icon}
|
{item.icon}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!isCollapsed && (
|
{!effectivelyCollapsed && (
|
||||||
<span className="text-base font-medium truncate">
|
<span className="text-base font-medium truncate">
|
||||||
{item.label}
|
{item.label}
|
||||||
</span>
|
</span>
|
||||||
@@ -461,9 +463,9 @@ export default function AuthenticatedLayout({
|
|||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{hasChildren && isExpanded && !isCollapsed && (
|
{hasChildren && isExpanded && !effectivelyCollapsed && (
|
||||||
<div className="mt-1 space-y-1">
|
<div className="mt-1 space-y-1">
|
||||||
{item.children?.map((child) => renderMenuItem(child, level + 1))}
|
{item.children?.map((child) => renderMenuItem(child, level + 1, forceExpand))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -573,7 +575,7 @@ export default function AuthenticatedLayout({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-4 border-t border-slate-100 flex items-center justify-between">
|
<div className="p-4 border-t border-slate-100 flex items-center justify-between">
|
||||||
{!isCollapsed && <p className="text-[10px] font-medium text-slate-400 uppercase tracking-wider px-2">Version 1.0.0</p>}
|
{!isCollapsed && <p className="text-[10px] font-medium text-slate-400 uppercase tracking-wider px-2">Version {props.app_version || '1.0.0'}</p>}
|
||||||
<button
|
<button
|
||||||
onClick={() => setIsCollapsed(!isCollapsed)}
|
onClick={() => setIsCollapsed(!isCollapsed)}
|
||||||
className={cn(
|
className={cn(
|
||||||
@@ -613,7 +615,7 @@ export default function AuthenticatedLayout({
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex-1 overflow-y-auto p-4" scroll-region="true">
|
<div className="flex-1 overflow-y-auto p-4" scroll-region="true">
|
||||||
<nav className="space-y-1">
|
<nav className="space-y-1">
|
||||||
{menuItems.map((item) => renderMenuItem(item))}
|
{menuItems.map((item) => renderMenuItem(item, 0, true))}
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { Head, router } from '@inertiajs/react';
|
|||||||
import { PageProps } from '@/types/global';
|
import { PageProps } from '@/types/global';
|
||||||
import Pagination from '@/Components/shared/Pagination';
|
import Pagination from '@/Components/shared/Pagination';
|
||||||
import { SearchableSelect } from "@/Components/ui/searchable-select";
|
import { SearchableSelect } from "@/Components/ui/searchable-select";
|
||||||
import { FileText, Search, RotateCcw, Calendar, ChevronDown, ChevronUp } from 'lucide-react';
|
import { FileText, Search, RotateCcw, Calendar } from 'lucide-react';
|
||||||
import LogTable, { Activity } from '@/Components/ActivityLog/LogTable';
|
import LogTable, { Activity } from '@/Components/ActivityLog/LogTable';
|
||||||
import ActivityDetailDialog from '@/Components/ActivityLog/ActivityDetailDialog';
|
import ActivityDetailDialog from '@/Components/ActivityLog/ActivityDetailDialog';
|
||||||
import { Button } from '@/Components/ui/button';
|
import { Button } from '@/Components/ui/button';
|
||||||
@@ -57,10 +57,7 @@ export default function ActivityLogIndex({ activities, filters, subject_types, u
|
|||||||
const [causer, setCauser] = useState(filters.causer_id || 'all');
|
const [causer, setCauser] = useState(filters.causer_id || 'all');
|
||||||
const [dateRangeType, setDateRangeType] = useState('custom');
|
const [dateRangeType, setDateRangeType] = useState('custom');
|
||||||
|
|
||||||
// Advanced Filter Toggle
|
|
||||||
const [showAdvancedFilter, setShowAdvancedFilter] = useState(
|
|
||||||
!!(filters.date_start || filters.date_end)
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleDateRangeChange = (type: string) => {
|
const handleDateRangeChange = (type: string) => {
|
||||||
setDateRangeType(type);
|
setDateRangeType(type);
|
||||||
@@ -161,75 +158,12 @@ export default function ActivityLogIndex({ activities, filters, subject_types, u
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 篩選區塊 */}
|
{/* 篩選區塊 */}
|
||||||
<div className="bg-white p-5 rounded-lg shadow-sm border border-grey-4 mb-6">
|
<div className="bg-white rounded-xl shadow-sm border border-grey-4 p-5 mb-6">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-4 mb-4">
|
<div className="space-y-4">
|
||||||
{/* 關鍵字搜尋 */}
|
{/* Top Config: Date Range & Quick Buttons */}
|
||||||
<div className="md:col-span-4 space-y-1">
|
<div className="flex flex-col lg:flex-row gap-4 lg:items-end">
|
||||||
<Label className="text-xs font-medium text-grey-1">關鍵字搜尋</Label>
|
<div className="flex-none space-y-2">
|
||||||
<div className="relative">
|
<Label className="text-xs font-medium text-grey-2">快速時間區間</Label>
|
||||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
|
|
||||||
<Input
|
|
||||||
placeholder="搜尋描述、內容..."
|
|
||||||
value={search}
|
|
||||||
onChange={(e) => setSearch(e.target.value)}
|
|
||||||
className="pl-10 h-9 block"
|
|
||||||
onKeyDown={(e) => e.key === 'Enter' && handleFilter()}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 事件類型 */}
|
|
||||||
<div className="md:col-span-2 space-y-1">
|
|
||||||
<Label className="text-xs font-medium text-grey-1">事件類型</Label>
|
|
||||||
<Select value={event} onValueChange={setEvent}>
|
|
||||||
<SelectTrigger className="h-9">
|
|
||||||
<SelectValue placeholder="所有事件" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="all">所有事件</SelectItem>
|
|
||||||
<SelectItem value="created">新增 (Created)</SelectItem>
|
|
||||||
<SelectItem value="updated">更新 (Updated)</SelectItem>
|
|
||||||
<SelectItem value="deleted">刪除 (Deleted)</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 操作對象 */}
|
|
||||||
<div className="md:col-span-3 space-y-1">
|
|
||||||
<Label className="text-xs font-medium text-grey-1">操作對象</Label>
|
|
||||||
<SearchableSelect
|
|
||||||
value={subjectType}
|
|
||||||
onValueChange={setSubjectType}
|
|
||||||
options={[
|
|
||||||
{ label: "所有對象", value: "all" },
|
|
||||||
...subject_types
|
|
||||||
]}
|
|
||||||
placeholder="選擇對象"
|
|
||||||
className="w-full h-9"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 操作人員 */}
|
|
||||||
<div className="md:col-span-3 space-y-1">
|
|
||||||
<Label className="text-xs font-medium text-grey-1">操作人員</Label>
|
|
||||||
<SearchableSelect
|
|
||||||
value={causer}
|
|
||||||
onValueChange={setCauser}
|
|
||||||
options={[
|
|
||||||
{ label: "所有人員", value: "all" },
|
|
||||||
...users
|
|
||||||
]}
|
|
||||||
placeholder="選擇人員"
|
|
||||||
className="w-full h-9"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Row 2: Date Filters (Collapsible) */}
|
|
||||||
{showAdvancedFilter && (
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-4 items-end animate-in fade-in slide-in-from-top-2 duration-200">
|
|
||||||
<div className="md:col-span-6 space-y-2">
|
|
||||||
<Label className="text-xs font-medium text-grey-1">快速時間區間</Label>
|
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{[
|
{[
|
||||||
{ label: "今日", value: "today" },
|
{ label: "今日", value: "today" },
|
||||||
@@ -254,10 +188,11 @@ export default function ActivityLogIndex({ activities, filters, subject_types, u
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="md:col-span-6">
|
{/* Date Inputs */}
|
||||||
<div className="grid grid-cols-2 gap-4 items-end">
|
<div className="w-full lg:flex-1">
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label className="text-xs font-medium text-grey-2">開始日期</Label>
|
<Label className="text-xs text-grey-2 font-medium">開始日期</Label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Calendar className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
|
<Calendar className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
|
||||||
<Input
|
<Input
|
||||||
@@ -267,13 +202,12 @@ export default function ActivityLogIndex({ activities, filters, subject_types, u
|
|||||||
setDateStart(e.target.value);
|
setDateStart(e.target.value);
|
||||||
setDateRangeType('custom');
|
setDateRangeType('custom');
|
||||||
}}
|
}}
|
||||||
// block w-full to ensure it fills space
|
|
||||||
className="pl-9 block w-full h-9 bg-white"
|
className="pl-9 block w-full h-9 bg-white"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label className="text-xs font-medium text-grey-2">結束日期</Label>
|
<Label className="text-xs text-grey-2 font-medium">結束日期</Label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Calendar className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
|
<Calendar className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400 pointer-events-none" />
|
||||||
<Input
|
<Input
|
||||||
@@ -290,45 +224,90 @@ export default function ActivityLogIndex({ activities, filters, subject_types, u
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Action Bar */}
|
{/* Detailed Filters row */}
|
||||||
<div className="flex items-center justify-end border-t border-grey-4 pt-5 gap-3 mt-4">
|
<div className="grid grid-cols-1 md:grid-cols-12 gap-4 items-end">
|
||||||
<Button
|
{/* 事件類型 */}
|
||||||
variant="ghost"
|
<div className="md:col-span-2 space-y-1">
|
||||||
size="sm"
|
<Label className="text-xs font-medium text-grey-2">事件類型</Label>
|
||||||
onClick={() => setShowAdvancedFilter(!showAdvancedFilter)}
|
<Select value={event} onValueChange={setEvent}>
|
||||||
className="mr-auto text-gray-500 hover:text-gray-900 h-9"
|
<SelectTrigger className="h-9 bg-white">
|
||||||
>
|
<SelectValue placeholder="所有事件" />
|
||||||
{showAdvancedFilter ? (
|
</SelectTrigger>
|
||||||
<>
|
<SelectContent>
|
||||||
<ChevronUp className="h-4 w-4 mr-1" />
|
<SelectItem value="all">所有事件</SelectItem>
|
||||||
收合篩選
|
<SelectItem value="created">新增 (Created)</SelectItem>
|
||||||
</>
|
<SelectItem value="updated">更新 (Updated)</SelectItem>
|
||||||
) : (
|
<SelectItem value="deleted">刪除 (Deleted)</SelectItem>
|
||||||
<>
|
</SelectContent>
|
||||||
<ChevronDown className="h-4 w-4 mr-1" />
|
</Select>
|
||||||
進階篩選
|
</div>
|
||||||
{(dateStart || dateEnd) && (
|
|
||||||
<span className="ml-2 w-2 h-2 rounded-full bg-primary-main" />
|
{/* 操作對象 */}
|
||||||
)}
|
<div className="md:col-span-2 space-y-1">
|
||||||
</>
|
<Label className="text-xs font-medium text-grey-2">操作對象</Label>
|
||||||
)}
|
<SearchableSelect
|
||||||
</Button>
|
value={subjectType}
|
||||||
|
onValueChange={setSubjectType}
|
||||||
|
options={[
|
||||||
|
{ label: "所有對象", value: "all" },
|
||||||
|
...subject_types
|
||||||
|
]}
|
||||||
|
placeholder="選擇對象"
|
||||||
|
className="w-full h-9 bg-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 操作人員 */}
|
||||||
|
<div className="md:col-span-2 space-y-1">
|
||||||
|
<Label className="text-xs font-medium text-grey-2">操作人員</Label>
|
||||||
|
<SearchableSelect
|
||||||
|
value={causer}
|
||||||
|
onValueChange={setCauser}
|
||||||
|
options={[
|
||||||
|
{ label: "所有人員", value: "all" },
|
||||||
|
...users
|
||||||
|
]}
|
||||||
|
placeholder="選擇人員"
|
||||||
|
className="w-full h-9 bg-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 關鍵字搜尋 */}
|
||||||
|
<div className="md:col-span-3 space-y-1">
|
||||||
|
<Label className="text-xs font-medium text-grey-2">關鍵字搜尋</Label>
|
||||||
|
<div className="relative">
|
||||||
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-gray-400" />
|
||||||
|
<Input
|
||||||
|
placeholder="搜尋內容..."
|
||||||
|
value={search}
|
||||||
|
onChange={(e) => setSearch(e.target.value)}
|
||||||
|
className="pl-10 h-9 block bg-white"
|
||||||
|
onKeyDown={(e) => e.key === 'Enter' && handleFilter()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Action Buttons Integrated */}
|
||||||
|
<div className="md:col-span-3 flex items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={handleReset}
|
onClick={handleReset}
|
||||||
className="flex items-center gap-2 button-outlined-primary h-9"
|
className="flex-1 items-center gap-2 button-outlined-primary h-9"
|
||||||
>
|
>
|
||||||
<RotateCcw className="h-4 w-4" />
|
<RotateCcw className="h-4 w-4" />
|
||||||
重置
|
重置
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleFilter} className="button-filled-primary h-9 px-6 gap-2">
|
<Button
|
||||||
<Search className="h-4 w-4" />
|
onClick={handleFilter}
|
||||||
查詢
|
className="flex-1 button-filled-primary h-9 gap-2 shadow-sm"
|
||||||
|
>
|
||||||
|
<Search className="h-4 w-4" /> 查詢
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<LogTable
|
<LogTable
|
||||||
activities={activities.data}
|
activities={activities.data}
|
||||||
|
|||||||
1
resources/js/types/global.d.ts
vendored
1
resources/js/types/global.d.ts
vendored
@@ -28,6 +28,7 @@ export interface PageProps {
|
|||||||
error?: string;
|
error?: string;
|
||||||
};
|
};
|
||||||
branding?: Branding | null;
|
branding?: Branding | null;
|
||||||
|
app_version?: string;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user