dina1 commited on
Commit
986b890
·
verified ·
1 Parent(s): fcd1527

Update playwright_model.py

Browse files
Files changed (1) hide show
  1. playwright_model.py +30 -67
playwright_model.py CHANGED
@@ -6,7 +6,6 @@ from fpdf import FPDF
6
 
7
  OUTPUT_DIR = "static/outputs"
8
 
9
-
10
  async def capture_workflows(public_url: str, pdf_filename: str = "workflow_screens.pdf"):
11
  os.makedirs(OUTPUT_DIR, exist_ok=True)
12
  pdf_path = os.path.join(OUTPUT_DIR, pdf_filename)
@@ -17,6 +16,7 @@ async def capture_workflows(public_url: str, pdf_filename: str = "workflow_scree
17
  print(f"Opening page: {public_url}")
18
  await page.goto(public_url, wait_until="load")
19
 
 
20
  async def wait_for_layout_stable():
21
  await page.evaluate("""
22
  (async () => {
@@ -40,6 +40,7 @@ async def capture_workflows(public_url: str, pdf_filename: str = "workflow_scree
40
  })();
41
  """)
42
 
 
43
  async def fix_sidebar_permanently():
44
  try:
45
  await page.evaluate("""
@@ -47,7 +48,7 @@ async def capture_workflows(public_url: str, pdf_filename: str = "workflow_scree
47
  if (sidebar) {
48
  const rect = sidebar.getBoundingClientRect();
49
  const sidebarWidth = rect.width || sidebar.offsetWidth || 220;
50
- const topOffset = 60; // pixels to push sidebar downward below header
51
  sidebar.style.position = 'fixed';
52
  sidebar.style.top = topOffset + 'px';
53
  sidebar.style.left = '0';
@@ -58,43 +59,52 @@ async def capture_workflows(public_url: str, pdf_filename: str = "workflow_scree
58
  sidebar.style.transition = 'none';
59
  sidebar.dataset.locked = 'true';
60
  }
 
61
  const main = document.querySelector('main, .main-content, .app-body, .content');
62
  if (main && sidebar) {
63
  main.style.marginLeft = sidebar.offsetWidth + 'px';
64
  main.style.position = 'relative';
65
  main.style.top = '0';
66
  }
 
67
  window.scrollTo(0, 0);
68
  document.documentElement.scrollTop = 0;
69
  document.body.scrollTop = 0;
70
  document.body.style.margin = '0';
71
  document.body.style.padding = '0';
72
- document.body.style.overflow = 'hidden';
73
  """)
74
  except Exception as e:
75
  print(f"[WARN] Sidebar fix failed: {e}")
76
 
 
77
  await page.wait_for_selector("aside, .sidebar, nav", timeout=5000)
78
  await wait_for_layout_stable()
79
  await fix_sidebar_permanently()
80
- await asyncio.sleep(0.6)
81
 
 
82
  js_logic = """
83
  (function(){
84
- const getAllMenus = ()=>[...document.querySelectorAll('.menu-item, nav a, aside a, .sidebar a')];
85
  const screens=[...document.querySelectorAll('.screen')];
86
  window.__ordered=[];
87
  const seen=new Set();
88
- for(const m of getAllMenus()){
 
89
  let id=m.dataset.screen||m.dataset.target;
90
  if(!id){
91
- const href=m.getAttribute('href')||m.getAttribute('data-target')||'';
92
  if(href && href.startsWith('#')) id=href.substring(1);
93
  }
94
  const s=screens.find(x=>x.id===id);
95
- if(s && !seen.has(s)){seen.add(s);window.__ordered.push({menuRef:id,screen:s});}
96
  }
97
- for(const s of screens) if(!seen.has(s)) window.__ordered.push({menuRef:null,screen:s});
 
 
 
 
98
  window.__visitedWorkflows=[];
99
  window.__currentIndex=0;
100
  window.__done=false;
@@ -109,75 +119,28 @@ async def capture_workflows(public_url: str, pdf_filename: str = "workflow_scree
109
  return list;
110
  };
111
 
112
- window.__findMenuForScreen = function(screen){
113
- if(!screen) return null;
114
- const idCandidates = [];
115
- if(screen.id) idCandidates.push(screen.id);
116
- const dataName = screen.getAttribute('data-name');
117
- if(dataName) idCandidates.push(dataName);
118
- // also try visible title text inside the screen
119
- const titleEl = screen.querySelector('.page-title, .header-title, h1, h2, h3');
120
- if(titleEl && titleEl.textContent) idCandidates.push(titleEl.textContent.trim());
121
-
122
- const menus = getAllMenus();
123
- for(const m of menus){
124
- let mid = m.dataset.screen||m.dataset.target||'';
125
- if(!mid){
126
- const href = m.getAttribute('href')||m.getAttribute('data-target')||'';
127
- if(href && href.startsWith('#')) mid = href.substring(1);
128
- }
129
- if(mid && idCandidates.includes(mid)) return m;
130
- }
131
- // fallback: try matching by visible text
132
- for(const m of menus){
133
- const txt = m.textContent?.trim();
134
- if(txt && idCandidates.some(c=>c.toLowerCase()===txt.toLowerCase())) return m;
135
- }
136
- return null;
137
- };
138
-
139
- window.__clearHighlight = function(){
140
- getAllMenus().forEach(el=>{
141
- el.style.backgroundColor='';
142
- el.style.color='';
143
- el.style.borderRadius='';
144
- el.style.boxShadow='';
145
- });
146
- };
147
-
148
- window.__highlightMenuElement = function(menuEl){
149
- window.__clearHighlight();
150
- if(!menuEl) return;
151
- menuEl.style.backgroundColor='#0078d4';
152
- menuEl.style.color='white';
153
- menuEl.style.borderRadius='4px';
154
- menuEl.style.boxShadow='0 1px 3px rgba(0,0,0,0.15)';
155
- menuEl.scrollIntoView({block:'nearest', inline:'nearest'});
156
- };
157
-
158
  window.__captureNext=async function(){
159
  if(window.__done) return false;
160
  if(window.__currentIndex>=window.__ordered.length){window.__done=true;return false;}
 
161
  const pair=window.__ordered[window.__currentIndex];
162
- const {screen}=pair;
163
  if(!screen){window.__done=true;return false;}
 
164
  const wfName=screen.id || screen.getAttribute('data-name') || ('screen_'+window.__currentIndex);
165
  if(window.__visitedWorkflows.includes(wfName)){
166
  window.__currentIndex++;
167
  return window.__captureNext();
168
  }
169
- window.__visitedWorkflows.push(wfName);
170
 
 
171
  document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active'));
 
172
  screen.classList.add('active');
173
-
174
- // find matching menu dynamically each time
175
- const menuEl = window.__findMenuForScreen(screen);
176
- window.__highlightMenuElement(menuEl);
177
-
178
- // center screen in viewport
179
  screen.scrollIntoView({behavior:'smooth',block:'center'});
180
  window.__currentIndex++;
 
181
  const subs = window.__getSubScreens(screen);
182
  return {screenName:wfName, subScreens:subs};
183
  };
@@ -191,11 +154,12 @@ async def capture_workflows(public_url: str, pdf_filename: str = "workflow_scree
191
  })();
192
  """
193
  await page.evaluate(js_logic)
194
- await asyncio.sleep(0.6)
195
 
196
  screenshots = []
197
  index = 0
198
 
 
199
  while True:
200
  result = await page.evaluate("window.__captureNext()")
201
  if not result:
@@ -208,7 +172,7 @@ async def capture_workflows(public_url: str, pdf_filename: str = "workflow_scree
208
 
209
  await wait_for_layout_stable()
210
  await fix_sidebar_permanently()
211
- await asyncio.sleep(0.6)
212
  await page.screenshot(path=screenshot_path, full_page=True)
213
  screenshots.append(screenshot_path)
214
 
@@ -232,11 +196,10 @@ async def capture_workflows(public_url: str, pdf_filename: str = "workflow_scree
232
  await page.evaluate(f"window.__clickSubScreen('{sub}')")
233
  await wait_for_layout_stable()
234
  await fix_sidebar_permanently()
235
- await asyncio.sleep(0.6)
236
 
237
  sub_name_clean = sub.replace(" ", "_").lower()
238
  sub_path = os.path.join(OUTPUT_DIR, f"{screen_name}_{sub_name_clean}.png")
239
-
240
  await page.screenshot(path=sub_path, full_page=True)
241
  screenshots.append(sub_path)
242
 
 
6
 
7
  OUTPUT_DIR = "static/outputs"
8
 
 
9
  async def capture_workflows(public_url: str, pdf_filename: str = "workflow_screens.pdf"):
10
  os.makedirs(OUTPUT_DIR, exist_ok=True)
11
  pdf_path = os.path.join(OUTPUT_DIR, pdf_filename)
 
16
  print(f"Opening page: {public_url}")
17
  await page.goto(public_url, wait_until="load")
18
 
19
+ # Wait for layout to stabilize
20
  async def wait_for_layout_stable():
21
  await page.evaluate("""
22
  (async () => {
 
40
  })();
41
  """)
42
 
43
+ # Fix sidebar permanently below top bar
44
  async def fix_sidebar_permanently():
45
  try:
46
  await page.evaluate("""
 
48
  if (sidebar) {
49
  const rect = sidebar.getBoundingClientRect();
50
  const sidebarWidth = rect.width || sidebar.offsetWidth || 220;
51
+ const topOffset = 60; // px height of top bar
52
  sidebar.style.position = 'fixed';
53
  sidebar.style.top = topOffset + 'px';
54
  sidebar.style.left = '0';
 
59
  sidebar.style.transition = 'none';
60
  sidebar.dataset.locked = 'true';
61
  }
62
+
63
  const main = document.querySelector('main, .main-content, .app-body, .content');
64
  if (main && sidebar) {
65
  main.style.marginLeft = sidebar.offsetWidth + 'px';
66
  main.style.position = 'relative';
67
  main.style.top = '0';
68
  }
69
+
70
  window.scrollTo(0, 0);
71
  document.documentElement.scrollTop = 0;
72
  document.body.scrollTop = 0;
73
  document.body.style.margin = '0';
74
  document.body.style.padding = '0';
75
+ document.body.style.overflow = 'hidden';
76
  """)
77
  except Exception as e:
78
  print(f"[WARN] Sidebar fix failed: {e}")
79
 
80
+ # Wait for sidebar to appear
81
  await page.wait_for_selector("aside, .sidebar, nav", timeout=5000)
82
  await wait_for_layout_stable()
83
  await fix_sidebar_permanently()
84
+ await asyncio.sleep(1)
85
 
86
+ # JS to enumerate workflows and tabs
87
  js_logic = """
88
  (function(){
89
+ const menus=[...document.querySelectorAll('.menu-item')];
90
  const screens=[...document.querySelectorAll('.screen')];
91
  window.__ordered=[];
92
  const seen=new Set();
93
+
94
+ for(const m of menus){
95
  let id=m.dataset.screen||m.dataset.target;
96
  if(!id){
97
+ const href=m.getAttribute('href');
98
  if(href && href.startsWith('#')) id=href.substring(1);
99
  }
100
  const s=screens.find(x=>x.id===id);
101
+ if(s && !seen.has(s)){seen.add(s);window.__ordered.push({menu:m,screen:s});}
102
  }
103
+
104
+ for(const s of screens)
105
+ if(!seen.has(s))
106
+ window.__ordered.push({menu:null,screen:s});
107
+
108
  window.__visitedWorkflows=[];
109
  window.__currentIndex=0;
110
  window.__done=false;
 
119
  return list;
120
  };
121
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  window.__captureNext=async function(){
123
  if(window.__done) return false;
124
  if(window.__currentIndex>=window.__ordered.length){window.__done=true;return false;}
125
+
126
  const pair=window.__ordered[window.__currentIndex];
127
+ const {menu,screen}=pair;
128
  if(!screen){window.__done=true;return false;}
129
+
130
  const wfName=screen.id || screen.getAttribute('data-name') || ('screen_'+window.__currentIndex);
131
  if(window.__visitedWorkflows.includes(wfName)){
132
  window.__currentIndex++;
133
  return window.__captureNext();
134
  }
 
135
 
136
+ window.__visitedWorkflows.push(wfName);
137
  document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active'));
138
+ document.querySelectorAll('.menu-item').forEach(m=>m.classList.remove('active'));
139
  screen.classList.add('active');
140
+ if(menu) menu.classList.add('active');
 
 
 
 
 
141
  screen.scrollIntoView({behavior:'smooth',block:'center'});
142
  window.__currentIndex++;
143
+
144
  const subs = window.__getSubScreens(screen);
145
  return {screenName:wfName, subScreens:subs};
146
  };
 
154
  })();
155
  """
156
  await page.evaluate(js_logic)
157
+ await asyncio.sleep(1)
158
 
159
  screenshots = []
160
  index = 0
161
 
162
+ # Capture all screens + sub-screens
163
  while True:
164
  result = await page.evaluate("window.__captureNext()")
165
  if not result:
 
172
 
173
  await wait_for_layout_stable()
174
  await fix_sidebar_permanently()
175
+ await asyncio.sleep(0.8)
176
  await page.screenshot(path=screenshot_path, full_page=True)
177
  screenshots.append(screenshot_path)
178
 
 
196
  await page.evaluate(f"window.__clickSubScreen('{sub}')")
197
  await wait_for_layout_stable()
198
  await fix_sidebar_permanently()
199
+ await asyncio.sleep(0.8)
200
 
201
  sub_name_clean = sub.replace(" ", "_").lower()
202
  sub_path = os.path.join(OUTPUT_DIR, f"{screen_name}_{sub_name_clean}.png")
 
203
  await page.screenshot(path=sub_path, full_page=True)
204
  screenshots.append(sub_path)
205