Skip to content

Commit 3d7efcd

Browse files
committed
[IMP] runbot: preferences shown in dialog instead of collapse
Uses the BS modal styling but adapted to the `<dialog>` element instead of BS javascript. Note: preferences in itself aren't modified as this is not this commit's goal. Note: includes a very adhoc and basic polyfill to support command and commandfor attributes on "older" browser (i.e. tested Safari 18 < 26 and Firefox ESR 140).
1 parent b71869c commit 3d7efcd

3 files changed

Lines changed: 91 additions & 64 deletions

File tree

runbot/__manifest__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
'runbot/static/lib/fontawesome/css/font-awesome.css',
8383
'runbot/static/src/css/runbot.css',
8484

85+
'runbot/static/src/js/polyfill_command_api.js',
8586
'runbot/static/lib/jquery/jquery.js',
8687
'runbot/static/lib/bootstrap/js/bootstrap.bundle.js',
8788
'runbot/static/src/js/runbot.js',

runbot/static/src/css/runbot.css

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ table {
152152
font-size: 0.875rem;
153153
}
154154

155+
dialog.modal {
156+
--bs-modal-zindex: auto;
157+
margin: 0;
158+
padding: 0;
159+
border: none;
160+
background-color: transparent;
161+
162+
&::backdrop {
163+
background-color: rgba(0, 0, 0, 0.5);
164+
}
165+
166+
&[open] {
167+
display: block;
168+
}
169+
}
170+
155171
.fa {
156172
line-height: inherit; /* reset fa icon line height to body height*/
157173
}

runbot/templates/utils.xml

Lines changed: 74 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@
6767
</t>
6868
</t>
6969
<li class="nav-item divider"/>
70-
71-
<li class="nav-item dropdown">
72-
<a data-bs-toggle="collapse" href="#collapsePreference" role="button" class="nav-link">
70+
71+
<li class="nav-item">
72+
<button command="show-modal" commandfor="collapsePreference" type="button" class="nav-link">
7373
<i class="fa fa-gear"/>
74-
</a>
74+
</button>
7575
</li>
7676
<li class="nav-item divider" t-ignore="true"/>
7777
<t t-if="not user_id._is_public()">
@@ -147,68 +147,78 @@
147147
</div>
148148
</div>
149149
</div></div>
150-
<div id="collapsePreference" class="collapse">
151-
<form class="px-4 py-3" method="post" action="/runbot/submit" id="preferences_form">
152-
<input type="hidden" name="redirect" t-att-value="current_path"/>
153-
<div>
154-
<div class="form-check form-switch">
155-
<label for="more" class="form-check-label" >More info</label>
156-
<input onclick="document.getElementById('preferences_form').submit()" class="form-check-input" type="checkbox" role="switch" id="more" name="more" t-att-checked="more"/>
157-
</div></div>
158-
<div>
159-
<label for="theme_selection" style="min-width: 80px">Theme:</label>
160-
<div id="theme_selection" class="text-nowrap btn-group btn-group-sm" role="group">
161-
<button onclick="document.cookie = 'theme=legacy; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='legacy' else 'secondary'}}">Legacy</button>
162-
<button onclick="document.cookie = 'theme=dark; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='dark' else 'secondary'}}">Dark</button>
163-
<button onclick="document.cookie = 'theme=light; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='light' else 'secondary'}}">Light</button>
164-
<button onclick="document.cookie = 'theme=red404; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='red404' else 'secondary'}}">Red404</button>
165-
</div></div>
166-
<div>
167-
<label for="theme_selection" style="min-width: 80px">Sticky:</label>
168-
<div class="text-nowrap btn-group btn-group-sm" role="group">
169-
<button onclick="document.cookie = 'filter_mode=default; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='default' else 'secondary'}}" help="Only display sticky except if searching">Default</button>
170-
<button onclick="document.cookie = 'filter_mode=all; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='all' else 'secondary'}}">All</button>
171-
<button onclick="document.cookie = 'filter_mode=sticky; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='sticky' else 'secondary'}}">Sticky only</button>
172-
<button onclick="document.cookie = 'filter_mode=nosticky; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='nosticky' else 'secondary'}}">Dev only</button>
173-
</div></div>
174-
<div>
175-
<label for="theme_selection" style="min-width: 80px">Category:</label>
176-
<div class="text-nowrap btn-group btn-group-sm" role="group">
177-
<t t-foreach="categories" t-as="category">
178-
<button t-attf-onclick="document.cookie = 'category={{category.id}}; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if category.id == active_category_id else 'secondary'}}" t-out="category.name"/>
179-
</t>
180-
</div></div>
181-
182-
<hr class="separator"/>
183-
<div t-if="triggers">
184-
<input type="hidden" name="update_triggers" t-att-value="project.id"/>
185-
<t t-foreach="categories" t-as="category">
186-
<t t-set="category_triggers" t-value="triggers.filtered(lambda t: not t.manual and t.category_id == category)"/>
187-
<t t-if="category_triggers">
188-
<h3 t-out="category.name"/>
189-
<div class="row">
190-
<t t-foreach="category_triggers" t-as="trigger">
191-
<div class="col-md-3 text-nowrap">
192-
<input t-attf-class="trigger_selection {{'trigger_selection_hide' if trigger.hide else 'trigger_selection_show'}}" type="checkbox" t-attf-name="trigger_{{trigger.id}}" t-attf-id="trigger_{{trigger.id}}" t-att-checked="not trigger.hide if trigger_display is None else trigger.id in trigger_display"/>
193-
<label t-attf-for="trigger_{{trigger.id}}" t-out="trigger.name"/>
150+
<dialog id="collapsePreference" class="modal modal-xl">
151+
<div class="modal-dialog">
152+
<form class="modal-content" method="post" action="/runbot/submit" id="preferences_form">
153+
<header class="modal-header">
154+
<h5 class="modal-title">Preferences</h5>
155+
<button type="button" class="btn-close" command="close" commandfor="collapsePreference"/>
156+
</header>
157+
<div class="modal-body">
158+
<input type="hidden" name="redirect" t-att-value="current_path"/>
159+
<div>
160+
<div class="form-check form-switch">
161+
<label for="more" class="form-check-label" >More info</label>
162+
<input onclick="document.getElementById('preferences_form').submit()" class="form-check-input" type="checkbox" role="switch" id="more" name="more" t-att-checked="more"/>
163+
</div></div>
164+
<div>
165+
<label for="theme_selection" style="min-width: 80px">Theme:</label>
166+
<div id="theme_selection" class="text-nowrap btn-group btn-group-sm" role="group">
167+
<button onclick="document.cookie = 'theme=legacy; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='legacy' else 'secondary'}}">Legacy</button>
168+
<button onclick="document.cookie = 'theme=dark; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='dark' else 'secondary'}}">Dark</button>
169+
<button onclick="document.cookie = 'theme=light; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='light' else 'secondary'}}">Light</button>
170+
<button onclick="document.cookie = 'theme=red404; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if theme=='red404' else 'secondary'}}">Red404</button>
171+
</div></div>
172+
<div>
173+
<label for="theme_selection" style="min-width: 80px">Sticky:</label>
174+
<div class="text-nowrap btn-group btn-group-sm" role="group">
175+
<button onclick="document.cookie = 'filter_mode=default; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='default' else 'secondary'}}" help="Only display sticky except if searching">Default</button>
176+
<button onclick="document.cookie = 'filter_mode=all; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='all' else 'secondary'}}">All</button>
177+
<button onclick="document.cookie = 'filter_mode=sticky; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='sticky' else 'secondary'}}">Sticky only</button>
178+
<button onclick="document.cookie = 'filter_mode=nosticky; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if filter_mode=='nosticky' else 'secondary'}}">Dev only</button>
179+
</div></div>
180+
<div>
181+
<label for="theme_selection" style="min-width: 80px">Category:</label>
182+
<div class="text-nowrap btn-group btn-group-sm" role="group">
183+
<t t-foreach="categories" t-as="category">
184+
<button t-attf-onclick="document.cookie = 'category={{category.id}}; expires=Thu, 1 Dec 2942 12:00:00 UTC; path=/'; location.reload();" type="button" t-attf-class="btn btn-{{'primary' if category.id == active_category_id else 'secondary'}}" t-out="category.name"/>
185+
</t>
186+
</div></div>
187+
188+
<hr class="separator"/>
189+
<div t-if="triggers">
190+
<input type="hidden" name="update_triggers" t-att-value="project.id"/>
191+
<t t-foreach="categories" t-as="category">
192+
<t t-set="category_triggers" t-value="triggers.filtered(lambda t: not t.manual and t.category_id == category)"/>
193+
<t t-if="category_triggers">
194+
<h3 t-out="category.name"/>
195+
<div class="row">
196+
<t t-foreach="category_triggers" t-as="trigger">
197+
<div class="col-md-3 text-nowrap">
198+
<input t-attf-class="trigger_selection {{'trigger_selection_hide' if trigger.hide else 'trigger_selection_show'}}" type="checkbox" t-attf-name="trigger_{{trigger.id}}" t-attf-id="trigger_{{trigger.id}}" t-att-checked="not trigger.hide if trigger_display is None else trigger.id in trigger_display"/>
199+
<label t-attf-for="trigger_{{trigger.id}}" t-out="trigger.name"/>
200+
</div>
201+
</t>
194202
</div>
195203
</t>
196-
</div>
197-
</t>
198-
</t>
199-
</div>
200-
<button
201-
onclick="Array.from(document.getElementsByClassName('trigger_selection_show')).forEach((element) => element.checked = true); Array.from(document.getElementsByClassName('trigger_selection_hide')).forEach((element) => element.checked = false); event.preventDefault();"
202-
class="btn btn-secondary">Reset to default</button>
203-
<button
204-
onclick="Array.from(document.getElementsByClassName('trigger_selection')).forEach((element) => element.checked = true); event.preventDefault();"
205-
class="btn btn-secondary">All</button>
206-
<button
207-
onclick="Array.from(document.getElementsByClassName('trigger_selection')).forEach((element) => element.checked = false); event.preventDefault();"
208-
class="btn btn-secondary">None</button>
209-
<button type="submit" class="btn btn-primary">Save</button>
210-
</form>
211-
</div>
204+
</t>
205+
</div>
206+
</div>
207+
<footer class="modal-footer">
208+
<button
209+
onclick="Array.from(document.getElementsByClassName('trigger_selection_show')).forEach((element) => element.checked = true); Array.from(document.getElementsByClassName('trigger_selection_hide')).forEach((element) => element.checked = false); event.preventDefault();"
210+
class="btn btn-secondary">Reset to default</button>
211+
<button
212+
onclick="Array.from(document.getElementsByClassName('trigger_selection')).forEach((element) => element.checked = true); event.preventDefault();"
213+
class="btn btn-secondary">All</button>
214+
<button
215+
onclick="Array.from(document.getElementsByClassName('trigger_selection')).forEach((element) => element.checked = false); event.preventDefault();"
216+
class="btn btn-secondary">None</button>
217+
<button type="submit" class="btn btn-primary">Save</button>
218+
</footer>
219+
</form>
220+
</div>
221+
</dialog>
212222
<t t-out="0"/>
213223
</body>
214224
</xpath>

0 commit comments

Comments
 (0)