fix: 메인 갱신 중 클릭을 toast로 안내
실시간 또는 수동 갱신 중에도 직접 갱신 버튼의 활성 시각 상태를 유지한다. 중복 클릭은 추가 조회 없이 공통 안내 toast로 전달하고 데스크톱·모바일 Chromium 회귀 검증을 보강한다.
This commit is contained in:
@@ -2107,16 +2107,24 @@ test('mobile bottom controls share Ref pressed geometry while their color bases
|
||||
await expect
|
||||
.poll(() => page.locator(manualRefreshSelector).evaluate((element) => getComputedStyle(element).boxShadow))
|
||||
.not.toBe('none');
|
||||
const callsBeforeManualRefresh = state.generalMeCalls;
|
||||
await page.locator(manualRefreshSelector).click();
|
||||
await expect(page.locator(manualRefreshSelector)).toBeDisabled();
|
||||
await expect(page.locator(manualRefreshSelector)).toBeEnabled();
|
||||
await expect(page.locator(manualRefreshSelector)).toHaveAttribute('aria-busy', 'true');
|
||||
await page.locator(manualRefreshSelector).click();
|
||||
await expect(page.getByTestId('game-toast')).toContainText('이미 정보를 갱신하고 있습니다.');
|
||||
await page.mouse.move(1, 1);
|
||||
expect(await buttonStyle(manualRefreshSelector)).toMatchObject({
|
||||
backgroundColor: 'rgb(33, 37, 41)',
|
||||
borderBottomWidth: '4px',
|
||||
marginTop: '0px',
|
||||
height: 45,
|
||||
});
|
||||
await expect(page.locator(manualRefreshSelector)).toHaveCSS('opacity', '0.55');
|
||||
await expect(page.locator(manualRefreshSelector)).toHaveCSS('opacity', '1');
|
||||
await page.screenshot({ path: testInfo.outputPath('mobile-refresh-busy-toast.png'), fullPage: true });
|
||||
await expect(page.locator(manualRefreshSelector)).toHaveAttribute('aria-busy', 'false');
|
||||
await expect(page.locator(manualRefreshSelector)).toBeEnabled();
|
||||
expect(state.generalMeCalls).toBe(callsBeforeManualRefresh + 1);
|
||||
|
||||
await persistArtifact(page, `${basePath.slice(1)}-mobile-bottom-ref-buttons`);
|
||||
});
|
||||
@@ -2685,6 +2693,7 @@ test('realtime read-model events skip clock-only work, merge bursts, patch in pl
|
||||
|
||||
const operationsBeforeChangedBurst = state.operations.length;
|
||||
state.generalName = '부드럽게갱신된장수';
|
||||
state.refreshDelayMs = 1_000;
|
||||
await page.evaluate(() => {
|
||||
const emit = (window as unknown as { __emitMainRealtime: (type: string, payload: unknown) => void })
|
||||
.__emitMainRealtime;
|
||||
@@ -2706,7 +2715,20 @@ test('realtime read-model events skip clock-only work, merge bursts, patch in pl
|
||||
}
|
||||
});
|
||||
|
||||
const manualRefresh = page.getByRole('button', { name: '갱 신' });
|
||||
await expect(manualRefresh).toHaveAttribute('aria-busy', 'true');
|
||||
await expect(manualRefresh).toBeEnabled();
|
||||
await manualRefresh.click();
|
||||
await expect(page.getByTestId('game-toast')).toContainText('이미 정보를 갱신하고 있습니다.');
|
||||
if (autoRefreshArtifactRoot) {
|
||||
await page.screenshot({
|
||||
path: resolve(autoRefreshArtifactRoot, 'auto-refresh-busy-feedback.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
}
|
||||
|
||||
await expect.poll(() => state.generalMeCalls, { timeout: 3_000 }).toBe(callsBeforeRefresh + 1);
|
||||
state.refreshDelayMs = 300;
|
||||
await expect(page.locator('[data-main-target="general"] .skeleton-line')).toHaveCount(0);
|
||||
await expect(page.locator('[data-main-target="city"] .skeleton-line')).toHaveCount(0);
|
||||
await expect(page.getByRole('button', { name: '갱 신' })).toHaveAttribute('aria-busy', 'false');
|
||||
|
||||
@@ -226,7 +226,6 @@ const onQuick = (item: QuickNavigationItem) => {
|
||||
data-bottom-menu="manual-refresh"
|
||||
aria-label="직접 갱신"
|
||||
title="직접 갱신"
|
||||
:disabled="refreshing"
|
||||
:aria-busy="refreshing"
|
||||
@click="emit('refresh')"
|
||||
>
|
||||
@@ -306,12 +305,6 @@ const onQuick = (item: QuickNavigationItem) => {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.manual-refresh-trigger:disabled {
|
||||
cursor: wait;
|
||||
filter: grayscale(0.6);
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.bottom-trigger.legacy-button:not(:disabled, [aria-disabled='true']):hover,
|
||||
.bottom-trigger.legacy-button:not(:disabled, [aria-disabled='true'])[aria-expanded='true'] {
|
||||
height: 44px;
|
||||
|
||||
@@ -20,11 +20,13 @@ import type { QuickNavigationItem } from '../components/main/mainNavigation';
|
||||
import { formatLog } from '../utils/formatLog';
|
||||
import { useSessionStore } from '../stores/session';
|
||||
import { useMainDashboardStore } from '../stores/mainDashboard';
|
||||
import { useGameFeedback } from '../composables/useGameFeedback';
|
||||
import { trpc } from '../utils/trpc';
|
||||
import type { CommandPatternEntry } from '../components/command/types';
|
||||
|
||||
const session = useSessionStore();
|
||||
const dashboard = useMainDashboardStore();
|
||||
const { info: showInfoToast } = useGameFeedback();
|
||||
const isMobile = useMediaQuery('(max-width: 939.98px)');
|
||||
|
||||
const npcMode = ref(0);
|
||||
@@ -115,6 +117,14 @@ const loadMainData = async () => {
|
||||
npcMode.value = worldState?.config.npcMode ?? 0;
|
||||
};
|
||||
|
||||
const requestManualRefresh = () => {
|
||||
if (refreshing.value) {
|
||||
showInfoToast('이미 정보를 갱신하고 있습니다.');
|
||||
return;
|
||||
}
|
||||
void loadMainData();
|
||||
};
|
||||
|
||||
const moveLobby = () => {
|
||||
window.location.replace(import.meta.env.VITE_GATEWAY_WEB_URL?.trim() || '/gateway/');
|
||||
};
|
||||
@@ -154,9 +164,8 @@ watch(
|
||||
<button
|
||||
class="game-shell__action legacy-button legacy-button--navigation"
|
||||
type="button"
|
||||
:disabled="refreshing"
|
||||
:aria-busy="refreshing"
|
||||
@click="loadMainData"
|
||||
@click="requestManualRefresh"
|
||||
>
|
||||
갱 신
|
||||
</button>
|
||||
@@ -451,7 +460,7 @@ watch(
|
||||
:npc-mode="npcMode"
|
||||
:realtime-enabled="realtimeEnabled"
|
||||
:refreshing="refreshing"
|
||||
@refresh="loadMainData"
|
||||
@refresh="requestManualRefresh"
|
||||
@toggle-realtime="dashboard.setRealtimeEnabled(!realtimeEnabled)"
|
||||
@lobby="moveLobby"
|
||||
@quick="moveQuick"
|
||||
|
||||
Reference in New Issue
Block a user