Add administrator pause and joining-lock controls
Provide authenticated owner/operator room controls with live account binding, durable audit and exact saved retries. Pause gates human, bot and automatic writes while preserving recovery, discussion and taking back control. Resume keeps decisions and restores AI pacing. Add directory availability filters and player notices. Verified types, lint, 5223 offline tests, 52 HTTP tests and build. Independent persistence/privacy review and authenticated HTTP acceptance passed. Desktop/mobile browser QA confirmed lost-response refresh/retry makes one audit row and resume restores controls. Existing games preserved. Authenticated deployed admin acceptance remains pending explicit QA access confirmation.
This commit is contained in:
1 parent
f29d05620c
commit
8c922b446b
39 files changed
+3196
-104
No files matched your search
+15
-13
@@ -86,6 +86,7 @@ import {
|
||||
} from './richese-allied-no-field';
|
||||
import { presenceByLocation } from '@/game/force-presence';
|
||||
import { AutomaticActionNotice } from './automatic-action-notice';
|
||||
import { RoomControlNotice } from './room-control-notice';
|
||||
import { TableSounds } from './table-sounds';
|
||||
import { EcazSpice } from './ecaz-spice';
|
||||
import { VictoryProgress } from './victory-progress';
|
||||
@@ -285,7 +286,7 @@ export function GameTable({
|
||||
: [],
|
||||
);
|
||||
const busy =
|
||||
transportBusy || !!me.autopilot || g.automaticContinuationPending;
|
||||
transportBusy || !!g.roomControl?.paused || !!me.autopilot || g.automaticContinuationPending;
|
||||
const traitorBattle = g.battle;
|
||||
const traitorBeneficiary =
|
||||
traitorBattle &&
|
||||
@@ -954,6 +955,7 @@ export function GameTable({
|
||||
</Button>
|
||||
</div>
|
||||
</header>
|
||||
<RoomControlNotice control={g.roomControl} />
|
||||
<div className="game-banner">
|
||||
<span className="eyebrow">
|
||||
{g.status === 'lobby'
|
||||
@@ -1573,14 +1575,14 @@ export function GameTable({
|
||||
<PrivateBattlePlan game={g} />
|
||||
<NexusCards game={g} act={act} busy={busy} />
|
||||
<Recruits game={g} act={act} busy={busy} />
|
||||
<NexusTraitors game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<DiscoveryPanel game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<LeaderSkillsPanel skills={g.leaderSkills} leaders={g.allLeaders} players={g.players} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<NexusTraitors game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
<DiscoveryPanel game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
<LeaderSkillsPanel skills={g.leaderSkills} leaders={g.allLeaders} players={g.players} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
<RihaniHistory game={g} />
|
||||
<MentatHistory game={g} />
|
||||
<NexusChoamTrade game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<NexusTleilaxu game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<NexusSuboids game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<NexusChoamTrade game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
<NexusTleilaxu game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
<NexusSuboids game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
<NexusAdvisors game={g} act={act} busy={busy} />
|
||||
<NexusSardaukar game={g} act={act} busy={busy} />
|
||||
{!g.nexusCards?.waiting.length && <TupileIntelligence game={g} act={act} busy={busy} />}
|
||||
@@ -3035,9 +3037,9 @@ export function GameTable({
|
||||
))}
|
||||
</>
|
||||
) : g.decision.kind === 'sukRescue' ? (
|
||||
<SukGraduatePanel key={g.decision.event} decision={g.decision} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<SukGraduatePanel key={g.decision.event} decision={g.decision} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
) : g.decision.kind === 'rihani' ? (
|
||||
<RihaniChoice key={g.decision.event} game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<RihaniChoice key={g.decision.event} game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
) : g.decision.kind === 'battleLosses' ? (
|
||||
<>
|
||||
<p className="muted">
|
||||
@@ -3142,13 +3144,13 @@ export function GameTable({
|
||||
})}
|
||||
</>
|
||||
) : g.decision.kind === 'discoveryEntry' ? (
|
||||
<DiscoveryEntryDecision game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<DiscoveryEntryDecision game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
) : g.decision.kind === 'ecologicalStorm' ? (
|
||||
<DiscoveryStormDecision game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<DiscoveryStormDecision game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
) : g.decision.kind === 'discoveryDiscard' ? (
|
||||
<DiscoveryDiscardDecision game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<DiscoveryDiscardDecision game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
) : g.decision.kind === 'greatMakerVote' || g.decision.kind === 'greatMakerRide' ? (
|
||||
<GreatMakerDecision game={g} act={act} busy={transportBusy || !!me.autopilot} />
|
||||
<GreatMakerDecision game={g} act={act} busy={transportBusy || !!g.roomControl?.paused || !!me.autopilot} />
|
||||
) : g.decision.kind === 'wormProtection' ? (
|
||||
<>
|
||||
<p className="muted">
|
||||
|
||||
Reference in new issue
Block a user