Coverage for src/mesh/views/components/stepper.py: 26%
103 statements
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-28 07:45 +0000
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-28 07:45 +0000
1from __future__ import annotations
3from dataclasses import dataclass, field
4from typing import TYPE_CHECKING
6from django.urls import reverse_lazy
7from django.utils.translation import gettext_lazy as _
9from mesh.views.forms.base_forms import FormAction
11from .button import Button
13if TYPE_CHECKING: 13 ↛ 14line 13 didn't jump to line 14 because the condition on line 13 was never true
14 from ...models.submission_models import Submission
17@dataclass
18class StepConfig:
19 id: str
20 title: str
21 href: str = field(default="")
22 description: str = field(default="")
23 tooltip: str = field(default="")
24 # Whether the step has already been completed
25 completed: bool = field(default=False)
26 # Whether this is the currently displayed/selected step.
27 active: bool = field(default=False)
28 # Whether the step config is navigable.
29 # Usually it should be equals to `previous_step.completed`
30 can_navigate: bool = field(default=False)
31 # For some steps, the Next button is the form submit button
32 # For others (use_href_for_next=True), the Next button is a simple link
33 use_href_for_next_button: bool = field(default=False)
36@dataclass
37class StepperConfig:
38 steps: list[StepConfig] = field(default_factory=list)
39 title: str = field(default="")
40 # Id of the active step
41 active: str = field(default="")
43 def get_step(self, step_id: str) -> StepConfig | None:
44 return next((s for s in self.steps if s.id == step_id), None)
46 def set_active_step(self, step_id: str):
47 step = self.get_step(step_id)
48 if step is None:
49 return
51 for s in self.steps:
52 s.active = False
53 step.active = True
54 self.active = step_id
56 def get_next_step(self, step_id):
57 next_step = None
58 i = 0
59 while next_step is None and i < len(self.steps):
60 if self.steps[i].id == step_id:
61 if i + 1 < len(self.steps):
62 next_step = self.steps[i + 1]
63 i += 1
64 return next_step
66 def get_previous_step(self, step_id):
67 previous_step = None
68 i = 0
69 while previous_step is None and i < len(self.steps):
70 if self.steps[i].id == step_id:
71 if i - 1 > -1:
72 previous_step = self.steps[i - 1]
73 i += 1
74 return previous_step
76 def set_completed_steps(self, step_ids: list[str]):
77 for step in self.steps:
78 step.completed = step.id in step_ids
80 def get_next_button(self):
81 step_id = self.active
82 button = None
83 next_step = self.get_next_step(step_id)
84 if next_step is not None:
85 current_step = self.get_step(step_id)
86 href = next_step.href if current_step.use_href_for_next_button else None
87 button = add_stepper_button(
88 id="next",
89 title="Next",
90 icon_class="fa-right-long",
91 name=FormAction.NEXT.value,
92 href=href,
93 btn_classes=["button-highlight"],
94 )
95 return button
97 def get_previous_button(self):
98 step_id = self.active
99 button = None
100 previous_step = self.get_previous_step(step_id)
101 if previous_step is not None:
102 button = add_stepper_button(
103 id="previous",
104 title="Previous",
105 icon_class="fa-left-long",
106 name=FormAction.PREVIOUS.value,
107 href=previous_step.href,
108 )
109 return button
112def get_submission_stepper(submission: Submission | None) -> StepperConfig:
113 """
114 Returns the submission stepper config adapted with the given submission.
115 The active step is not set.
116 """
117 metadata_step = StepConfig(id="metadata", title=_("Article metadata"))
118 authors_step = StepConfig(
119 id="authors",
120 title=_("Authors"),
121 use_href_for_next_button=True,
122 # description="I have something very very VERY long to say. Please make some space in the layout to render this description properly."
123 )
124 version_step = StepConfig(id="version", title=_("Files"))
125 confirm_step = StepConfig(id="confirm", title=_("Confirm"))
127 if submission:
128 metadata_step.href = reverse_lazy("mesh:submission_update", kwargs={"pk": submission.pk})
129 metadata_step.completed = True
130 metadata_step.can_navigate = True
132 authors_step.href = reverse_lazy("mesh:submission_authors", kwargs={"pk": submission.pk})
133 authors_step.completed = submission.authors.exists() # type:ignore
134 authors_step.can_navigate = True
136 version = submission.current_version
137 version_step.href = (
138 reverse_lazy("mesh:submission_version_update", kwargs={"pk": version.pk})
139 if version
140 else reverse_lazy(
141 "mesh:submission_version_create",
142 kwargs={"submission_pk": submission.pk},
143 )
144 )
145 version_step.completed = version is not None
146 version_step.can_navigate = authors_step.completed
148 if version:
149 confirm_step.href = reverse_lazy(
150 "mesh:submission_confirm", kwargs={"pk": submission.pk}
151 )
152 confirm_step.can_navigate = True
154 return StepperConfig(
155 steps=[metadata_step, authors_step, version_step, confirm_step],
156 title=_("Submit process"),
157 )
160def add_stepper_button(id, title, icon_class, name, href=None, btn_classes=[]):
161 attrs = {"name": [name]}
162 if href is None:
163 attrs["type"] = ["submit"]
164 attrs["form"] = ["id-form-fullpage"]
165 btn_classes.append("save-button")
166 attrs["class"] = btn_classes
167 else:
168 attrs["href"] = [href]
169 btn_classes.extend(["as-button", "save-button"])
170 attrs["class"] = btn_classes
172 return Button(
173 id=id,
174 title=_(title),
175 icon_class=icon_class,
176 # attrs={"href": [author_step.href], "class": ["as-button"]},
177 attrs=attrs,
178 )