v2.2.17: Google Service Control & Astra Office Flow Layer
This commit is contained in:
@@ -5,6 +5,23 @@
|
||||
const OFFICE_RUNTIME_JS_TEMPLATE = `
|
||||
<script>(function(){
|
||||
const base='\${assets.derivedBase}'; const stage=document.getElementById('stage');
|
||||
const officeEl = stage && stage.closest ? stage.closest('.office') : null;
|
||||
if(officeEl){
|
||||
officeEl.style.setProperty('--office-backdrop', 'url(\"'+base+'/office-backdrop-astra-v2.png\")');
|
||||
officeEl.classList.add('has-art');
|
||||
}
|
||||
let _stageScale = 1;
|
||||
function _fitStage(){
|
||||
const shell = stage && stage.closest ? stage.closest('.office') : null;
|
||||
if(!stage || !shell) return;
|
||||
const sx = Math.max(.62, (shell.clientWidth - 28) / 720);
|
||||
const sy = Math.max(.62, (shell.clientHeight - 28) / 585);
|
||||
_stageScale = Math.min(1, sx, sy);
|
||||
stage.style.transform = 'scale(' + _stageScale + ')';
|
||||
stage.style.transformOrigin = 'center center';
|
||||
}
|
||||
window.addEventListener('resize', _fitStage);
|
||||
setTimeout(_fitStage, 0);
|
||||
// \u2500\u2500 \uB370\uC774\uD130 \uBAA8\uB378 \u2500\u2500
|
||||
// stations: \uCC45\uC0C1 + \uCE90\uB9AD\uD130 \uC815\uC758 \uBC30\uC5F4 (let \u2014 \uCD94\uAC00/\uC81C\uAC70 \uAC00\uB2A5).
|
||||
// key = \uC548\uC815\uC801 \uC2DD\uBCC4\uC790 (DOM dataset.role \uB85C\uB3C4 \uC0AC\uC6A9). \uC0AC\uC6A9\uC790\uAC00 \uC0C8\uB85C \uB9CC\uB4E0 \uCC45\uC0C1\uC740 \uC790\uB3D9 \uC0DD\uC131.
|
||||
@@ -31,13 +48,17 @@ const DESK_SPRITE_CHOICES=['desk-main','desk-boss','desk-dark-mirror','desk-main
|
||||
// \uCD94\uAC00 \uAC00\uB2A5\uD55C \uD504\uB78D sprite \uD6C4\uBCF4.
|
||||
const PROP_SPRITE_CHOICES=['board','plant-tall','bookshelf','plant-bushy','partition','cooler','filing','couch','rug','shelf','printer','monitor-blue','monitor-black','chair-blue','crt'];
|
||||
const DEFAULT_PROPS=[
|
||||
{name:'board',x:316,y:12,w:88},{name:'plant-tall',x:44,y:92,w:42},{name:'bookshelf',x:86,y:70,w:54},
|
||||
{name:'plant-bushy',x:642,y:96,w:42},{name:'partition',x:520,y:208,w:72},{name:'cooler',x:640,y:248,w:38},
|
||||
{name:'filing',x:620,y:330,w:42},{name:'couch',x:578,y:432,w:96},{name:'rug',x:560,y:510,w:126},
|
||||
{name:'shelf',x:40,y:504,w:118},{name:'printer',x:520,y:520,w:58},{name:'monitor-blue',x:356,y:56,w:44},
|
||||
{name:'plant-tall',x:40,y:118,w:42},{name:'bookshelf',x:86,y:88,w:54},
|
||||
{name:'plant-bushy',x:640,y:118,w:42},{name:'cooler',x:646,y:286,w:38},
|
||||
{name:'filing',x:618,y:374,w:42},{name:'couch',x:584,y:452,w:96},
|
||||
{name:'rug',x:560,y:514,w:126},{name:'printer',x:520,y:526,w:58},
|
||||
];
|
||||
|
||||
let stations=[]; // mutable, \uC2DC\uC791 \uC2DC default \uB610\uB294 saved layout \uB85C \uCC44\uC6C0.
|
||||
let _hasSavedLayout=false;
|
||||
let _layoutSource='default';
|
||||
let _lastPipelineLayoutSignature='';
|
||||
let _latestSnapshot=null;
|
||||
let __nextDeskN=100; // user-add \uCC45\uC0C1 id \uCE74\uC6B4\uD130 (default \uC640 \uCDA9\uB3CC \uD68C\uD53C \uC704\uD574 \uD070 \uC218\uC5D0\uC11C \uC2DC\uC791).
|
||||
let __nextObjN=0;
|
||||
const stationByKey={}; // \uBE60\uB978 lookup. stations \uBCC0\uACBD \uC2DC rebuild.
|
||||
@@ -51,6 +72,193 @@ function _rebuildStationIndex(){
|
||||
Object.keys(stationByKey).forEach(k=>delete stationByKey[k]);
|
||||
stations.forEach(st=>{ stationByKey[st.key]=st; });
|
||||
}
|
||||
function _safeDeskKey(raw){
|
||||
return 'pipe_' + String(raw || 'agent').toLowerCase().replace(/[^a-z0-9_-]+/g,'_');
|
||||
}
|
||||
function _uniqueAgentsById(list){
|
||||
const seen=new Set(), out=[];
|
||||
for(const item of list||[]){
|
||||
if(!item || !item.agentId || seen.has(item.agentId)) continue;
|
||||
seen.add(item.agentId); out.push(item);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function _inferRoleFromStageLabel(label){
|
||||
const s=String(label||'').toLowerCase();
|
||||
if(/qa|테스트|검증/.test(s)) return 'qa';
|
||||
if(/검토|감리|review/.test(s)) return 'inspector';
|
||||
if(/디자인|ux|ui/.test(s)) return 'designer';
|
||||
if(/시장|트렌드|조사|리서치|research/.test(s)) return 'researcher';
|
||||
if(/설계|개발|구현|배포|deploy|dev/.test(s)) return 'developer';
|
||||
if(/기획|방향|문서|plan/.test(s)) return 'planner';
|
||||
return null;
|
||||
}
|
||||
function _resolvedStageAgentId(stage, roster){
|
||||
const explicit = stage && (stage.agentId || stage.agent);
|
||||
if(explicit) return explicit;
|
||||
const role = _inferRoleFromStageLabel(stage && stage.label);
|
||||
if(!role) return null;
|
||||
const match = (roster||[]).find(r=>r && r.roleCategory===role);
|
||||
return match ? match.agentId : null;
|
||||
}
|
||||
function _pipelineRosterOrder(roster, pipeline){
|
||||
const list=Array.isArray(roster)?roster.slice():[];
|
||||
if(!pipeline || !Array.isArray(pipeline.stages) || !pipeline.stages.length) return list;
|
||||
const byId=new Map(list.map(r=>[r.agentId,r]));
|
||||
const ordered=[];
|
||||
const ceo=byId.get('ceo');
|
||||
if(ceo) ordered.push(ceo);
|
||||
for(const stage of pipeline.stages){
|
||||
const aid=_resolvedStageAgentId(stage,list);
|
||||
const agent=aid && byId.get(aid);
|
||||
if(agent) ordered.push(agent);
|
||||
}
|
||||
for(const agent of list) ordered.push(agent);
|
||||
return _uniqueAgentsById(ordered);
|
||||
}
|
||||
function _stationSpriteFor(slot, roleCategory){
|
||||
if(roleCategory==='ceo') return 'desk-boss';
|
||||
return slot >= 4 ? 'desk-dark-mirror' : (slot % 2 ? 'desk-dark' : 'desk-main');
|
||||
}
|
||||
function _stationSlot(slot){
|
||||
const path=[
|
||||
[72,220,'R'],[214,210,'R'],[356,220,'R'],[498,210,'R'],
|
||||
[498,394,'L'],[356,404,'L'],[214,394,'L'],[72,404,'L'],
|
||||
];
|
||||
if(path[slot]) return path[slot];
|
||||
const extra=slot-path.length;
|
||||
const cols=4;
|
||||
return [54+(extra%cols)*144, 42+Math.floor(extra/cols)*86, extra%2?'L':'R'];
|
||||
}
|
||||
function _makeStationForRosterAgent(agent, slot){
|
||||
if(agent.roleCategory==='ceo' || agent.agentId==='ceo'){
|
||||
return {
|
||||
key:'ceo',agentKey:agent.agentId,label:agent.agentName||'CEO',charRow:_roleCategoryToCharRow(agent.roleCategory),
|
||||
deskSprite:'desk-boss',deskX:292,deskY:82,deskW:136,seatX:319,seatY:113,face:'R',
|
||||
dock:[350,164],roam:[[306,196],[396,196]],boss:true,
|
||||
};
|
||||
}
|
||||
const [deskX,deskY,face]=_stationSlot(slot);
|
||||
const deskW=112;
|
||||
const seatX=face==='L' ? deskX+48 : deskX+4;
|
||||
const seatY=deskY+36;
|
||||
return {
|
||||
key:_safeDeskKey(agent.agentId),agentKey:agent.agentId,label:agent.agentName||agent.agentId,
|
||||
charRow:_roleCategoryToCharRow(agent.roleCategory),deskSprite:_stationSpriteFor(slot,agent.roleCategory),
|
||||
deskX,deskY,deskW,seatX,seatY,face,boss:false,
|
||||
dock:[deskX+(face==='L'?72:32),deskY+82],
|
||||
roam:[[deskX+18,deskY+116],[deskX+78,deskY+102]],
|
||||
};
|
||||
}
|
||||
function _rebuildScene(nextStations, props){
|
||||
_clearStage();
|
||||
stations=(nextStations||[]).map(st=>Object.assign({},st));
|
||||
_rebuildStationIndex();
|
||||
stations.forEach(buildStation);
|
||||
(props||DEFAULT_PROPS).forEach(p=>addImg(p.name,p.x,p.y,p.w));
|
||||
}
|
||||
function _restoreDefaultScene(){
|
||||
_rebuildScene(DEFAULT_STATIONS,DEFAULT_PROPS);
|
||||
_layoutSource='default';
|
||||
_lastPipelineLayoutSignature='';
|
||||
const shell=document.querySelector('.office-shell');
|
||||
if(shell) shell.dataset.layout='default';
|
||||
}
|
||||
function _syncPipelineLayout(pipeline, roster){
|
||||
if(_hasSavedLayout || _editMode) return;
|
||||
const stages=pipeline && Array.isArray(pipeline.stages) ? pipeline.stages : [];
|
||||
if(!stages.length){
|
||||
if(_layoutSource==='pipeline') _restoreDefaultScene();
|
||||
return;
|
||||
}
|
||||
const ordered=_pipelineRosterOrder(roster,pipeline);
|
||||
const signature=ordered.map(r=>r.agentId).join('|')+'::'+stages.map(s=>(s.label||'')+':'+(_resolvedStageAgentId(s,ordered)||'')).join('|');
|
||||
if(_layoutSource==='pipeline' && signature===_lastPipelineLayoutSignature) return;
|
||||
const ceo=ordered.find(r=>r.agentId==='ceo' || r.roleCategory==='ceo');
|
||||
const workers=ordered.filter(r=>r!==ceo);
|
||||
const next=[];
|
||||
if(ceo) next.push(_makeStationForRosterAgent(ceo,0));
|
||||
workers.forEach((agent,idx)=>next.push(_makeStationForRosterAgent(agent,idx)));
|
||||
if(next.length){
|
||||
_rebuildScene(next,DEFAULT_PROPS);
|
||||
_layoutSource='pipeline';
|
||||
_lastPipelineLayoutSignature=signature;
|
||||
const shell=document.querySelector('.office-shell');
|
||||
if(shell) shell.dataset.layout='pipeline';
|
||||
}
|
||||
}
|
||||
function _clearPipelineDecor(){
|
||||
Object.values(__deskWrap).forEach(wrap=>{
|
||||
wrap.classList.remove('pipeline-desk');
|
||||
delete wrap.dataset.flow;
|
||||
wrap.querySelectorAll('.flow-badge').forEach(el=>el.remove());
|
||||
});
|
||||
const flow=document.getElementById('flowLayer');
|
||||
if(flow) flow.innerHTML='';
|
||||
}
|
||||
function _deskCenterForAgent(agentId){
|
||||
const st=findStationByAgent(agentId);
|
||||
if(!st) return null;
|
||||
const wrap=__deskWrap[st.key];
|
||||
if(!wrap) return null;
|
||||
const x=parseFloat(wrap.style.left)+(parseFloat(wrap.style.width)||st.deskW||112)/2;
|
||||
const y=parseFloat(wrap.style.top)+34;
|
||||
return {x,y,st,wrap};
|
||||
}
|
||||
function _renderPipelineDecor(pipeline, roster){
|
||||
_clearPipelineDecor();
|
||||
const stages=pipeline && Array.isArray(pipeline.stages) ? pipeline.stages : [];
|
||||
if(!stages.length) return;
|
||||
const stageAgents=stages.map(stg=>({ stage:stg, agentId:_resolvedStageAgentId(stg,roster) })).filter(x=>!!x.agentId);
|
||||
if(!stageAgents.length) return;
|
||||
const meta=new Map();
|
||||
stageAgents.forEach((item,idx)=>{
|
||||
const prev=meta.get(item.agentId)||{first:idx+1,count:0,statuses:[]};
|
||||
prev.count++;
|
||||
prev.statuses.push(item.stage.status||'pending');
|
||||
meta.set(item.agentId,prev);
|
||||
});
|
||||
meta.forEach((m,agentId)=>{
|
||||
const center=_deskCenterForAgent(agentId);
|
||||
if(!center) return;
|
||||
const status=m.statuses.includes('active') ? 'active' : (m.statuses.every(s=>s==='done') ? 'done' : 'pending');
|
||||
center.wrap.classList.add('pipeline-desk');
|
||||
center.wrap.dataset.flow=status;
|
||||
const badge=document.createElement('div');
|
||||
badge.className='flow-badge';
|
||||
badge.textContent=m.count>1 ? (m.first+'×'+m.count) : String(m.first);
|
||||
center.wrap.appendChild(badge);
|
||||
});
|
||||
const compact=[], seenRouteAgents=new Set();
|
||||
for(const item of stageAgents){
|
||||
if(seenRouteAgents.has(item.agentId)) continue;
|
||||
seenRouteAgents.add(item.agentId);
|
||||
compact.push(item);
|
||||
}
|
||||
const pts=compact.map(item=>{
|
||||
const center=_deskCenterForAgent(item.agentId);
|
||||
const m=meta.get(item.agentId);
|
||||
const status=m && m.statuses.includes('active') ? 'active' : (m && m.statuses.every(s=>s==='done') ? 'done' : 'pending');
|
||||
return { ...item, status, center };
|
||||
}).filter(x=>!!x.center);
|
||||
const flow=document.getElementById('flowLayer');
|
||||
if(!flow || pts.length<1) return;
|
||||
if(pts.length>1){
|
||||
const path=document.createElementNS('http://www.w3.org/2000/svg','path');
|
||||
path.setAttribute('class','flow-route');
|
||||
path.setAttribute('d',pts.map((p,i)=>(i?'L':'M')+p.center.x+' '+p.center.y).join(' '));
|
||||
flow.appendChild(path);
|
||||
}
|
||||
pts.forEach((p)=>{
|
||||
const c=document.createElementNS('http://www.w3.org/2000/svg','circle');
|
||||
c.setAttribute('class','flow-node');
|
||||
c.setAttribute('cx',String(p.center.x));
|
||||
c.setAttribute('cy',String(p.center.y));
|
||||
c.setAttribute('r',p.status==='active'?'7':'5');
|
||||
c.dataset.status=p.status||'pending';
|
||||
flow.appendChild(c);
|
||||
});
|
||||
}
|
||||
// agentKey \u2192 station.key \uB85C \uB77C\uC6B0\uD305. roleMap \uC758 \uB3D9\uC801 \uBC84\uC804.
|
||||
function findStationByAgent(agentId){
|
||||
if(!agentId) return null;
|
||||
@@ -375,6 +583,8 @@ function apply(s){
|
||||
_lastState = s; // D. 컨텍스트 메뉴 / 세부보기에서 사용.
|
||||
const st = s?.status || 'idle';
|
||||
const meta = _statusMeta(st);
|
||||
const officeShell = document.querySelector('.office-shell');
|
||||
if(officeShell) officeShell.dataset.status = st;
|
||||
// 정적 갱신은 *항상* — 헤더/태스크/단계/로그/프로그레스.
|
||||
const statusEl = document.getElementById('status');
|
||||
const phasePill = document.getElementById('phasePill');
|
||||
@@ -436,7 +646,7 @@ function apply(s){
|
||||
dot.dataset.status = stg.status || 'pending';
|
||||
const label = document.createElement('span');
|
||||
label.className = 'mm-label';
|
||||
label.textContent = (i+1) + '. ' + (stg.label || '단계') + (stg.agent ? ' · ' + stg.agent : '');
|
||||
label.textContent = (i+1) + '. ' + (stg.label || '단계') + ((stg.agentId || stg.agent) ? ' · ' + (stg.agentId || stg.agent) : '');
|
||||
dot.appendChild(label);
|
||||
mm.appendChild(dot);
|
||||
if(i < stages.length - 1){
|
||||
@@ -452,6 +662,7 @@ function apply(s){
|
||||
} else {
|
||||
mm.style.display = 'none';
|
||||
}
|
||||
setTimeout(_fitStage, 0);
|
||||
// 활성 캐릭터 결정. roleMap 은 agentKey → 실제 존재하는 station.key 로 lookup
|
||||
// 하므로, 매핑된 책상이 없으면 null. 사용자가 default ceo 책상을 지워도 안전.
|
||||
let role = null;
|
||||
@@ -652,6 +863,8 @@ function _renderRoster(roster, activeAgentId){
|
||||
const count = document.getElementById('rosterCount');
|
||||
if(!wrap || !count) return;
|
||||
const list = Array.isArray(roster) ? roster : [];
|
||||
const officeShell = document.querySelector('.office-shell');
|
||||
if(officeShell) officeShell.dataset.rosterEmpty = list.length ? 'false' : 'true';
|
||||
count.textContent = String(list.length);
|
||||
if(!list.length){
|
||||
wrap.innerHTML = '<div class="roster-item"><div class="roster-copy"><strong>등록된 팀이 없습니다</strong><span class="roster-meta">회사 모드를 켜면 라인업이 표시됩니다.</span></div></div>';
|
||||
@@ -669,6 +882,20 @@ function _renderRoster(roster, activeAgentId){
|
||||
'</div>'+
|
||||
'</div>';
|
||||
}).join('');
|
||||
wrap.querySelectorAll('.roster-item[data-agent]').forEach((item)=>{
|
||||
const id = item.dataset.agent;
|
||||
item.addEventListener('mouseenter', ()=>_previewAgent(id, true, item));
|
||||
item.addEventListener('mouseleave', ()=>_previewAgent(id, false, item));
|
||||
});
|
||||
}
|
||||
function _previewAgent(agentId, on, item){
|
||||
if(item) item.classList.toggle('preview', !!on);
|
||||
const st = findStationByAgent(agentId);
|
||||
if(!st) return;
|
||||
const desk = __deskWrap[st.key];
|
||||
const ch = chars[st.key];
|
||||
if(desk) desk.classList.toggle('preview', !!on);
|
||||
if(ch) ch.classList.toggle('preview', !!on);
|
||||
}
|
||||
// refactor #G-full — roster 에 있는 agent 중 desk 가 없는 경우 자동 생성.
|
||||
// 한 번 처리된 agentId 는 _autoDeskedFor 에 기록 → 사용자가 그 desk 를 지워도 재생성 안 함.
|
||||
@@ -735,20 +962,31 @@ function _ensureRosterDesks(roster){
|
||||
|
||||
function applyFromSnapshot(snap){
|
||||
if(!snap) return;
|
||||
_latestSnapshot = snap;
|
||||
const roster = Array.isArray(snap.roster) ? snap.roster : [];
|
||||
_renderRoster(roster, snap.activeAgentId);
|
||||
_ensureRosterDesks(roster);
|
||||
const orderedRoster = _pipelineRosterOrder(roster, snap.pipeline);
|
||||
_renderRoster(orderedRoster, snap.activeAgentId);
|
||||
_syncPipelineLayout(snap.pipeline, orderedRoster);
|
||||
if(_layoutSource!=='pipeline' || _hasSavedLayout) _ensureRosterDesks(orderedRoster);
|
||||
_renderPipelineDecor(snap.pipeline, orderedRoster);
|
||||
const active = (snap.activeAgentId && roster.find(a => a.agentId === snap.activeAgentId)) || roster[0];
|
||||
const activeStage = snap.pipeline && Array.isArray(snap.pipeline.stages)
|
||||
? snap.pipeline.stages.find(stg => stg.status === 'active')
|
||||
: null;
|
||||
const stageCount = snap.pipeline && Array.isArray(snap.pipeline.stages) ? snap.pipeline.stages.length : 0;
|
||||
const doneCount = snap.pipeline && Array.isArray(snap.pipeline.stages)
|
||||
? snap.pipeline.stages.filter(stg => stg.status === 'done').length
|
||||
: 0;
|
||||
const synthetic = {
|
||||
agentId: snap.activeAgentId || (active && active.agentId) || 'main',
|
||||
agentName: (active && active.agentName) || 'Agent',
|
||||
status: (active && active.status) || _phaseToStatus(snap.phase),
|
||||
currentTask: snap.task && snap.task.goal,
|
||||
currentStep: active && active.currentStep,
|
||||
currentStep: (active && active.currentStep) || (activeStage && activeStage.label),
|
||||
// apply() 의 message regex 가 첫 토큰을 agentId 로 추출 — activeAgentId 그대로 넘김.
|
||||
message: snap.activeAgentId || '',
|
||||
recentLogs: (active && active.lastLog) ? [active.lastLog] : [],
|
||||
progress: snap.pipeline ? (snap.pipeline.index / Math.max(1, snap.pipeline.stages.length)) : 0,
|
||||
progress: stageCount ? (doneCount / stageCount) : 0,
|
||||
pipelineStages: snap.pipeline && snap.pipeline.stages,
|
||||
needUserInput: (snap.awaiting && snap.awaiting.kind === 'clarification') ? snap.awaiting.questions : undefined,
|
||||
awaitingApproval: (snap.awaiting && snap.awaiting.kind === 'approval') ? snap.awaiting.questions[0] : undefined,
|
||||
@@ -865,6 +1103,7 @@ function _clearStage(){
|
||||
// refactor #G-full: layout reset 시 auto-desk 결정 기록도 초기화 →
|
||||
// 다음 snapshot 도착 시 roster 기반으로 다시 평가.
|
||||
_autoDeskedFor.clear();
|
||||
_clearPipelineDecor();
|
||||
}
|
||||
|
||||
function _applyRot(el, rot){
|
||||
@@ -1216,8 +1455,8 @@ stage.addEventListener('mousedown', e=>{
|
||||
const rect = stage.getBoundingClientRect();
|
||||
const tx = parseFloat(target.style.left)||0;
|
||||
const ty = parseFloat(target.style.top)||0;
|
||||
_dragDX = e.clientX - rect.left - tx;
|
||||
_dragDY = e.clientY - rect.top - ty;
|
||||
_dragDX = ((e.clientX - rect.left) / _stageScale) - tx;
|
||||
_dragDY = ((e.clientY - rect.top) / _stageScale) - ty;
|
||||
target.classList.add('dragging');
|
||||
});
|
||||
|
||||
@@ -1252,8 +1491,8 @@ document.addEventListener('keydown', e=>{
|
||||
document.addEventListener('mousemove', e=>{
|
||||
if(!_editMode || !_drag) return;
|
||||
const rect = stage.getBoundingClientRect();
|
||||
let x = e.clientX - rect.left - _dragDX;
|
||||
let y = e.clientY - rect.top - _dragDY;
|
||||
let x = ((e.clientX - rect.left) / _stageScale) - _dragDX;
|
||||
let y = ((e.clientY - rect.top) / _stageScale) - _dragDY;
|
||||
// 4px 격자 snap
|
||||
x = Math.round(x/4)*4;
|
||||
y = Math.round(y/4)*4;
|
||||
@@ -1331,9 +1570,20 @@ window.addEventListener('message', e=>{
|
||||
const d = e.data;
|
||||
if(!d || typeof d !== 'object') return;
|
||||
if(d.type === 'pixelOfficeLayoutLoaded'){
|
||||
if(d.value) _restoreLayout(d.value);
|
||||
_hasSavedLayout = !!d.value;
|
||||
if(d.value) {
|
||||
_layoutSource = 'saved';
|
||||
_restoreLayout(d.value);
|
||||
} else if(_latestSnapshot) {
|
||||
_syncPipelineLayout(_latestSnapshot.pipeline, _pipelineRosterOrder(_latestSnapshot.roster || [], _latestSnapshot.pipeline));
|
||||
_renderPipelineDecor(_latestSnapshot.pipeline, _latestSnapshot.roster || []);
|
||||
}
|
||||
}
|
||||
if(d.type === 'pixelOfficeLayoutSaved'){
|
||||
if(d.value && !d.value.reset) {
|
||||
_hasSavedLayout = true;
|
||||
_layoutSource = 'saved';
|
||||
}
|
||||
if(d.value && d.value.reset){
|
||||
// 디폴트로 리셋된 경우 — 페이지를 재로딩해서 코드 기본값으로 복귀.
|
||||
location.reload();
|
||||
|
||||
Reference in New Issue
Block a user