Coverage for src/mesh/views/components/stepper.py: 24%
112 statements
« prev ^ index » next coverage.py v7.9.0, created at 2025-09-10 11:20 +0000
« prev ^ index » next coverage.py v7.9.0, created at 2025-09-10 11:20 +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 this is a step below the currently displayed/selected step.
29 below_active: bool = field(default=False)
30 # Whether the step config is navigable.
31 # It can be True for steps after active one if you have used the Previous button or a direct link to a step.
32 can_navigate: bool = field(default=False)
33 # For some steps, the Next button is the form submit button
34 # For others (use_href_for_next=True), the Next button is a simple link
35 use_href_for_next_button: bool = field(default=False)
38@dataclass
39class StepperConfig:
40 steps: list[StepConfig] = field(default_factory=list)
41 title: str = field(default="")
42 # Id of the active step
43 active: str = field(default="")
44 submission: Submission = None
46 def get_step(self, step_id: str) -> StepConfig | None:
47 return next((s for s in self.steps if s.id == step_id), None)
49 def set_active_step(self, step_id: str):
50 below_active_step = True
52 for s in self.steps:
53 s.below_active = below_active_step
55 if s.id == step_id:
56 below_active_step = False
57 s.active = True
58 self.active = step_id
60 def get_next_step(self, step_id):
61 next_step = None
62 i = 0
63 while next_step is None and i < len(self.steps):
64 if self.steps[i].id == step_id:
65 if i + 1 < len(self.steps):
66 next_step = self.steps[i + 1]
67 i += 1
68 return next_step
70 def get_previous_step(self, step_id):
71 previous_step = None
72 i = 0
73 while previous_step is None and i < len(self.steps):
74 if self.steps[i].id == step_id:
75 if i - 1 > -1:
76 previous_step = self.steps[i - 1]
77 i += 1
78 return previous_step
80 def set_completed_steps(self, step_ids: list[str]):
81 for step in self.steps:
82 step.completed = step.id in step_ids
84 def get_next_button(self):
85 step_id = self.active
86 button = None
87 next_step = self.get_next_step(step_id)
88 current_step = self.get_step(step_id)
89 id = "next" # if step_id != "metadata" else "next-from-mesh"
90 data_attrs = {}
91 if step_id == "metadata":
92 data_attrs["data-url"] = [
93 reverse_lazy("mesh:submission_update_vuejs", kwargs={"pk": self.submission.pk})
94 ]
96 if next_step is not None:
97 current_step = self.get_step(step_id)
98 href = next_step.href if current_step.use_href_for_next_button else None
99 button = add_stepper_button(
100 id=id,
101 title="Next",
102 icon_class="fa-right-long",
103 name=FormAction.NEXT.value,
104 href=href,
105 btn_classes=["button-highlight", "next-button-to-watch"],
106 data_attrs=data_attrs,
107 submit_button=True if step_id != "metadata" else False,
108 )
109 return button
111 def get_previous_button(self):
112 step_id = self.active
113 button = None
114 previous_step = self.get_previous_step(step_id)
115 if previous_step is not None:
116 button = add_stepper_button(
117 id="previous",
118 title="Previous",
119 icon_class="fa-left-long",
120 name=FormAction.PREVIOUS.value,
121 href=previous_step.href,
122 )
123 return button
126def get_submission_stepper(submission: Submission | None) -> StepperConfig:
127 """
128 Returns the submission stepper config adapted with the given submission.
129 The active step is not set.
130 """
131 preprint_step = StepConfig(id="preprint", title=_("Init"))
132 metadata_step = StepConfig(id="metadata", title=_("Article data"))
133 info_step = StepConfig(id="info", title=_("Submission info"))
134 confirm_step = StepConfig(id="confirm", title=_("Confirm"))
136 preprint_step.can_navigate = True
137 preprint_step.href = reverse_lazy("mesh:submission_create")
139 if submission:
140 preprint_step.completed = True
141 preprint_step.href = reverse_lazy(
142 "mesh:submission_update_preprint", kwargs={"pk": submission.pk}
143 )
144 metadata_step.can_navigate = True
145 metadata_step.href = reverse_lazy(
146 "mesh:submission_edit_article_metadata", kwargs={"pk": submission.pk}
147 )
149 if hasattr(submission.current_version, "main_file"):
150 metadata_step.completed = True
151 info_step.can_navigate = True
152 info_step.href = reverse_lazy(
153 "mesh:submission_info_update", kwargs={"pk": submission.pk}
154 )
156 if submission.author_agreement:
157 info_step.completed = True
158 confirm_step.can_navigate = True
159 confirm_step.href = reverse_lazy(
160 "mesh:submission_confirm", kwargs={"pk": submission.pk}
161 )
163 return StepperConfig(
164 steps=[preprint_step, metadata_step, info_step, confirm_step],
165 title=_("Submit process"),
166 submission=submission,
167 )
170def add_stepper_button(
171 id, title, icon_class, name, href=None, btn_classes=[], data_attrs={}, submit_button=True
172):
173 attrs = {"name": [name]} | data_attrs
174 if href is None:
175 if submit_button:
176 attrs["type"] = ["submit"]
177 attrs["form"] = ["id-form-fullpage"]
178 btn_classes.append("save-button")
179 attrs["class"] = btn_classes
180 else:
181 attrs["href"] = [href]
182 btn_classes.extend(["as-button", "save-button"])
183 attrs["class"] = btn_classes
185 return Button(
186 id=id,
187 title=_(title),
188 icon_class=icon_class,
189 # attrs={"href": [author_step.href], "class": ["as-button"]},
190 attrs=attrs,
191 )