Compare commits

...
Author SHA1 Message Date
guoyuqi f986d0f283 fix: container list search 2026-10-16 10:02:16 +08:00
107 changed files with 1175 additions and 296 deletions
+1
View File
@@ -266,6 +266,7 @@ func (b *BaseApi) GetLoginSetting(c *gin.Context) {
Language: settingInfo.Language,
MenuTabs: settingInfo.MenuTabs,
MenuAccordion: settingInfo.MenuAccordion,
PanelCache: settingInfo.PanelCache,
PanelName: settingInfo.PanelName,
Theme: settingInfo.Theme,
NeedCaptcha: needCaptcha,
+13
View File
@@ -4,6 +4,16 @@ import (
"time"
)
const DefaultPanelCache = `{"tabs":true,"pagination":true,"refresh":true,"search":false,"duration":"24h"}`
type PanelCache struct {
Tabs *bool `json:"tabs"`
Pagination *bool `json:"pagination"`
Refresh *bool `json:"refresh"`
Search *bool `json:"search"`
Duration string `json:"duration"`
}
type SettingInfo struct {
SystemVersion string `json:"systemVersion"`
DeveloperMode string `json:"developerMode"`
@@ -18,6 +28,7 @@ type SettingInfo struct {
Theme string `json:"theme"`
MenuTabs string `json:"menuTabs"`
MenuAccordion string `json:"menuAccordion"`
PanelCache string `json:"panelCache"`
Language string `json:"language"`
DocSource string `json:"docSource"`
@@ -62,6 +73,7 @@ type SettingBaseInfo struct {
Theme string `json:"theme"`
MenuTabs string `json:"menuTabs"`
MenuAccordion string `json:"menuAccordion"`
PanelCache string `json:"panelCache"`
Language string `json:"language"`
HideMenu string `json:"hideMenu"`
DocSource string `json:"docSource"`
@@ -288,6 +300,7 @@ type LoginSetting struct {
Language string `json:"language"`
MenuTabs string `json:"menuTabs"`
MenuAccordion string `json:"menuAccordion"`
PanelCache string `json:"panelCache"`
PanelName string `json:"panelName"`
Theme string `json:"theme"`
NeedCaptcha bool `json:"needCaptcha"`
+27
View File
@@ -120,6 +120,9 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
for _, set := range setting {
settingMap[set.Key] = set.Value
}
if settingMap["PanelCache"] == "" {
settingMap["PanelCache"] = dto.DefaultPanelCache
}
repairAndSortHideMenu(settingMap)
var info dto.SettingInfo
arr, err := json.Marshal(settingMap)
@@ -155,6 +158,9 @@ func (u *SettingService) GetSettingBaseInfo() (*dto.SettingBaseInfo, error) {
for _, set := range setting {
settingMap[set.Key] = set.Value
}
if settingMap["PanelCache"] == "" {
settingMap["PanelCache"] = dto.DefaultPanelCache
}
repairAndSortHideMenu(settingMap)
var info dto.SettingBaseInfo
arr, err := json.Marshal(settingMap)
@@ -224,6 +230,27 @@ func (u *SettingService) Update(c *gin.Context, key, value string) error {
if auth.IsAPICredentialSetting(key) {
return buserr.New("ErrInvalidParams")
}
if key == "PanelCache" {
var config dto.PanelCache
decoder := json.NewDecoder(strings.NewReader(value))
decoder.DisallowUnknownFields()
if err := decoder.Decode(&config); err != nil {
return buserr.New("ErrInvalidParams")
}
if err := decoder.Decode(new(any)); err != io.EOF {
return buserr.New("ErrInvalidParams")
}
if config.Tabs == nil || config.Pagination == nil || config.Refresh == nil || config.Search == nil {
return buserr.New("ErrInvalidParams")
}
switch config.Duration {
case "24h", "week", "month", "forever":
default:
return buserr.New("ErrInvalidParams")
}
data, _ := json.Marshal(config)
return settingRepo.UpdateOrCreate(key, string(data))
}
oldVal, err := settingRepo.Get(repo.WithByKey(key))
if err != nil {
return err
+1
View File
@@ -26,6 +26,7 @@ func Init() {
}
var baseSettingKeys = map[string]struct{}{
"PanelCache": {},
"PanelName": {},
"Theme": {},
"MenuTabs": {},
+1
View File
@@ -77,6 +77,7 @@ export namespace Login {
language: string;
menuTabs: string;
menuAccordion: string;
panelCache: string;
panelName: string;
theme: string;
isOffline: boolean;
+2
View File
@@ -41,6 +41,7 @@ export namespace Setting {
theme: string;
menuTabs: string;
menuAccordion: string;
panelCache: string;
language: string;
docSource: string;
@@ -86,6 +87,7 @@ export namespace Setting {
theme: string;
menuTabs: string;
menuAccordion: string;
panelCache: string;
language: string;
hideMenu: string;
docSource: string;
+43 -45
View File
@@ -20,57 +20,55 @@
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue';
import { onActivated, onDeactivated, onMounted, onUnmounted, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { panelCacheKey, readPanelCache, writePanelCache } from '@/utils/panel-cache';
defineOptions({ name: 'TableSetting' });
const refreshRateUnit = ref<number>(0);
const refreshRateUnit = ref(0);
const emit = defineEmits(['search']);
const props = defineProps({
title: String,
rate: Number,
});
let timer: NodeJS.Timer | null = null;
const changeRefresh = (command: number) => {
refreshRateUnit.value = command || 0;
if (refreshRateUnit.value !== 0) {
if (timer) {
clearInterval(Number(timer));
timer = null;
}
timer = setInterval(() => {
emit('search');
}, 1000 * refreshRateUnit.value);
} else {
if (timer) {
clearInterval(Number(timer));
timer = null;
}
}
localStorage.setItem(props.title, refreshRateUnit.value + '');
const props = defineProps({ title: String, rate: Number });
const route = useRoute();
// Capture the owning page; useRoute continues to change while a page is deactivated.
const pagePath = route.path;
const cacheKey = () => panelCacheKey(`refresh:${pagePath}:${props.title || ''}`);
let timer: ReturnType<typeof setInterval> | undefined;
let active = false;
const stopTimer = () => {
clearInterval(timer);
timer = undefined;
};
onUnmounted(() => {
clearInterval(Number(timer));
timer = null;
if (props.title) {
localStorage.setItem(props.title, refreshRateUnit.value + '');
const startTimer = () => {
stopTimer();
if (active && refreshRateUnit.value > 0) {
timer = setInterval(() => emit('search'), 1000 * refreshRateUnit.value);
}
};
const restore = () => {
const rate = readPanelCache<number>('refresh', cacheKey());
refreshRateUnit.value = Number.isFinite(rate) && rate >= 0 ? rate : props.rate || 0;
startTimer();
};
const changeRefresh = (rate: number) => {
refreshRateUnit.value = rate;
writePanelCache('refresh', cacheKey(), rate);
startTimer();
};
const activate = () => {
if (active) return;
active = true;
restore();
};
watch(cacheKey, () => {
if (active) restore();
});
onMounted(() => {
if (props.title && localStorage.getItem(props.title) != null) {
let rate = Number(localStorage.getItem(props.title));
refreshRateUnit.value = rate ? Number(rate) : 0;
changeRefresh(refreshRateUnit.value);
return;
}
if (props.rate) {
refreshRateUnit.value = props.rate;
changeRefresh(refreshRateUnit.value);
}
onMounted(activate);
onActivated(activate);
onDeactivated(() => {
active = false;
stopTimer();
});
onUnmounted(stopTimer);
</script>
<style lang="scss" scoped>
@@ -167,6 +167,7 @@
</div>
</template>
<script setup lang="ts">
import { panelCacheKey, writePanelCache } from '@/utils/panel-cache';
import { computed, onDeactivated, onMounted, ref, useAttrs } from 'vue';
import { useGlobalStore } from '@/composables/useGlobalStore';
import { flattenVNodes, type FuTableOperationButton } from '@/components/table/shared';
@@ -341,13 +342,33 @@ const handleRightClick = (row, column, event) => {
openContextMenu(row, event);
};
watch(
() => props.data,
() => {
const pagination = props.paginationConfig;
if (!pagination || !pagination.pageSize) return;
const lastPage = Math.max(1, Math.ceil(pagination.total / pagination.pageSize));
if (pagination.currentPage > lastPage) {
pagination.currentPage = lastPage;
emit('search');
}
},
{ flush: 'post' },
);
function currentChange() {
emit('search');
}
function sizeChange() {
if (props.paginationConfig.cacheSizeKey) {
writePanelCache(
'pagination',
panelCacheKey(`size:${props.paginationConfig.cacheSizeKey}`),
props.paginationConfig.pageSize,
);
}
props.paginationConfig.currentPage = 1;
localStorage.setItem(props.paginationConfig.cacheSizeKey, props.paginationConfig.pageSize);
emit('search');
}
+2 -1
View File
@@ -52,6 +52,7 @@
</template>
<script setup lang="ts">
import { readCachedPageSize } from '@/utils/panel-cache';
import TaskLog from '@/components/log/task/index.vue';
import NodeSelect from '@/components/node-select/index.vue';
@@ -73,7 +74,7 @@ const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'task-list-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('task-list-page-size')) || 20,
pageSize: readCachedPageSize('task-list-page-size') || 20,
total: 0,
small: true,
});
@@ -1,24 +0,0 @@
import { storeToRefs } from 'pinia';
import { onActivated, onDeactivated } from 'vue';
import GlobalStore from '@/store/modules/global';
import { bindSearchReset, type SearchFields } from '@/utils/search-reset';
interface SearchResetOptions {
scope?: () => string | number | undefined;
onRevisit: () => unknown;
}
export const useSearchReset = (fields: SearchFields, options: SearchResetOptions) => {
const { currentNode } = storeToRefs(GlobalStore());
const reset = bindSearchReset(options.scope ? [currentNode, options.scope] : [currentNode], fields);
let deactivated = false;
onDeactivated(() => {
deactivated = true;
});
onActivated(() => {
if (!deactivated) return;
deactivated = false;
reset();
return options.onRevisit();
});
};
+14
View File
@@ -2962,6 +2962,20 @@ const message = {
remote: 'Remote SSH',
},
setting: {
panelCache: {
title: 'Cache settings',
tabs: 'Tab cache',
pagination: 'Pagination cache',
refresh: 'Refresh interval cache',
search: 'Search input cache',
duration: 'Cache duration',
'24h': '24h',
week: 'One week',
month: 'One month',
forever: 'Forever',
helper: 'Expires after the last state change. Expired values return to page defaults.',
},
panel: 'Panel',
user: 'Panel user',
userChange: 'Change panel user',
+14
View File
@@ -3007,6 +3007,20 @@ const message = {
remote: 'SSH remoto',
},
setting: {
panelCache: {
title: 'Configuración de caché',
tabs: 'Caché de pestañas',
pagination: 'Caché de paginación',
refresh: 'Caché del intervalo de actualización',
search: 'Caché del campo de búsqueda',
duration: 'Duración de la caché',
'24h': '24 horas',
week: 'Una semana',
month: 'Un mes',
forever: 'Permanente',
helper: 'El plazo se calcula desde el último cambio de estado. Al caducar, se restablecen los valores predeterminados.',
},
panel: 'Panel',
user: 'Usuario del panel',
userChange: 'Cambiar usuario del panel',
+14
View File
@@ -2932,6 +2932,20 @@ const message = {
remote: 'SSH از راه دور',
},
setting: {
panelCache: {
title: 'تنظیمات حافظهٔ نهان',
tabs: 'حافظهٔ نهان زبانه‌ها',
pagination: 'حافظهٔ نهان صفحه‌بندی',
refresh: 'حافظهٔ نهان فاصلهٔ بازخوانی',
search: 'حافظهٔ نهان ورودی جستجو',
duration: 'مدت نگهداری حافظهٔ نهان',
'24h': '۲۴ ساعت',
week: 'یک هفته',
month: 'یک ماه',
forever: 'دائمی',
helper: 'مدت اعتبار از آخرین تغییر وضعیت محاسبه می‌شود. پس از انقضا، مقادیر پیش‌فرض بازیابی می‌شوند.',
},
panel: 'پنل',
user: 'کاربر پنل',
userChange: 'تغییر کاربر پنل',
+14
View File
@@ -2937,6 +2937,20 @@ const message = {
remote: 'リモートSSH',
},
setting: {
panelCache: {
title: 'キャッシュ設定',
tabs: 'タブのキャッシュ',
pagination: 'ページネーションのキャッシュ',
refresh: '更新間隔のキャッシュ',
search: '検索入力のキャッシュ',
duration: 'キャッシュ期間',
'24h': '24時間',
week: '1週間',
month: '1か月',
forever: '無期限',
helper: '有効期間は状態を最後に変更した時点から計算されます。期限が切れると既定値に戻ります。',
},
panel: 'パネル',
user: 'パネルユーザー',
userChange: 'パネルユーザーを変更します',
+14
View File
@@ -2898,6 +2898,20 @@ const message = {
remote: '원격 SSH',
},
setting: {
panelCache: {
title: '캐시 설정',
tabs: '탭 캐시',
pagination: '페이지 이동 캐시',
refresh: '새로 고침 간격 캐시',
search: '검색 입력 캐시',
duration: '캐시 유지 기간',
'24h': '24시간',
week: '1주',
month: '1개월',
forever: '무기한',
helper: '유효 기간은 상태를 마지막으로 변경한 시점부터 계산됩니다. 만료되면 기본값으로 돌아갑니다.',
},
panel: '패널',
user: '패널 사용자',
userChange: '패널 사용자 변경',
+14
View File
@@ -2879,6 +2879,20 @@ const message = {
remote: 'SSH ທາງໄກ',
},
setting: {
panelCache: {
title: 'ການຕັ້ງຄ່າແຄດ',
tabs: 'ແຄດແຖບ',
pagination: 'ແຄດການແບ່ງໜ້າ',
refresh: 'ແຄດຊ່ວງເວລາຣີເຟຣຊ',
search: 'ແຄດຂໍ້ຄວາມຄົ້ນຫາ',
duration: 'ໄລຍະເວລາເກັບແຄດ',
'24h': '24 ຊົ່ວໂມງ',
week: 'ໜຶ່ງອາທິດ',
month: 'ໜຶ່ງເດືອນ',
forever: 'ຖາວອນ',
helper: 'ໄລຍະເວລາຈະນັບຈາກການປ່ຽນສະຖານະຄັ້ງຫຼ້າສຸດ. ເມື່ອໝົດອາຍຸ ຈະກັບຄືນເປັນຄ່າເລີ່ມຕົ້ນ.',
},
panel: 'ພາເນລ',
user: 'ຜູ້ໃຊ້ພາເນລ',
userChange: 'ປ່ຽນຜູ້ໃຊ້ພາເນລ',
+14
View File
@@ -3005,6 +3005,20 @@ const message = {
remote: 'SSH jauh',
},
setting: {
panelCache: {
title: 'Tetapan cache',
tabs: 'Cache tab',
pagination: 'Cache halaman',
refresh: 'Cache sela penyegaran',
search: 'Cache input carian',
duration: 'Tempoh cache',
'24h': '24 jam',
week: 'Satu minggu',
month: 'Satu bulan',
forever: 'Kekal',
helper: 'Tempoh sah dikira dari perubahan keadaan terakhir. Selepas tamat tempoh, nilai lalai dipulihkan.',
},
panel: 'Panel',
user: 'Pengguna panel',
userChange: 'Tukar pengguna panel',
+14
View File
@@ -3004,6 +3004,20 @@ const message = {
remote: 'SSH remoto',
},
setting: {
panelCache: {
title: 'Configurações de cache',
tabs: 'Cache de abas',
pagination: 'Cache de paginação',
refresh: 'Cache do intervalo de atualização',
search: 'Cache do campo de pesquisa',
duration: 'Duração do cache',
'24h': '24 horas',
week: 'Uma semana',
month: 'Um mês',
forever: 'Permanente',
helper: 'O prazo é contado a partir da última alteração de estado. Após a expiração, os valores padrão são restaurados.',
},
panel: 'Painel',
user: 'Usuário do painel',
userChange: 'Alterar usuário do painel',
+14
View File
@@ -2977,6 +2977,20 @@ const message = {
remote: 'Удаленный SSH',
},
setting: {
panelCache: {
title: 'Настройки кэша',
tabs: 'Кэш вкладок',
pagination: 'Кэш пагинации',
refresh: 'Кэш интервала обновления',
search: 'Кэш поискового запроса',
duration: 'Срок хранения кэша',
'24h': '24 часа',
week: 'Одна неделя',
month: 'Один месяц',
forever: 'Бессрочно',
helper: 'Срок хранения отсчитывается с последнего изменения состояния. После его истечения восстанавливаются значения по умолчанию.',
},
panel: 'Панель',
user: 'Пользователь панели',
userChange: 'Изменить пользователя панели',
+14
View File
@@ -2995,6 +2995,20 @@ const message = {
remote: 'Uzak SSH',
},
setting: {
panelCache: {
title: 'Önbellek ayarları',
tabs: 'Sekme önbelleği',
pagination: 'Sayfalama önbelleği',
refresh: 'Yenileme aralığı önbelleği',
search: 'Arama alanı önbelleği',
duration: 'Önbellek süresi',
'24h': '24 saat',
week: 'Bir hafta',
month: 'Bir ay',
forever: 'Süresiz',
helper: 'Geçerlilik süresi son durum değişikliğinden itibaren hesaplanır. Süre dolduğunda varsayılan değerler geri yüklenir.',
},
panel: 'Panel',
user: 'Panel kullanıcısı',
userChange: 'Panel kullanıcısını değiştir',
+14
View File
@@ -2786,6 +2786,20 @@ const message = {
stopSSHWarn: '是否斷開此SSH連接',
},
setting: {
panelCache: {
title: '快取設定',
tabs: '標籤頁快取',
pagination: '分頁快取',
refresh: '重新整理頻率快取',
search: '搜尋輸入框快取',
duration: '快取時間',
'24h': '24h',
week: '一週',
month: '一個月',
forever: '永久',
helper: '有效期從狀態最後一次修改開始計算;過期後恢復預設值。',
},
panel: '面板',
user: '面板使用者',
userChange: '修改面板使用者',
+14
View File
@@ -2817,6 +2817,20 @@ const message = {
stopSSHWarn: '是否断开此SSH连接',
},
setting: {
panelCache: {
title: '缓存设置',
tabs: '标签页缓存',
pagination: '翻页缓存',
refresh: '刷新频率缓存',
search: '搜索输入框缓存',
duration: '缓存时间',
'24h': '24h',
week: '一周',
month: '一月',
forever: '永久',
helper: '有效期从状态最后一次修改开始计算;过期后恢复默认值。',
},
panel: '面板',
user: '面板用户',
userChange: '修改面板用户',
@@ -55,6 +55,7 @@
</template>
<script setup lang="ts">
import { applyPanelCacheSettings } from '@/utils/panel-cache';
import { ref, computed, onBeforeUnmount, onMounted, watch } from 'vue';
import { RouteRecordRaw, useRoute, useRouter } from 'vue-router';
import { loadingSvg } from '@/utils/svg';
@@ -141,6 +142,7 @@ const search = async () => {
settingInfo = res.data;
version.value = res.data.systemVersion;
menuAccordion.value = res.data.menuAccordion === 'Enable';
applyPanelCacheSettings(res.data.panelCache);
} catch (error) {
version.value = '';
}
+4
View File
@@ -54,6 +54,7 @@
</template>
<script setup lang="ts">
import { prunePanelCache } from '@/utils/panel-cache';
import { onMounted, computed, ref, watch, onBeforeUnmount } from 'vue';
import { Sidebar, Footer, AppMain, MobileHeader, Tabs } from './components';
import TerminalHost from '@/components/terminal/host.vue';
@@ -106,6 +107,7 @@ const loadingText = computed(() =>
);
let timer: NodeJS.Timer | null = null;
let cacheCleanupTimer: ReturnType<typeof setInterval> | undefined;
const classObj = computed(() => {
return {
@@ -186,10 +188,12 @@ const loadStatus = async () => {
}
};
onBeforeUnmount(() => {
clearInterval(cacheCleanupTimer);
clearInterval(Number(timer));
timer = null;
});
onMounted(() => {
cacheCleanupTimer = setInterval(() => prunePanelCache(), 300000);
if (openMenuTabs.value && !tabsStore.activeTabPath) {
handleMenuClick('/');
}
+22 -10
View File
@@ -1,3 +1,4 @@
import { panelCacheKey, readPanelCache, writePanelCache, removePanelCache, prunePanelCache } from '@/utils/panel-cache';
import router from '@/routers/router';
import NProgress from '@/config/nprogress';
import { useGlobalStore } from '@/composables/useGlobalStore';
@@ -102,29 +103,34 @@ router.beforeEach(async (to, from) => {
if (to.name === 'Expired') {
return true;
}
const activeMenuKey = 'cachedRoute' + (to.meta.activeMenu || '');
const activeMenuKey = panelCacheKey(String(to.meta.activeMenu || ''));
if (to.query.uncached != undefined) {
const query = { ...to.query };
delete query.uncached;
localStorage.removeItem(activeMenuKey);
removePanelCache('tabs', activeMenuKey);
return { path: to.path, query };
}
const cachedRoute = localStorage.getItem(activeMenuKey);
const cachedRoute = readPanelCache<string>('tabs', activeMenuKey);
if (
to.meta.activeMenu &&
to.meta.activeMenu != from.meta.activeMenu &&
typeof cachedRoute === 'string' &&
cachedRoute &&
cachedRoute !== to.path &&
!isRedirecting
) {
const cachedRouteInfo = router.resolve(cachedRoute);
if (cachedRouteInfo.matched.length > 0 && hasRouteAccess(cachedRouteInfo)) {
if (
cachedRouteInfo.matched.length > 0 &&
cachedRouteInfo.meta.activeMenu === to.meta.activeMenu &&
hasRouteAccess(cachedRouteInfo)
) {
isRedirecting = true;
NProgress.done();
return cachedRoute;
}
localStorage.removeItem(activeMenuKey);
removePanelCache('tabs', activeMenuKey);
}
if (!hasRouteAccess(to)) {
@@ -135,7 +141,13 @@ router.beforeEach(async (to, from) => {
return true;
});
router.afterEach((to) => {
router.afterEach((to, _from, failure) => {
prunePanelCache();
if (failure) {
isRedirecting = false;
NProgress.done();
return;
}
if (to.meta.activeMenu && !to.meta.ignoreTab && !isRedirecting) {
let notMathParam = true;
if (to.matched.some((record) => record.path.includes(':'))) {
@@ -143,13 +155,13 @@ router.afterEach((to) => {
}
if (notMathParam) {
if (to.meta.activeMenu === '/cronjobs' && to.path === '/cronjobs/cronjob/operate') {
localStorage.setItem('cachedRoute' + to.meta.activeMenu, '/cronjobs/cronjob');
writePanelCache('tabs', panelCacheKey(String(to.meta.activeMenu)), '/cronjobs/cronjob');
} else if (to.meta.activeMenu === '/containers' && to.path === '/containers/container/operate') {
localStorage.setItem('cachedRoute' + to.meta.activeMenu, '/containers/container');
writePanelCache('tabs', panelCacheKey(String(to.meta.activeMenu)), '/containers/container');
} else if (to.meta.activeMenu === '/toolbox' && to.path === '/toolbox/clam/setting') {
localStorage.setItem('cachedRoute' + to.meta.activeMenu, '/toolbox/clam');
writePanelCache('tabs', panelCacheKey(String(to.meta.activeMenu)), '/toolbox/clam');
} else {
localStorage.setItem('cachedRoute' + to.meta.activeMenu, to.path);
writePanelCache('tabs', panelCacheKey(String(to.meta.activeMenu)), to.path);
}
}
}
+3
View File
@@ -1,5 +1,6 @@
import { RouteRecordRaw } from 'vue-router';
import { DeviceType } from '@/enums/app';
import type { PanelCacheSettings } from '@/utils/panel-cache';
export interface ThemeConfigProp {
panelName: string;
primary: string;
@@ -34,6 +35,8 @@ export interface GlobalState {
isFullScreen: boolean;
openMenuTabs: boolean;
menuAccordion: boolean;
panelCache: PanelCacheSettings;
cacheUserID: string;
watermark: Watermark | null;
watermarkShow: boolean;
isLoading: boolean;
+4
View File
@@ -6,6 +6,7 @@ import { DeviceType } from '@/enums/app';
import i18n, { setActiveLocale } from '@/lang';
import { isMasterOnlyPermissionCode, setMasterOnlyPermissionCodes, toManageCode } from '@/utils/permission-codes';
import { clearPageStateCache } from '@/utils/page-state-cache';
import { defaultPanelCache } from '@/utils/panel-cache';
const CN_DOCS_URL = 'https://docs.fit2cloud.com/1panel';
const INTL_DOCS_URL = 'https://1panel.pro/docs/v2';
@@ -33,6 +34,8 @@ const GlobalStore = defineStore('GlobalState', {
isFullScreen: false,
openMenuTabs: false,
menuAccordion: false,
panelCache: { ...defaultPanelCache },
cacheUserID: '',
watermark: null,
watermarkShow: false,
isLoading: false,
@@ -123,6 +126,7 @@ const GlobalStore = defineStore('GlobalState', {
},
clearAuthInfo() {
clearPageStateCache();
this.cacheUserID = '';
this.permissions = [];
this.masterOnlyPermissions = [];
this.nodeRoles = [];
+4 -5
View File
@@ -1,6 +1,5 @@
import { bindSearchReset } from '@/utils/search-reset';
import router from '@/routers/router';
import { useGlobalStore } from '@/composables/useGlobalStore';
import { bindSearchState } from '@/utils/search-reset';
import { panelCacheKey } from '@/utils/panel-cache';
import { defineStore } from 'pinia';
import { ref, reactive, toRef } from 'vue';
import { MsgError } from '@/utils/message';
@@ -49,8 +48,7 @@ export const ProcessStore = defineStore('ProcessStore', () => {
port: undefined,
});
const { currentNode } = useGlobalStore();
bindSearchReset([() => router.currentRoute.value.path, currentNode], {
const searchState = bindSearchState(() => panelCacheKey('host/process'), {
pid: toRef(psSearch, 'pid'),
name: toRef(psSearch, 'name'),
username: toRef(psSearch, 'username'),
@@ -321,6 +319,7 @@ export const ProcessStore = defineStore('ProcessStore', () => {
};
return {
restoreSearchState: searchState.restore,
isConnected,
isConnecting,
psData,
+130
View File
@@ -0,0 +1,130 @@
import GlobalStore from '@/store/modules/global';
export type CacheCategory = 'tabs' | 'pagination' | 'refresh' | 'search';
export interface PanelCacheSettings {
tabs: boolean;
pagination: boolean;
refresh: boolean;
search: boolean;
duration: '24h' | 'week' | 'month' | 'forever';
}
export const defaultPanelCache: PanelCacheSettings = {
tabs: true,
pagination: true,
refresh: true,
search: false,
duration: '24h',
};
const categories: CacheCategory[] = ['tabs', 'pagination', 'refresh', 'search'];
const durations = { '24h': 86400000, week: 604800000, month: 2592000000, forever: Infinity };
const prefix = '1panel:page-cache:v1:';
interface CacheEntry {
category: CacheCategory;
updatedAt: number;
value: unknown;
}
export const applyPanelCacheSettings = (raw: string) => {
let value: Partial<PanelCacheSettings> = {};
try {
value = JSON.parse(raw) || {};
} catch {
// Older servers do not return this setting yet.
}
const settings = { ...defaultPanelCache };
for (const category of categories) {
if (typeof value[category] === 'boolean') settings[category] = value[category];
}
if (Object.hasOwn(durations, value.duration || '')) settings.duration = value.duration;
const store = GlobalStore();
const changed =
settings.duration !== store.panelCache.duration ||
categories.some((category) => settings[category] !== store.panelCache[category]);
if (changed) store.panelCache = settings;
// Repeated settings loads share the normal cleanup interval.
prunePanelCache(changed);
};
export const panelCacheKey = (key: string): string => {
const { cacheUserID, currentNode } = GlobalStore();
return JSON.stringify([cacheUserID, currentNode, key]);
};
const storageKey = (category: CacheCategory, key: string) => prefix + JSON.stringify([category, key]);
const validEntry = (entry: CacheEntry, settings: PanelCacheSettings, now: number) => {
return (
entry &&
categories.includes(entry.category) &&
settings[entry.category] &&
Number.isFinite(entry.updatedAt) &&
entry.updatedAt <= now &&
now - entry.updatedAt < durations[settings.duration]
);
};
export const readPanelCache = <T>(category: CacheCategory, key: string): T | undefined => {
const store = GlobalStore();
if (!store.cacheUserID || !store.panelCache[category]) return;
try {
const target = storageKey(category, key);
const raw = localStorage.getItem(target);
if (!raw) return;
const entry: CacheEntry = JSON.parse(raw);
if (entry.category === category && validEntry(entry, store.panelCache, Date.now())) return entry.value as T;
localStorage.removeItem(target);
} catch {
// Storage can be unavailable or contain invalid data; use page defaults.
}
};
export const writePanelCache = (category: CacheCategory, key: string, value: unknown) => {
const store = GlobalStore();
if (!store.cacheUserID || !store.panelCache[category]) return;
try {
// Repeated visits and unchanged values must not extend the expiration time.
const previous = readPanelCache(category, key);
if (previous !== undefined && JSON.stringify(previous) === JSON.stringify(value)) return;
localStorage.setItem(storageKey(category, key), JSON.stringify({ category, updatedAt: Date.now(), value }));
} catch {
// A full or disabled localStorage must not block page interactions.
}
};
export const removePanelCache = (category: CacheCategory, key: string) => {
try {
localStorage.removeItem(storageKey(category, key));
} catch {
/* Storage is optional. */
}
};
let lastPruned = 0;
export const prunePanelCache = (force = false) => {
const now = Date.now();
if (!force && now - lastPruned < 300000) return;
lastPruned = now;
const settings = GlobalStore().panelCache;
try {
for (let index = localStorage.length - 1; index >= 0; index--) {
const key = localStorage.key(index);
if (!key) continue;
if (key.startsWith('1panel:search-state:v2:') || key.startsWith('cachedRoute')) {
// Legacy entries have neither ownership nor timestamps and cannot be safely restored.
localStorage.removeItem(key);
} else if (key.startsWith(prefix)) {
try {
if (validEntry(JSON.parse(localStorage.getItem(key)), settings, now)) continue;
} catch {
/* Remove malformed entries too. */
}
localStorage.removeItem(key);
}
}
} catch {
/* Storage is optional. */
}
};
export const readCachedPageSize = (key: string): number | undefined => {
const value = readPanelCache<number>('pagination', panelCacheKey(`size:${key}`));
return Number.isInteger(value) && value > 0 ? value : undefined;
};
+2
View File
@@ -22,6 +22,7 @@ export const syncAuthInfo = async (currentNode?: string) => {
const storeCurrentNode = globalStore.currentNode;
if (!globalStore.isEnterprise) {
const res = await getUserInfo();
globalStore.cacheUserID = `community:${res.data.id}`;
globalStore.setAuthInfo({
isAdmin: res.data.role === 'ADMIN',
permissions: res.data.permissions || [],
@@ -31,6 +32,7 @@ export const syncAuthInfo = async (currentNode?: string) => {
return res.data;
}
const res = await getEnterpriseUserInfo(currentNode ?? storeCurrentNode);
globalStore.cacheUserID = `enterprise:${res.data.id}`;
globalStore.setAuthInfo({
isAdmin: res.data.role === 'ADMIN',
permissions: res.data.permissions || [],
+160 -7
View File
@@ -1,12 +1,165 @@
import { watch, type Ref, type WatchSource } from 'vue';
import { storeToRefs } from 'pinia';
import { nextTick, onActivated, onDeactivated, onScopeDispose, watch, type Ref } from 'vue';
import { panelCacheKey, readPanelCache, writePanelCache } from '@/utils/panel-cache';
import GlobalStore from '@/store/modules/global';
export type SearchFields = Record<string, Ref<string | number | undefined>>;
type SearchValues = Record<string, string | number | undefined>;
export const bindSearchReset = (sources: WatchSource[], fields: SearchFields) => {
const defaults = Object.values(fields).map((field) => ({ field, value: field.value }));
const reset = () => {
for (const { field, value } of defaults) field.value = value;
// Keep categories separate so changing search text does not renew pagination's lifetime.
const searchStorage = {
save(key: string, values: SearchValues) {
for (const category of ['search', 'pagination'] as const) {
const entries = Object.entries(values).filter(
([name]) => (name === 'page' || name === 'pageSize') === (category === 'pagination'),
);
if (entries.length) {
writePanelCache(
category,
key,
Object.fromEntries(entries.map(([name, value]) => [name, value ?? null])),
);
}
}
},
read(key: string): SearchValues {
const values = {
...readPanelCache<SearchValues>('search', key),
...readPanelCache<SearchValues>('pagination', key),
};
watch(sources, reset, { flush: 'sync' });
return reset;
return Object.fromEntries(
Object.entries(values)
.filter(
([, value]) =>
value === null ||
typeof value === 'string' ||
(typeof value === 'number' && Number.isFinite(value)),
)
.map(([name, value]) => [name, value === null ? undefined : value]),
);
},
};
export const bindSearchState = (key: () => string | undefined, fields: SearchFields, storage = searchStorage) => {
const defaults = Object.fromEntries(Object.entries(fields).map(([name, field]) => [name, field.value]));
const names = Object.keys(fields).sort((left, right) => Number(left === 'page') - Number(right === 'page'));
let pending: { key: string; values: SearchValues } | undefined;
let queued = false;
const flush = () => {
if (!pending) return;
const snapshot = pending;
pending = undefined;
storage.save(snapshot.key, snapshot.values);
};
let restoring = false;
let activeKey: string | undefined;
let active = true;
let resuming = false;
let resumeVersion = 0;
const pause = () => {
flush();
active = false;
resuming = false;
resumeVersion++;
};
onScopeDispose(pause);
const restore = () => {
// Commit the previous node/resource before restoring another one.
flush();
activeKey = key();
if (!activeKey) return;
const saved = storage.read(activeKey) || defaults;
restoring = true;
try {
// Restore pagination last: search/filter watchers may reset it to page one.
for (const name of names) {
const value = Object.hasOwn(saved, name) ? saved[name] : defaults[name];
const initial = defaults[name];
const invalidPage =
(name === 'page' || name === 'pageSize') &&
(typeof value !== 'number' || !Number.isInteger(value) || value < 1);
fields[name].value =
invalidPage || (initial !== undefined && value !== undefined && typeof value !== typeof initial)
? initial
: value;
}
} finally {
restoring = false;
}
};
watch(
key,
() => {
if (active || resuming) restore();
},
{ immediate: true, flush: 'sync' },
);
watch(
() => Object.fromEntries(Object.entries(fields).map(([name, field]) => [name, field.value])),
(values, previous) => {
if (restoring || !active || !activeKey) return;
const changed = Object.entries(values).filter(([name, value]) => value !== previous[name]);
const paginationChanged = changed.some(([name]) => name === 'page' || name === 'pageSize');
const searchChanged = changed.some(([name]) => name !== 'page' && name !== 'pageSize');
const snapshot = Object.fromEntries(
Object.entries(values).filter(([name]) =>
name === 'page' || name === 'pageSize' ? paginationChanged : searchChanged,
),
);
pending = { key: activeKey, values: { ...pending?.values, ...snapshot } };
if (queued) return;
queued = true;
queueMicrotask(() => {
queued = false;
flush();
});
},
{ flush: 'sync' },
);
return {
restore,
pause,
resume: async () => {
const version = ++resumeVersion;
resuming = true;
active = false;
restore();
const restoredKey = activeKey;
const page = fields.page?.value;
await nextTick();
if (version !== resumeVersion) return false;
// Search watchers may reset the page while restoring a changed query.
if (activeKey === restoredKey && fields.page && page !== undefined) fields.page.value = page;
active = true;
resuming = false;
return true;
},
};
};
interface SearchStateOptions {
scope?: () => string | number | undefined;
onRevisit: () => unknown;
}
/** Keep queries across page visits and reload data when a cached page becomes active. */
export const useSearchState = (page: string, fields: SearchFields, options: SearchStateOptions) => {
const { cacheUserID } = storeToRefs(GlobalStore());
const binding = bindSearchState(() => {
const scope = options.scope?.();
if (options.scope && scope === undefined) return undefined;
// Track account and node changes, including initial auth synchronisation.
if (!cacheUserID.value) return undefined;
return panelCacheKey(JSON.stringify([page, scope ?? '']));
}, fields);
let deactivated = false;
onDeactivated(() => {
deactivated = true;
binding.pause();
});
onActivated(async () => {
if (!deactivated) return;
deactivated = false;
if (await binding.resume()) return options.onRevisit();
});
};
+2
View File
@@ -1,3 +1,4 @@
import { applyPanelCacheSettings } from '@/utils/panel-cache';
import {
getLicenseStatus,
getMasterLicenseStatus,
@@ -86,6 +87,7 @@ const loadDataFromDB = async () => {
globalStore.entrance = res.data.securityEntrance;
globalStore.openMenuTabs = res.data.menuTabs === 'Enable';
globalStore.menuAccordion = res.data.menuAccordion === 'Enable';
applyPanelCacheSettings(res.data.panelCache);
};
export async function loadProductProFromDB() {
@@ -172,7 +172,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { computed, ref, watch } from 'vue';
import { Refresh, Search } from '@element-plus/icons-vue';
import { ElMessageBox } from 'element-plus';
@@ -193,7 +193,8 @@ const searching = ref(false);
const operating = ref('');
const keyword = ref('');
const marketKeyword = ref('');
useSearchReset(
useSearchState(
'ai/agents/agent/config/tabs/plugins',
{ keyword, marketKeyword },
{
scope: () => agentId.value || undefined,
@@ -138,7 +138,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { computed, ref, watch } from 'vue';
import { Refresh, Search } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
@@ -169,7 +169,8 @@ const getDefaultMarketSource = (): HermesSkillMarketSource => {
const marketSource = ref<HermesSkillMarketSource>(getDefaultMarketSource());
const marketSearched = ref(false);
const agentId = ref(0);
useSearchReset(
useSearchState(
'ai/agents/agent/config/tabs/skills/hermes',
{ installedKeyword, marketKeyword },
{
scope: () => agentId.value || undefined,
@@ -142,7 +142,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { computed, ref, watch } from 'vue';
import { Refresh, Search } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
@@ -181,7 +181,8 @@ const getDefaultMarketSource = (): SkillMarketSource => {
const marketSource = ref<SkillMarketSource>(getDefaultMarketSource());
const marketSearched = ref(false);
const agentId = ref(0);
useSearchReset(
useSearchState(
'ai/agents/agent/config/tabs/skills/openclaw',
{ installedKeyword, marketKeyword },
{
scope: () => agentId.value || undefined,
+6 -2
View File
@@ -272,7 +272,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { toRef, defineAsyncComponent, onMounted, reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { deleteAgentCheck, pageAgents, resetAgentToken, unbindAgentWebsite, updateAgentRemark } from '@/api/modules/ai';
@@ -400,7 +400,11 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'ai/agents/agent/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const checkNoApp = async () => {
try {
+6 -2
View File
@@ -69,7 +69,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { toRef, onMounted, reactive, ref } from 'vue';
import { deleteAgentAccount, getAgentProviders, pageAgentAccounts } from '@/api/modules/ai';
import { AI } from '@/api/interface/ai';
@@ -111,7 +111,11 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'ai/agents/model/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const search = async () => {
const req: AI.AgentAccountSearch = {
+11 -2
View File
@@ -98,6 +98,8 @@
</template>
<script lang="ts" setup>
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { AI } from '@/api/interface/ai';
import {
deleteMcpServer,
@@ -129,11 +131,18 @@ const bindDomainRef = ref();
const configRef = ref();
const items = ref<AI.McpServer[]>([]);
const paginationConfig = reactive({
cacheSizeKey: 'mcp-server-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('mcp-server-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'ai/mcp/server/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const getUrl = (row: AI.McpServer) => {
if (row.outputTransport == 'sse') {
+7 -4
View File
@@ -186,7 +186,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import AppStatus from '@/components/app-status/index.vue';
import AddDialog from '@/views/ai/model/ollama/add/index.vue';
import Conn from '@/views/ai/model/ollama/conn/index.vue';
@@ -231,13 +231,16 @@ const bindDomainRef = ref();
const taskLogRef = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'model-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('page-size')) || 20,
pageSize: 20,
total: 0,
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'ai/model/ollama/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const appInstallID = ref(0);
const opRef = ref();
@@ -77,6 +77,8 @@
</template>
<script lang="ts" setup>
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import OperateDialog from './operate/index.vue';
import ComposeLogs from '@/components/log/compose/index.vue';
import PortJumpDialog from '@/components/port-jump/index.vue';
@@ -101,6 +103,14 @@ const paginationConfig = reactive({
pageSize: 10,
total: 0,
});
useSearchState(
'ai/model/tensorrt/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const searchName = ref();
const opRef = ref();
const dialogRef = ref();
+9 -6
View File
@@ -70,7 +70,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { App } from '@/api/interface/app';
import { toRef, onMounted, reactive, ref } from 'vue';
import { searchApp, syncApp, syncCutomAppStore, syncLocalApp, getCurrentNodeCustomAppConfig } from '@/api/modules/app';
@@ -91,9 +91,8 @@ import { useGlobalStore } from '@/composables/useGlobalStore';
const { isProductPro, isOffline, isMobile, isEnterprise } = useGlobalStore();
const paginationConfig = reactive({
cacheSizeKey: 'app-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('app-page-size')) || 60,
pageSize: 60,
total: 0,
});
@@ -105,8 +104,13 @@ const req = reactive({
resource: 'all',
showCurrentArch: false,
});
useSearchReset(
{ search: toRef(req, 'name'), page: toRef(paginationConfig, 'currentPage') },
useSearchState(
'app-store/apps/index',
{
search: toRef(req, 'name'),
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search(req) },
);
@@ -133,7 +137,6 @@ const search = async (req: App.AppReq) => {
loading.value = true;
req.pageSize = paginationConfig.pageSize;
req.page = paginationConfig.currentPage;
localStorage.setItem('app-page-size', req.pageSize + '');
const customReq = {
page: req.page,
@@ -139,7 +139,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import AppCard from '@/views/app-store/installed/app/card.vue';
import Backups from '@/components/backup/index.vue';
import Uploads from '@/components/upload/index.vue';
@@ -181,9 +181,8 @@ const sortContainer = ref();
let sortableInstance: Sortable | null = null;
let timer: NodeJS.Timer | null = null;
const paginationConfig = reactive({
cacheSizeKey: 'app-installed-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('app-installed-page-size')) || 20,
pageSize: 20,
total: 0,
});
const open = ref(false);
@@ -211,8 +210,13 @@ const searchReq = reactive({
update: false,
sync: false,
});
useSearchReset(
{ search: toRef(searchReq, 'name'), page: toRef(paginationConfig, 'currentPage') },
useSearchState(
'app-store/installed/index',
{
search: toRef(searchReq, 'name'),
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const router = useRouter();
@@ -238,8 +242,6 @@ const search = async () => {
searchReq.page = paginationConfig.currentPage;
searchReq.pageSize = paginationConfig.pageSize;
localStorage.setItem('app-installed-page-size', String(searchReq.pageSize));
const res = await searchAppInstalled(searchReq);
data.value = res.data.items;
paginationConfig.total = res.data.total;
@@ -522,7 +522,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { computed, h, ref } from 'vue';
import CodemirrorPro from '@/components/codemirror-pro/index.vue';
import ContainerLog from '@/components/log/container/index.vue';
@@ -577,7 +577,7 @@ const dialogBackupRef = ref();
const uploadRef = ref();
const searchName = ref('');
useSearchReset({ search: searchName }, { onRevisit: () => search() });
useSearchState('container/compose/index', { search: searchName }, { onRevisit: () => search() });
const includeAppStore = ref(localStorage.getItem('includeAppStore') !== 'false');
const showType = ref('compose');
const containerStats = ref<any[]>([]);
@@ -474,7 +474,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import PruneDialog from '@/views/container/container/prune/index.vue';
import RenameDialog from '@/views/container/container/rename/index.vue';
import UpgradeDialog from '@/views/container/container/upgrade/index.vue';
@@ -527,16 +527,14 @@ const portFilter = ref('');
const showIPv6Ports = ref(true);
const selects = ref<any>([]);
const paginationConfig = reactive({
cacheSizeKey: 'container-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('container-page-size')) || 20,
pageSize: 20,
total: 0,
state: 'all',
orderBy: 'name',
order: 'ascending',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
const dialogUpgradeRef = ref();
const dialogCommitRef = ref();
const dialogPortJumpRef = ref();
@@ -552,6 +550,19 @@ const taskLogRef = ref();
const tags = ref([]);
const activeTag = ref('all');
useSearchState(
'container/container/index',
{
search: searchName,
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
state: toRef(paginationConfig, 'state'),
activeTag,
orderBy: toRef(paginationConfig, 'orderBy'),
order: toRef(paginationConfig, 'order'),
},
{ onRevisit: () => search() },
);
const activeDropdownContainerId = ref('');
const statFields = [
+9 -5
View File
@@ -157,7 +157,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { toRef, reactive, ref, computed } from 'vue';
import { dateFormat } from '@/utils/date';
import { newUUID } from '@/utils/id';
@@ -192,16 +192,20 @@ const data = ref();
const names = ref();
const repos = ref();
const paginationConfig = reactive({
cacheSizeKey: 'container-image-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('container-image-page-size')) || 20,
pageSize: 20,
total: 0,
name: '',
orderBy: 'createdAt',
order: 'null',
});
useSearchReset(
{ search: toRef(paginationConfig, 'name'), page: toRef(paginationConfig, 'currentPage') },
useSearchState(
'container/image/index',
{
search: toRef(paginationConfig, 'name'),
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const columns = ref([]);
@@ -95,7 +95,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import CreateDialog from '@/views/container/network/create/index.vue';
import DetailDrawer from '@/views/container/network/detail/index.vue';
import { toRef, reactive, ref } from 'vue';
@@ -115,13 +115,16 @@ const taskLogRef = ref();
const data = ref();
const selects = ref<any>([]);
const paginationConfig = reactive({
cacheSizeKey: 'container-network-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('container-network-page-size')) || 20,
pageSize: 20,
total: 0,
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'container/network/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const opRef = ref();
const isActive = ref(false);
+7 -4
View File
@@ -59,7 +59,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import OperatorDialog from '@/views/container/repo/operator/index.vue';
import { toRef, reactive, ref } from 'vue';
import { dateFormat } from '@/utils/date';
@@ -72,13 +72,16 @@ const loading = ref();
const data = ref();
const selects = ref<any>([]);
const paginationConfig = reactive({
cacheSizeKey: 'image-repo-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('image-repo-page-size')) || 20,
pageSize: 20,
total: 0,
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'container/repo/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const opRef = ref();
const confirmDialog = ref();
@@ -81,7 +81,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { toRef, reactive, ref } from 'vue';
import { dateFormat, getCurrentDateFormatted } from '@/utils/date';
import { downloadWithContent } from '@/utils/file';
@@ -105,13 +105,16 @@ const isActive = ref(false);
const isExist = ref(false);
const paginationConfig = reactive({
cacheSizeKey: 'compose-template-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('compose-template-page-size')) || 20,
pageSize: 20,
total: 0,
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'container/template/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const search = async () => {
if (!isActive.value || !isExist.value) {
@@ -124,7 +124,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import CreateDialog from '@/views/container/volume/create/index.vue';
import CodemirrorDrawer from '@/components/codemirror-pro/drawer.vue';
import DockerStatus from '@/views/container/docker-status/index.vue';
@@ -152,13 +152,16 @@ const opRef = ref();
const data = ref();
const selects = ref<any>([]);
const paginationConfig = reactive({
cacheSizeKey: 'container-volume-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('container-volume-page-size')) || 20,
pageSize: 20,
total: 0,
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'container/volume/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const isActive = ref(false);
const isExist = ref(false);
+7 -4
View File
@@ -263,7 +263,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import Records from '@/views/cronjob/cronjob/record/index.vue';
import Backups from '@/views/cronjob/cronjob/backup/index.vue';
import Import from '@/views/cronjob/cronjob/import/index.vue';
@@ -310,9 +310,8 @@ const groupOptions = ref();
const dialogGroupRef = ref();
const pageState = usePageState(() => ({
paginationConfig: {
cacheSizeKey: 'cronjob-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('cronjob-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
@@ -323,7 +322,11 @@ const pageState = usePageState(() => ({
}));
const paginationConfig = pageState.paginationConfig;
const { defaultGroupID, searchName, searchGroupID } = toRefs(pageState);
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'cronjob/cronjob/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const search = async (column?: any) => {
if (column) {
@@ -256,6 +256,7 @@
</template>
<script lang="ts" setup>
import { panelCacheKey, writePanelCache, readCachedPageSize } from '@/utils/panel-cache';
import { reactive, ref } from 'vue';
import { useMediaQuery } from '@vueuse/core';
import { Cronjob } from '@/api/interface/cronjob';
@@ -309,7 +310,7 @@ const formatInterval = (interval?: number) => {
};
const acceptParams = async (params: DialogProps): Promise<void> => {
let itemSize = Number(localStorage.getItem(searchInfo.cacheSizeKey));
let itemSize = readCachedPageSize(searchInfo.cacheSizeKey);
if (itemSize) {
searchInfo.pageSize = itemSize;
}
@@ -341,7 +342,7 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
const handleSizeChange = (val: number) => {
searchInfo.pageSize = val;
localStorage.setItem(searchInfo.cacheSizeKey, val + '');
writePanelCache('pagination', panelCacheKey(`size:${searchInfo.cacheSizeKey}`), val);
search(true);
};
const handleCurrentChange = (val: number) => {
+7 -4
View File
@@ -124,7 +124,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { dateFormat, getCurrentDateFormatted } from '@/utils/date';
import { deepCopy } from '@/utils/misc';
import { newUUID } from '@/utils/id';
@@ -156,13 +156,16 @@ const scriptSync = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'script-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('script-page-size')) || 20,
pageSize: 20,
total: 0,
});
const searchInfo = ref<string>('');
useSearchReset({ search: searchInfo, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'cronjob/library/index',
{ search: searchInfo, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const group = ref<string>('');
const groupOptions = ref();
@@ -323,7 +323,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { toRef, nextTick, onMounted, reactive, ref } from 'vue';
import { dateFormat } from '@/utils/date';
import { getRandomStr } from '@/utils/id';
@@ -392,14 +392,17 @@ const dbOptionsRemote = ref<Array<Database.DatabaseOption>>([]);
const tableRows = ref<Array<Database.MongodbDBInfo>>([]);
const paginationConfig = reactive({
cacheSizeKey: 'mongodb-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('mongodb-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'database/mongodb/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
@@ -75,7 +75,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { dateFormat } from '@/utils/date';
import { toRef, onMounted, reactive, ref } from 'vue';
import { deleteCheckDatabase, searchDatabases } from '@/api/modules/database';
@@ -93,15 +93,18 @@ const deleteRef = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'mongodb-remote-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('mongodb-remote-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'database/mongodb/remote/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const search = async (column?: any) => {
paginationConfig.orderBy = column?.order ? column.prop : paginationConfig.orderBy;
+7 -4
View File
@@ -226,7 +226,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import BindDialog from '@/views/database/mysql/bind/index.vue';
import UserDialog from '@/views/database/mysql/user/index.vue';
import OperateDialog from '@/views/database/mysql/create/index.vue';
@@ -293,15 +293,18 @@ const dialogPortJumpRef = ref();
const data = ref<Database.MysqlDBInfo[]>([]);
let grantSummaryRequestID = 0;
const paginationConfig = reactive({
cacheSizeKey: 'mysql-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('mysql-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'database/mysql/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const mysqlContainer = ref();
const mysqlStatus = ref();
@@ -74,7 +74,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { dateFormat } from '@/utils/date';
import { toRef, onMounted, reactive, ref } from 'vue';
import { deleteCheckDatabase, searchDatabases } from '@/api/modules/database';
@@ -92,15 +92,18 @@ const deleteRef = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'mysql-remote-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('mysql-remote-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'database/mysql/remote/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const search = async (column?: any) => {
paginationConfig.orderBy = column?.order ? column.prop : paginationConfig.orderBy;
@@ -241,7 +241,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import BindDialog from '@/views/database/postgresql/bind/index.vue';
import OperateDialog from '@/views/database/postgresql/create/index.vue';
import DeleteDialog from '@/views/database/postgresql/delete/index.vue';
@@ -305,15 +305,18 @@ const dialogPortJumpRef = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'postgresql-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('postgresql-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'database/postgresql/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const postgresqlContainer = ref();
const postgresqlStatus = ref();
@@ -74,7 +74,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { dateFormat } from '@/utils/date';
import { toRef, onMounted, reactive, ref } from 'vue';
import { deleteCheckDatabase, searchDatabases } from '@/api/modules/database';
@@ -92,15 +92,18 @@ const deleteRef = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'postgresql-remote-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('postgresql-remote-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'database/postgresql/remote/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const search = async (column?: any) => {
paginationConfig.orderBy = column?.order ? column.prop : paginationConfig.orderBy;
@@ -73,7 +73,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { dateFormat } from '@/utils/date';
import { toRef, onMounted, reactive, ref } from 'vue';
import { deleteCheckDatabase, searchDatabases } from '@/api/modules/database';
@@ -91,15 +91,18 @@ const deleteRef = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'redis-remote-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('redis-remote-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'database/redis/remote/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const search = async (column?: any) => {
paginationConfig.orderBy = column?.order ? column.prop : paginationConfig.orderBy;
@@ -133,6 +133,7 @@
</template>
<script lang="ts" setup>
import { readCachedPageSize } from '@/utils/panel-cache';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { Database } from '@/api/interface/database';
import { redisPersistenceConf, updateRedisPersistenceConf } from '@/api/modules/database';
@@ -188,7 +189,7 @@ const confirmDialogRef = ref();
const paginationConfig = reactive({
cacheSizeKey: 'redis-backup-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('redis-backup-page-size')) || 20,
pageSize: readCachedPageSize('redis-backup-page-size') || 20,
total: 0,
});
@@ -223,6 +223,7 @@
</template>
<script setup lang="ts">
import { readCachedPageSize } from '@/utils/panel-cache';
import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, reactive, ref } from 'vue';
import { dateFormatSimpleWithSecond } from '@/utils/date';
import { computeSize } from '@/utils/size';
@@ -261,7 +262,7 @@ const activeCollapse = ref([]);
const paginationConfig = reactive({
cacheSizeKey: 'file-history-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('file-history-page-size')) || 20,
pageSize: readCachedPageSize('file-history-page-size') || 20,
total: 0,
small: false,
});
@@ -132,6 +132,7 @@
</template>
<script setup lang="ts">
import { readCachedPageSize } from '@/utils/panel-cache';
import i18n from '@/lang';
import { reactive, ref } from 'vue';
import { File } from '@/api/interface/file';
@@ -226,7 +227,7 @@ const addFile = () => {
const paginationConfig = reactive({
cacheSizeKey: 'file-convert-log-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('file-convert-log-page-size')) || 20,
pageSize: readCachedPageSize('file-convert-log-page-size') || 20,
total: 0,
});
@@ -20,6 +20,7 @@
</template>
<script setup lang="ts">
import { readCachedPageSize } from '@/utils/panel-cache';
import { searchFavorite, removeFavorite } from '@/api/modules/files';
import i18n from '@/lang';
import { reactive, ref } from 'vue';
@@ -28,7 +29,7 @@ import { File } from '@/api/interface/file';
const paginationConfig = reactive({
cacheSizeKey: 'favorite-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('favorite-page-size')) || 20,
pageSize: readCachedPageSize('favorite-page-size') || 20,
total: 0,
});
const req = reactive({
@@ -739,7 +739,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { toRef, computed, nextTick, onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import {
addFavorite,
@@ -980,13 +980,17 @@ const getCurrentPath = () => pathRefs.value[editableTabsKey.value];
const { searchableStatus, searchablePath, setSearchableInputRef, searchableInputBlur } = useMultipleSearchable(paths);
const paginationConfig = reactive({
cacheSizeKey: 'file-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('file-page-size')) || 100,
pageSize: 100,
total: 0,
});
useSearchReset(
{ search: toRef(req, 'search'), page: toRef(paginationConfig, 'currentPage') },
useSearchState(
'host/file-management/index',
{
search: toRef(req, 'search'),
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
@@ -82,6 +82,7 @@
</template>
<script lang="ts" setup>
import { readCachedPageSize } from '@/utils/panel-cache';
import { getRecycleStatus, clearRecycle, getRecycleList, reduceFile } from '@/api/modules/files';
import { reactive, ref } from 'vue';
import { dateFormat } from '@/utils/date';
@@ -107,7 +108,7 @@ const status = ref('Enable');
const paginationConfig = reactive({
cacheSizeKey: 'recycle-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('recycle-page-size')) || 20,
pageSize: readCachedPageSize('recycle-page-size') || 20,
total: 0,
});
@@ -24,6 +24,7 @@
</template>
<script setup lang="ts">
import { readCachedPageSize } from '@/utils/panel-cache';
import { removeFileShare, searchFileShare } from '@/api/modules/files';
import { File } from '@/api/interface/file';
import i18n from '@/lang';
@@ -33,7 +34,7 @@ import { computed, reactive, ref } from 'vue';
const paginationConfig = reactive({
cacheSizeKey: 'share-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('share-page-size')) || 20,
pageSize: readCachedPageSize('share-page-size') || 20,
total: 0,
});
const req = reactive({
@@ -219,7 +219,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { computed, reactive, ref, watch } from 'vue';
import FireRouter from '@/views/host/firewall/index.vue';
import DockerGuardStatus from '@/views/host/firewall/docker/status/index.vue';
@@ -263,7 +263,8 @@ const openRuleTask = (taskID: string) => taskLogRef.value?.openWithTaskID(taskID
const orphanDrawerVisible = ref(false);
const orphanSearchName = ref('');
const searchName = ref('');
useSearchReset(
useSearchState(
'host/firewall/docker/index',
{ search: searchName },
{
onRevisit: () => {
@@ -117,7 +117,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import OperateDialog from './operate/index.vue';
import ImportDialog from './import/index.vue';
import FireRouter from '@/views/host/firewall/index.vue';
@@ -183,12 +183,15 @@ const operateRules = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'firewall-forward-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('firewall-forward-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'host/firewall/forward/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const search = async () => {
if (!isInit.value || !isBind.value || fireName.value === '-') {
@@ -302,7 +302,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { Firewall } from '@/api/interface/firewall';
import type { FuTableOperationButton } from '@/components/table/shared';
import { buildHostRuleExport } from './transfer';
@@ -427,12 +427,15 @@ const supportsFirewalldPriority = computed(() => {
return major > 0 || minor >= 7;
});
const paginationConfig = reactive({
cacheSizeKey: 'firewall-rule-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('firewall-rule-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'host/firewall/rule/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const providerScopes = (): Firewall.Scope[] => {
if (provider.value === 'iptables' || provider.value === 'nftables') {
@@ -86,6 +86,8 @@ const statusOptions = [
const { currentNode } = useGlobalStore();
const isCompactTable = useMediaQuery('(max-width: 1024px)');
const processStore = ProcessStore();
processStore.restoreSearchState();
onActivated(() => processStore.restoreSearchState());
const quickSearchName = (name: string) => {
processStore.netSearch.processID = undefined;
@@ -83,6 +83,8 @@ import { useMediaQuery } from '@vueuse/core';
const { currentNode } = useGlobalStore();
const isCompactTable = useMediaQuery('(max-width: 1024px)');
const processStore = ProcessStore();
processStore.restoreSearchState();
onActivated(() => processStore.restoreSearchState());
const permissionDirective = resolveDirective('permission');
const statusOptions = computed(() => [
+7 -4
View File
@@ -93,7 +93,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { dateFormatServerTimezone } from '@/utils/date';
import { downloadFile } from '@/utils/file';
@@ -108,9 +108,8 @@ const loading = ref();
const data = ref();
const confirmDialogRef = ref();
const paginationConfig = reactive({
cacheSizeKey: 'ssh-log-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('ssh-log-page-size')) || 20,
pageSize: 20,
total: 0,
});
@@ -120,7 +119,11 @@ const exportConfig = reactive({
status: 'All',
});
const searchInfo = ref();
useSearchReset({ search: searchInfo, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'host/ssh/log/log',
{ search: searchInfo, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const searchStatus = ref('All');
const search = async () => {
@@ -24,7 +24,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import FireRouter from '@/views/host/ssh/index.vue';
import { toRef, ref, onMounted, onUnmounted, reactive } from 'vue';
import i18n from '@/lang';
@@ -38,7 +38,7 @@ const sshSearch = reactive({
type: 'ssh',
loginUser: '',
});
useSearchReset({ search: toRef(sshSearch, 'loginUser') }, { onRevisit: () => search() });
useSearchState('host/ssh/session/index', { search: toRef(sshSearch, 'loginUser') }, { onRevisit: () => search() });
const buttons = [
{
@@ -93,6 +93,7 @@
</div>
</template>
<script lang="ts" setup>
import { readCachedPageSize } from '@/utils/panel-cache';
import { Host } from '@/api/interface/host';
import { deleteCert, searchCert, syncCert } from '@/api/modules/host';
import i18n from '@/lang';
@@ -109,7 +110,7 @@ const selects = ref<any>([]);
const paginationConfig = reactive({
cacheSizeKey: 'login-log-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('login-log-page-size')) || 20,
pageSize: readCachedPageSize('login-log-page-size') || 20,
total: 0,
small: true,
});
+5 -4
View File
@@ -101,7 +101,8 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { panelCacheKey, writePanelCache, readCachedPageSize } from '@/utils/panel-cache';
import { useSearchState } from '@/utils/search-reset';
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue';
import { Log } from '@/api/interface/log';
import { getSystemLogStatus, listRunningServices, readSystemLogs } from '@/api/modules/log';
@@ -114,7 +115,7 @@ const logs = ref<Log.SystemLogItem[]>([]);
const loading = ref(false);
const watching = ref(false);
const keyword = ref('');
useSearchReset({ keyword }, { onRevisit: () => scheduleFilterSearch() });
useSearchState('log/host-system/index', { keyword }, { onRevisit: () => scheduleFilterSearch() });
const priority = ref('');
const service = ref('');
const services = ref<string[]>([]);
@@ -194,7 +195,7 @@ const loadPreviousPage = () => {
};
const changePageSize = () => {
localStorage.setItem(paginationConfig.cacheSizeKey, String(paginationConfig.pageSize));
writePanelCache('pagination', panelCacheKey(`size:${paginationConfig.cacheSizeKey}`), paginationConfig.pageSize);
resetAndLoadLogs();
};
@@ -263,7 +264,7 @@ const priorityType = (value: string) => {
};
onMounted(async () => {
const cachedPageSize = Number(localStorage.getItem(paginationConfig.cacheSizeKey));
const cachedPageSize = readCachedPageSize(paginationConfig.cacheSizeKey);
if (pageSizes.includes(cachedPageSize)) {
paginationConfig.pageSize = cachedPageSize;
}
+7 -4
View File
@@ -45,7 +45,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import LogRouter from '@/views/log/router/index.vue';
import { dateFormat } from '@/utils/date';
@@ -61,13 +61,16 @@ const loading = ref();
const data = ref();
const confirmDialogRef = ref();
const paginationConfig = reactive({
cacheSizeKey: 'login-log-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('login-log-page-size')) || 20,
pageSize: 20,
total: 0,
});
const searchInfo = ref<string>('');
useSearchReset({ search: searchInfo, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'log/login/index',
{ search: searchInfo, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const searchStatus = ref<string>('');
const search = async () => {
+7 -4
View File
@@ -139,7 +139,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import LogRouter from '@/views/log/router/index.vue';
import { dateFormat } from '@/utils/date';
@@ -154,13 +154,16 @@ const loading = ref();
const data = ref();
const confirmDialogRef = ref();
const paginationConfig = reactive({
cacheSizeKey: 'operation-log-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('operation-log-page-size')) || 20,
pageSize: 20,
total: 0,
});
const searchName = ref<string>('');
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'log/operation/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const searchGroup = ref<string>('');
const searchStatus = ref<string>('');
const searchNode = ref<string>('');
+11 -2
View File
@@ -49,6 +49,8 @@
</template>
<script setup lang="ts">
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import LogRouter from '@/views/log/router/index.vue';
import { dateFormat } from '@/utils/date';
import { searchTasks } from '@/api/modules/log';
@@ -61,11 +63,18 @@ import { translateTaskText } from '@/utils/task';
const loading = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'task-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('task-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'log/task/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const taskLogRef = ref();
const req = reactive({
type: '',
@@ -357,6 +357,7 @@
</template>
<script setup lang="ts">
import { applyPanelCacheSettings } from '@/utils/panel-cache';
import { ref, reactive, onMounted, onBeforeUnmount, computed, nextTick } from 'vue';
import type { ElForm } from 'element-plus';
import {
@@ -926,6 +927,7 @@ const getSetting = async () => {
i18n.warnHtmlMessage = false;
openMenuTabs.value = res.data.menuTabs === 'Enable';
menuAccordion.value = res.data.menuAccordion === 'Enable';
applyPanelCacheSettings(res.data.panelCache);
themeConfig.value = { ...themeConfig.value, theme: res.data.theme, panelName: res.data.panelName };
if (res.data.passkeySetting && !isIntl.value && !isFxplay.value) {
@@ -159,6 +159,8 @@
</template>
<script lang="ts" setup>
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { onMounted, reactive, ref } from 'vue';
import { useGlobalStore } from '@/composables/useGlobalStore';
import { getAlertConfigDisplayName } from '@/views/setting/alert/setting/drawer/secret-field';
@@ -191,13 +193,20 @@ const req = reactive({
});
const paginationConfig = reactive({
cacheSizeKey: 'alert-list-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('alert-list-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'created_at',
order: 'null',
});
useSearchState(
'setting/alert/dash/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const data = ref();
const buttons = [
+11 -2
View File
@@ -82,6 +82,8 @@
</template>
<script lang="ts" setup>
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { onMounted, reactive, ref } from 'vue';
import { dateFormat } from '@/utils/date';
import { MsgSuccess } from '@/utils/message';
@@ -131,11 +133,18 @@ const resourceTypes = [
'sshIpLogin',
];
const paginationConfig = reactive({
cacheSizeKey: 'alert-log-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('alert-log-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'setting/alert/log/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const req = reactive({
page: 1,
pageSize: 10,
@@ -149,6 +149,8 @@
</template>
<script lang="ts" setup>
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { computed, onMounted, reactive, ref } from 'vue';
import { useGlobalStore } from '@/composables/useGlobalStore';
import {
@@ -219,11 +221,18 @@ const config = ref<Alert.AlertConfigUpdateReq>({
});
const paginationConfig = reactive({
cacheSizeKey: 'alert-config-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('alert-config-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'setting/alert/setting/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const parseConfig = <T extends object>(raw: Alert.AlertConfigInfo, fallback: T): T => {
try {
@@ -120,7 +120,7 @@
</div>
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { dateFormat } from '@/utils/date';
import { toRef, onMounted, ref } from 'vue';
import { searchBackup, deleteBackup, refreshToken } from '@/api/modules/backup';
@@ -136,15 +136,19 @@ const { isProductPro, isFxplay, docsUrl, isMobile } = useGlobalStore();
const loading = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'backup-account-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('backup-account-size')) || 20,
pageSize: 20,
total: 0,
type: '',
name: '',
});
useSearchReset(
{ search: toRef(paginationConfig, 'name'), page: toRef(paginationConfig, 'currentPage') },
useSearchState(
'setting/backup-account/index',
{
search: toRef(paginationConfig, 'name'),
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const opRef = ref();
+11 -2
View File
@@ -99,6 +99,8 @@
</template>
<script setup lang="ts">
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { ref, reactive, onMounted } from 'vue';
import { deleteLicense, searchLicense, syncLicense, unbindLicense } from '@/api/modules/setting';
import LicenseImport from '@/components/license-import/index.vue';
@@ -125,13 +127,20 @@ const withDockerRestart = ref();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'license-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('license-page-size')) || 20,
pageSize: 20,
total: 0,
type: '',
name: '',
});
useSearchState(
'setting/license/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const loadMsg = (row: any) => {
if (row.status === 'Exceptional') {
+82
View File
@@ -0,0 +1,82 @@
<template>
<DrawerPro v-model="visible" :header="$t('setting.panelCache.title')" size="normal">
<el-card shadow="never">
<div v-for="key in categories" :key="key" class="flex items-center justify-between py-3">
<span>{{ $t(`setting.panelCache.${key}`) }}</span>
<el-switch v-model="form[key]" :aria-label="$t(`setting.panelCache.${key}`)" />
</div>
<div class="flex items-center justify-between gap-4 mt-4">
<div class="flex items-center gap-2 shrink-0">
<span>{{ $t('setting.panelCache.duration') }}</span>
<el-tooltip
:content="$t('setting.panelCache.helper')"
placement="top"
:trigger="isMobile ? 'click' : 'hover'"
:popper-style="{ maxWidth: 'min(360px, calc(100vw - 32px))' }"
>
<el-button
link
type="info"
icon="InfoFilled"
class="!ml-0 shrink-0"
:aria-label="$t('setting.panelCache.helper')"
@click.stop
/>
</el-tooltip>
</div>
<el-select
v-model="form.duration"
class="!w-40 min-w-0"
:aria-label="$t('setting.panelCache.duration')"
>
<el-option
v-for="value in durations"
:key="value"
:value="value"
:label="$t(`setting.panelCache.${value}`)"
/>
</el-select>
</div>
</el-card>
<template #footer>
<el-button :disabled="loading" @click="Object.assign(form, defaultPanelCache)">
{{ $t('commons.button.setDefault') }}
</el-button>
<el-button :disabled="loading" @click="visible = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :loading="loading" type="primary" @click="save">{{ $t('commons.button.confirm') }}</el-button>
</template>
</DrawerPro>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
import { updateSetting } from '@/api/modules/setting';
import { useGlobalStore } from '@/composables/useGlobalStore';
import { applyPanelCacheSettings, defaultPanelCache } from '@/utils/panel-cache';
import { MsgSuccess } from '@/utils/message';
import i18n from '@/lang';
const { panelCache, isMobile } = useGlobalStore();
const visible = ref(false);
const loading = ref(false);
const form = reactive({ ...defaultPanelCache });
const categories = ['tabs', 'pagination', 'refresh', 'search'] as const;
const durations = ['24h', 'week', 'month', 'forever'] as const;
const acceptParams = () => {
Object.assign(form, panelCache.value);
visible.value = true;
};
const save = async () => {
loading.value = true;
try {
const value = JSON.stringify(form);
await updateSetting({ key: 'PanelCache', value });
applyPanelCacheSettings(value);
visible.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
} finally {
loading.value = false;
}
};
defineExpose({ acceptParams });
</script>
@@ -170,6 +170,12 @@
</el-button>
</el-form-item>
<el-form-item :label="$t('setting.panelCache.title')">
<el-button v-show="!show" @click="cacheRef.acceptParams()" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</el-form-item>
<el-form-item :label="$t('setting.runtimeEnv')" prop="edition">
<el-button icon="Setting" @click="onChangeRegion">
{{ runtimeEnvLabel() }}
@@ -186,6 +192,7 @@
<Proxy ref="proxyRef" @search="search()" />
<Timeout ref="timeoutRef" @search="search()" />
<HideMenu ref="hideMenuRef" @search="search()" />
<CacheSettings ref="cacheRef" />
<ThemeColor ref="themeColorRef" />
<Watermark ref="watermarkRef" @search="search()" />
<Edition ref="editionRef" @search="search()" />
@@ -193,6 +200,7 @@
</template>
<script lang="ts" setup>
import { applyPanelCacheSettings } from '@/utils/panel-cache';
import { ref, reactive, onMounted } from 'vue';
import { ElForm, ElMessageBox } from 'element-plus';
import { getSettingInfo, updateSetting, getSystemAvailable, getAgentSettingInfo } from '@/api/modules/setting';
@@ -206,6 +214,7 @@ import Timeout from '@/views/setting/panel/timeout/index.vue';
import PanelName from '@/views/setting/panel/name/index.vue';
import SystemIP from '@/views/setting/panel/systemip/index.vue';
import Proxy from '@/views/setting/panel/proxy/index.vue';
import CacheSettings from '@/views/setting/panel/cache/index.vue';
import HideMenu from '@/views/setting/panel/hidemenu/index.vue';
import { getXpackProxyDocker } from '@/extensions/xpack';
import { getXpackSetting, updateXpackSettingByKey } from '@/utils/xpack';
@@ -274,6 +283,7 @@ const systemIPRef = ref();
const proxyRef = ref();
const timeoutRef = ref();
const hideMenuRef = ref();
const cacheRef = ref();
const watermarkRef = ref();
const themeColorRef = ref();
const editionRef = ref();
@@ -307,6 +317,7 @@ const search = async () => {
form.menuTabs = res.data.menuTabs;
form.menuAccordion = res.data.menuAccordion || 'Disable';
menuAccordion.value = form.menuAccordion === 'Enable';
applyPanelCacheSettings(res.data.panelCache);
form.panelName = res.data.panelName;
form.language = res.data.language;
form.sessionTimeout = Number(res.data.sessionTimeout || 0);
@@ -225,7 +225,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import {
searchSnapshotPage,
snapshotDelete,
@@ -253,15 +253,18 @@ const loading = ref(false);
const data = ref();
const selects = ref<any>([]);
const paginationConfig = reactive({
cacheSizeKey: 'snapshot-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('snapshot-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'setting/snapshot/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const opRef = ref();
@@ -91,7 +91,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { Command } from '@/api/interface/command';
import GroupDialog from '@/components/group/index.vue';
import OperateDialog from '@/views/terminal/command/operate/index.vue';
@@ -107,15 +107,18 @@ const data = ref();
const selects = ref<any>([]);
const groupList = ref();
const paginationConfig = reactive({
cacheSizeKey: 'terminal-command-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('terminal-command-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'name',
order: 'ascending',
});
const info = ref();
useSearchReset({ search: info, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'terminal/command/index',
{ search: info, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const group = ref<string>('');
const dialogRef = ref();
const opRef = ref();
+7 -4
View File
@@ -70,7 +70,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import GroupDialog from '@/components/agent-group/index.vue';
import OperateDialog from '@/views/terminal/host/operate/index.vue';
import { deleteHost, editHostGroup, searchHosts } from '@/api/modules/terminal';
@@ -85,13 +85,16 @@ const data = ref();
const groupList = ref();
const selects = ref<any>([]);
const paginationConfig = reactive({
cacheSizeKey: 'terminal-host-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('terminal-host-page-size')) || 20,
pageSize: 20,
total: 0,
});
const info = ref();
useSearchReset({ search: info, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'terminal/host/index',
{ search: info, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const group = ref<string>('');
const opRef = ref();
+7 -4
View File
@@ -190,7 +190,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { toRef, onMounted, reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
@@ -210,15 +210,18 @@ const selects = ref<any>([]);
const { docsUrl, isFxplay, isProductPro, isMobile } = useGlobalStore();
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'clam-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('clam-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'toolbox/clam/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const opRef = ref();
const dialogRef = ref();
@@ -193,6 +193,7 @@
</template>
<script lang="ts" setup>
import { panelCacheKey, writePanelCache, readCachedPageSize } from '@/utils/panel-cache';
import { reactive, ref } from 'vue';
import { useMediaQuery } from '@vueuse/core';
import i18n from '@/lang';
@@ -220,7 +221,7 @@ const records = ref<Array<Toolbox.ClamRecord>>([]);
const currentRecord = ref<Toolbox.ClamRecord>();
const acceptParams = async (params: DialogProps): Promise<void> => {
let itemSize = Number(localStorage.getItem(searchInfo.cacheSizeKey));
let itemSize = readCachedPageSize(searchInfo.cacheSizeKey);
if (itemSize) {
searchInfo.pageSize = itemSize;
}
@@ -232,7 +233,7 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
const handleSizeChange = (val: number) => {
searchInfo.pageSize = val;
localStorage.setItem(searchInfo.cacheSizeKey, val + '');
writePanelCache('pagination', panelCacheKey(`size:${searchInfo.cacheSizeKey}`), val);
search(true);
};
const handleCurrentChange = (val: number) => {
+7 -4
View File
@@ -174,7 +174,7 @@
</template>
<script lang="ts" setup>
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { toRef, onMounted, reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
@@ -193,15 +193,18 @@ const selects = ref<any>([]);
const data = ref();
const paginationConfig = reactive({
cacheSizeKey: 'ftp-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('ftp-page-size')) || 20,
pageSize: 20,
total: 0,
orderBy: 'createdAt',
order: 'null',
});
const searchName = ref();
useSearchReset({ search: searchName, page: toRef(paginationConfig, 'currentPage') }, { onRevisit: () => search() });
useSearchState(
'toolbox/ftp/index',
{ search: searchName, page: toRef(paginationConfig, 'currentPage'), pageSize: toRef(paginationConfig, 'pageSize') },
{ onRevisit: () => search() },
);
const form = reactive({
isActive: true,
+2 -1
View File
@@ -38,6 +38,7 @@
</template>
<script lang="ts" setup>
import { readCachedPageSize } from '@/utils/panel-cache';
import { reactive, ref } from 'vue';
import { searchFtpLog } from '@/api/modules/toolbox';
import { computeSizeFromByte } from '@/utils/size';
@@ -46,7 +47,7 @@ import i18n from '@/lang';
const paginationConfig = reactive({
cacheSizeKey: 'ftp-log-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('ftp-log-page-size')) || 20,
pageSize: readCachedPageSize('ftp-log-page-size') || 20,
total: 0,
user: '',
operation: '',
@@ -102,6 +102,8 @@
</template>
<script setup lang="ts">
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { onMounted, reactive, ref } from 'vue';
import { Runtime } from '@/api/interface/runtime';
import { RuntimeDeleteCheck, SearchRuntimes, SyncRuntime } from '@/api/modules/runtime';
@@ -138,11 +140,18 @@ const isActive = ref(false);
const isExist = ref(false);
const paginationConfig = reactive({
cacheSizeKey: 'runtime-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('runtime-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'website/runtime/dotnet/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const req = reactive<Runtime.RuntimeReq>({
name: '',
page: 1,
@@ -102,6 +102,8 @@
</template>
<script setup lang="ts">
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { onMounted, reactive, ref } from 'vue';
import { Runtime } from '@/api/interface/runtime';
import { RuntimeDeleteCheck, SearchRuntimes, SyncRuntime } from '@/api/modules/runtime';
@@ -138,11 +140,18 @@ const isActive = ref(false);
const isExist = ref(false);
const paginationConfig = reactive({
cacheSizeKey: 'runtime-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('runtime-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'website/runtime/go/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const req = reactive<Runtime.RuntimeReq>({
name: '',
page: 1,
@@ -102,6 +102,8 @@
</template>
<script setup lang="ts">
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { onMounted, reactive, ref } from 'vue';
import { Runtime } from '@/api/interface/runtime';
import { RuntimeDeleteCheck, SearchRuntimes, SyncRuntime } from '@/api/modules/runtime';
@@ -138,11 +140,18 @@ const isActive = ref(false);
const isExist = ref(false);
const paginationConfig = reactive({
cacheSizeKey: 'runtime-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('runtime-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'website/runtime/java/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const req = reactive<Runtime.RuntimeReq>({
name: '',
page: 1,
@@ -103,6 +103,8 @@
</template>
<script setup lang="ts">
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { onMounted, reactive, ref } from 'vue';
import { Runtime } from '@/api/interface/runtime';
import { RuntimeDeleteCheck, SearchRuntimes, SyncRuntime } from '@/api/modules/runtime';
@@ -141,11 +143,18 @@ const isActive = ref(false);
const isExist = ref(false);
const paginationConfig = reactive({
cacheSizeKey: 'runtime-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('runtime-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'website/runtime/node/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
const req = reactive<Runtime.RuntimeReq>({
name: '',
page: 1,
@@ -33,7 +33,7 @@
</template>
<script setup lang="ts">
import { useSearchReset } from '@/composables/useSearchReset';
import { useSearchState } from '@/utils/search-reset';
import { Runtime } from '@/api/interface/runtime';
import { GetPHPExtensions, InstallPHPExtension, UnInstallPHPExtension } from '@/api/modules/runtime';
import i18n from '@/lang';
@@ -49,7 +49,11 @@ const supportExtensions = ref([]);
const loading = ref(false);
const taskLogRef = ref();
const searchName = ref('');
useSearchReset({ search: searchName }, { onRevisit: () => searchByName() });
useSearchState(
'website/runtime/php/extension-management/index',
{ search: searchName },
{ onRevisit: () => searchByName() },
);
const data = ref([]);
const handleClose = () => {
@@ -24,6 +24,7 @@
</DrawerPro>
</template>
<script lang="ts" setup>
import { readCachedPageSize } from '@/utils/panel-cache';
import { DeletePHPExtensions, SearchPHPExtensions } from '@/api/modules/runtime';
import { reactive, ref } from 'vue';
import Create from './operate/index.vue';
@@ -38,7 +39,7 @@ const opRef = ref();
const paginationConfig = reactive({
cacheSizeKey: 'website-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('website-page-size')) || 20,
pageSize: readCachedPageSize('website-page-size') || 20,
total: 0,
});
@@ -135,6 +135,8 @@
</template>
<script setup lang="ts">
import { toRef } from 'vue';
import { useSearchState } from '@/utils/search-reset';
import { onMounted, reactive, ref } from 'vue';
import { Runtime } from '@/api/interface/runtime';
import { RuntimeDeleteCheck, SearchRuntimes } from '@/api/modules/runtime';
@@ -165,11 +167,18 @@ const { isMobile } = useGlobalStore();
const taskLogRef = ref();
const paginationConfig = reactive({
cacheSizeKey: 'runtime-page-size',
currentPage: 1,
pageSize: Number(localStorage.getItem('runtime-page-size')) || 20,
pageSize: 20,
total: 0,
});
useSearchState(
'website/runtime/php/index',
{
page: toRef(paginationConfig, 'currentPage'),
pageSize: toRef(paginationConfig, 'pageSize'),
},
{ onRevisit: () => search() },
);
let req = reactive<Runtime.RuntimeReq>({
name: '',
page: 1,

Some files were not shown because too many files have changed in this diff Show More