|
11 | 11 |
|
12 | 12 | class ProjectUserStories(models.Model): |
13 | 13 | _name = 'project.scrum.us' |
14 | | - _inherit = ['mail.thread', 'mail.activity.mixin'] |
| 14 | + _inherit = ['mail.thread', 'mail.activity.mixin', 'mermaid.mixin'] |
15 | 15 | _description = 'Project Scrum Use Stories' |
16 | 16 | _order = 'sequence' |
17 | 17 |
|
18 | | - _mermaid_keywords = r"^(graph|sequenceDiagram|classDiagram|stateDiagram|" \ |
19 | | - r"erDiagram|flowchart|pie|journey|gantt|gitGraph)\b" |
20 | 18 |
|
21 | 19 | def create_test_case_from_us(self): |
22 | 20 | active_ids = self.env['project.scrum.us'].browse(self.env.context.get('active_ids')) |
@@ -174,100 +172,3 @@ def _read_group_sprint_id(self, present_ids, domain): |
174 | 172 | 'sprint_ids': _read_group_sprint_id, |
175 | 173 | } |
176 | 174 |
|
177 | | - mermaid_editor = fields.Html(string="Editor", copy=False) |
178 | | - |
179 | | - def wrap_mermaid_in_pre(self, mermaid_editor): |
180 | | - """ |
181 | | - Finds Mermaid diagrams in HTML content and wraps them inside <pre> tags. |
182 | | -
|
183 | | - Args: |
184 | | - mermaid_editor (str): The raw HTML content. |
185 | | -
|
186 | | - Returns: |
187 | | - str: Modified HTML with Mermaid diagrams wrapped in <pre>. |
188 | | - """ |
189 | | - if not mermaid_editor: |
190 | | - return "" |
191 | | - |
192 | | - soup = BeautifulSoup(mermaid_editor, "html.parser") |
193 | | - |
194 | | - # Check for existing pre tags with mermaid content |
195 | | - if soup.find('pre', class_='mermaid'): |
196 | | - return str(soup) |
197 | | - |
198 | | - # Find potential Mermaid blocks |
199 | | - potential_blocks = [tag for tag in soup.find_all(["p", "div"]) |
200 | | - if re.search(self._mermaid_keywords, tag.get_text().lstrip(), re.MULTILINE)] |
201 | | - |
202 | | - # Process each potential block |
203 | | - for start_tag in potential_blocks: |
204 | | - diagram_content = [] |
205 | | - siblings_to_remove = [] |
206 | | - current_tag = start_tag |
207 | | - |
208 | | - # Process starting tag |
209 | | - for child in BeautifulSoup(str(current_tag), "html.parser").find_all(string=True): |
210 | | - if child.strip(): |
211 | | - diagram_content.append(html.unescape(str(child))) |
212 | | - |
213 | | - # Process potential siblings |
214 | | - next_tag = current_tag.next_sibling |
215 | | - while next_tag and hasattr(next_tag, 'name') and next_tag.name in ['p', 'div']: |
216 | | - if re.search(self._mermaid_keywords, next_tag.get_text().lstrip(), re.MULTILINE): |
217 | | - break |
218 | | - |
219 | | - for child in BeautifulSoup(str(next_tag), "html.parser").find_all(string=True): |
220 | | - if child.strip(): |
221 | | - diagram_content.append(html.unescape(str(child))) |
222 | | - |
223 | | - siblings_to_remove.append(next_tag) |
224 | | - next_tag = next_tag.next_sibling |
225 | | - |
226 | | - # Create pre tag and replace original tag |
227 | | - pre_tag = soup.new_tag("pre") |
228 | | - pre_tag.string = "\n".join(diagram_content) |
229 | | - pre_tag['class'] = 'mermaid' |
230 | | - start_tag.replace_with(pre_tag) |
231 | | - |
232 | | - # Remove siblings that were processed |
233 | | - for sibling in siblings_to_remove: |
234 | | - sibling.extract() # extract() is an alternative to decompose() |
235 | | - |
236 | | - return str(soup) |
237 | | - |
238 | | - @api.depends('mermaid_editor') |
239 | | - def _compute_mermaid_editor(self): |
240 | | - """ |
241 | | - Computes the Mermaid diagram text and wraps it in <pre> tags if needed. |
242 | | - Only processes content that appears to be Mermaid diagrams. |
243 | | - """ |
244 | | - for rec in self: |
245 | | - # Skip empty content or when called from our own update |
246 | | - if not rec.mermaid_editor: |
247 | | - rec.mermaid_diagram = "" |
248 | | - continue |
249 | | - |
250 | | - soup = BeautifulSoup(rec.mermaid_editor, "html.parser") |
251 | | - |
252 | | - # Check for existing pre tag with mermaid content |
253 | | - pre_tag = soup.find('pre', class_='mermaid') |
254 | | - if pre_tag: |
255 | | - rec.mermaid_diagram = pre_tag.get_text() |
256 | | - continue |
257 | | - |
258 | | - # Check if content appears to be mermaid format |
259 | | - text_content = soup.get_text('\n', strip=True) |
260 | | - if not re.search(self._mermaid_keywords, text_content, re.MULTILINE): |
261 | | - rec.mermaid_diagram = "" |
262 | | - continue |
263 | | - |
264 | | - # Extract text preserving structure and indentation |
265 | | - text_content = soup.get_text('\n', strip=False).replace('\xa0', ' ') |
266 | | - rec.mermaid_diagram = text_content |
267 | | - |
268 | | - # Wrap in pre tags |
269 | | - wrapped_content = self.wrap_mermaid_in_pre(rec.mermaid_editor) |
270 | | - if wrapped_content != rec.mermaid_editor: |
271 | | - rec.mermaid_editor = wrapped_content |
272 | | - |
273 | | - mermaid_diagram = fields.Text(string="Diagram", compute=_compute_mermaid_editor, copy=False) |
0 commit comments