goosebit 0.1.2__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. goosebit/__init__.py +50 -19
  2. goosebit/__main__.py +7 -0
  3. goosebit/api/responses.py +5 -0
  4. goosebit/api/routes.py +5 -15
  5. goosebit/api/telemetry/__init__.py +1 -0
  6. goosebit/{telemetry/__init__.py → api/telemetry/metrics.py} +9 -3
  7. goosebit/api/telemetry/prometheus/__init__.py +2 -0
  8. goosebit/api/telemetry/prometheus/readers.py +3 -0
  9. goosebit/api/telemetry/prometheus/routes.py +18 -0
  10. goosebit/api/telemetry/routes.py +9 -0
  11. goosebit/api/v1/__init__.py +1 -0
  12. goosebit/api/v1/devices/__init__.py +1 -0
  13. goosebit/api/v1/devices/device/__init__.py +1 -0
  14. goosebit/api/v1/devices/device/responses.py +13 -0
  15. goosebit/api/v1/devices/device/routes.py +27 -0
  16. goosebit/api/v1/devices/requests.py +7 -0
  17. goosebit/api/v1/devices/responses.py +16 -0
  18. goosebit/api/v1/devices/routes.py +35 -0
  19. goosebit/api/v1/download/__init__.py +1 -0
  20. goosebit/api/v1/download/routes.py +22 -0
  21. goosebit/api/v1/rollouts/__init__.py +1 -0
  22. goosebit/api/v1/rollouts/requests.py +16 -0
  23. goosebit/api/v1/rollouts/responses.py +19 -0
  24. goosebit/api/v1/rollouts/routes.py +50 -0
  25. goosebit/api/v1/routes.py +9 -0
  26. goosebit/api/v1/software/__init__.py +1 -0
  27. goosebit/api/v1/software/requests.py +5 -0
  28. goosebit/api/v1/software/responses.py +16 -0
  29. goosebit/api/v1/software/routes.py +77 -0
  30. goosebit/auth/__init__.py +101 -101
  31. goosebit/db/__init__.py +11 -0
  32. goosebit/db/config.py +10 -0
  33. goosebit/db/migrations/models/0_20240830054046_init.py +136 -0
  34. goosebit/{models.py → db/models.py} +17 -10
  35. goosebit/realtime/logs.py +4 -3
  36. goosebit/realtime/routes.py +2 -2
  37. goosebit/schema/__init__.py +0 -0
  38. goosebit/schema/devices.py +73 -0
  39. goosebit/schema/rollouts.py +31 -0
  40. goosebit/schema/software.py +37 -0
  41. goosebit/settings/__init__.py +17 -0
  42. goosebit/settings/const.py +21 -0
  43. goosebit/settings/schema.py +86 -0
  44. goosebit/ui/bff/__init__.py +1 -0
  45. goosebit/ui/bff/devices/__init__.py +1 -0
  46. goosebit/ui/bff/devices/requests.py +12 -0
  47. goosebit/ui/bff/devices/responses.py +39 -0
  48. goosebit/ui/bff/devices/routes.py +72 -0
  49. goosebit/ui/bff/download/__init__.py +1 -0
  50. goosebit/ui/bff/download/routes.py +22 -0
  51. goosebit/ui/bff/rollouts/__init__.py +1 -0
  52. goosebit/ui/bff/rollouts/responses.py +37 -0
  53. goosebit/ui/bff/rollouts/routes.py +52 -0
  54. goosebit/ui/bff/routes.py +11 -0
  55. goosebit/ui/bff/software/__init__.py +1 -0
  56. goosebit/ui/bff/software/responses.py +37 -0
  57. goosebit/ui/bff/software/routes.py +83 -0
  58. goosebit/ui/nav.py +16 -0
  59. goosebit/ui/routes.py +29 -66
  60. goosebit/ui/static/favicon.ico +0 -0
  61. goosebit/ui/static/favicon.svg +1 -1
  62. goosebit/ui/static/js/devices.js +47 -71
  63. goosebit/ui/static/js/index.js +4 -9
  64. goosebit/ui/static/js/login.js +23 -0
  65. goosebit/ui/static/js/logs.js +1 -1
  66. goosebit/ui/static/js/rollouts.js +33 -19
  67. goosebit/ui/static/js/{firmware.js → software.js} +87 -86
  68. goosebit/ui/static/js/util.js +60 -6
  69. goosebit/ui/static/svg/goosebit-logo.svg +1 -1
  70. goosebit/ui/templates/__init__.py +9 -1
  71. goosebit/ui/templates/devices.html.jinja +75 -0
  72. goosebit/ui/templates/index.html.jinja +25 -0
  73. goosebit/ui/templates/login.html.jinja +57 -0
  74. goosebit/ui/templates/logs.html.jinja +31 -0
  75. goosebit/ui/templates/nav.html.jinja +84 -0
  76. goosebit/ui/templates/rollouts.html.jinja +93 -0
  77. goosebit/ui/templates/software.html.jinja +139 -0
  78. goosebit/updater/controller/v1/routes.py +101 -96
  79. goosebit/updater/controller/v1/schema.py +56 -0
  80. goosebit/updater/manager.py +65 -65
  81. goosebit/updater/routes.py +3 -11
  82. goosebit/updates/__init__.py +91 -32
  83. goosebit/updates/swdesc.py +2 -7
  84. goosebit-0.2.1.dist-info/METADATA +173 -0
  85. goosebit-0.2.1.dist-info/RECORD +95 -0
  86. goosebit/api/devices.py +0 -136
  87. goosebit/api/download.py +0 -34
  88. goosebit/api/firmware.py +0 -57
  89. goosebit/api/helper.py +0 -30
  90. goosebit/api/rollouts.py +0 -87
  91. goosebit/db.py +0 -37
  92. goosebit/permissions.py +0 -75
  93. goosebit/settings.py +0 -64
  94. goosebit/telemetry/prometheus.py +0 -10
  95. goosebit/ui/templates/devices.html +0 -115
  96. goosebit/ui/templates/firmware.html +0 -163
  97. goosebit/ui/templates/index.html +0 -23
  98. goosebit/ui/templates/login.html +0 -65
  99. goosebit/ui/templates/logs.html +0 -36
  100. goosebit/ui/templates/nav.html +0 -117
  101. goosebit/ui/templates/rollouts.html +0 -76
  102. goosebit-0.1.2.dist-info/METADATA +0 -123
  103. goosebit-0.1.2.dist-info/RECORD +0 -51
  104. {goosebit-0.1.2.dist-info → goosebit-0.2.1.dist-info}/LICENSE +0 -0
  105. {goosebit-0.1.2.dist-info → goosebit-0.2.1.dist-info}/WHEEL +0 -0
@@ -1,115 +0,0 @@
1
- {% extends "nav.html" %} {% block content %}
2
- <div class="container-fluid">
3
- <div class="row p-2 d-flex justify-content-center">
4
- <div class="col">
5
- <table id="device-table" class="table table-hover">
6
- <thead>
7
- <tr>
8
- <th>Up</th>
9
- <th>UUID</th>
10
- <th>Name</th>
11
- <th>Model</th>
12
- <th>Revision</th>
13
- <th>Feed</th>
14
- <th>Flavor</th>
15
- <th>Installed Firmware</th>
16
- <th>Target Firmware</th>
17
- <th>Update Mode</th>
18
- <th>State</th>
19
- <th>Force Update</th>
20
- <th>Progress</th>
21
- <th>Last IP</th>
22
- <th>Last Seen</th>
23
- </tr>
24
- </thead>
25
- <tbody id="devices-list"></tbody>
26
- </table>
27
- </div>
28
- </div>
29
- </div>
30
- <div class="modal" id="device-config-modal">
31
- <div class="modal-dialog">
32
- <div class="modal-content">
33
- <div class="modal-header">
34
- <h5 class="modal-title">Configure Devices</h5>
35
- <button
36
- type="button"
37
- class="btn-close"
38
- data-bs-dismiss="modal"
39
- aria-label="Close"
40
- ></button>
41
- </div>
42
- <div class="modal-body">
43
- <input
44
- id="rollout-selected-feed"
45
- class="form-control mb-3"
46
- placeholder="Feed"
47
- />
48
- <input
49
- id="rollout-selected-flavor"
50
- class="form-control mb-3"
51
- placeholder="Flavor"
52
- />
53
- <select class="form-select" id="selected-fw"></select>
54
- </div>
55
- <div class="modal-footer">
56
- <button
57
- type="button"
58
- class="btn btn-secondary"
59
- data-bs-dismiss="modal"
60
- >
61
- Close
62
- </button>
63
- <button
64
- type="button"
65
- class="btn btn-outline-light"
66
- data-bs-dismiss="modal"
67
- onclick="updateDeviceConfig()"
68
- >
69
- Save changes
70
- </button>
71
- </div>
72
- </div>
73
- </div>
74
- </div>
75
- <div class="modal" id="device-rename-modal">
76
- <div class="modal-dialog">
77
- <div class="modal-content">
78
- <div class="modal-header">
79
- <h5 class="modal-title">Rename Device</h5>
80
- <button
81
- type="button"
82
- class="btn-close"
83
- data-bs-dismiss="modal"
84
- aria-label="Close"
85
- ></button>
86
- </div>
87
- <div class="modal-body">
88
- <input
89
- id="device-selected-name"
90
- class="form-control"
91
- placeholder="Name"
92
- />
93
- </div>
94
- <div class="modal-footer">
95
- <button
96
- type="button"
97
- class="btn btn-secondary"
98
- data-bs-dismiss="modal"
99
- >
100
- Close
101
- </button>
102
- <button
103
- type="button"
104
- class="btn btn-outline-light"
105
- data-bs-dismiss="modal"
106
- onclick="updateDeviceName()"
107
- >
108
- Save changes
109
- </button>
110
- </div>
111
- </div>
112
- </div>
113
- </div>
114
- <script src="{{ url_for('static', path='js/devices.js') }}"></script>
115
- {% endblock content %}
@@ -1,163 +0,0 @@
1
- {% extends "nav.html" %} {% block content %}
2
- <div class="container-fluid">
3
- <div class="row p-2 pt-4 g-4 d-flex justify-content-center">
4
- {% if "firmware.write" in request.user.permissions %}
5
- <div class="col col-12">
6
- <button
7
- type="button"
8
- class="btn btn-lg btn-outline-light w-100"
9
- data-bs-toggle="modal"
10
- data-bs-target="#upload-modal"
11
- >
12
- Upload
13
- </button>
14
- </div>
15
- {% endif %}
16
- <div class="col">
17
- <table id="firmware-table" class="table table-hover">
18
- <thead>
19
- <tr>
20
- <th>ID</th>
21
- <th>Name</th>
22
- <th>Version</th>
23
- <th>Size</th>
24
- </tr>
25
- </thead>
26
- <tbody id="firmware-list"></tbody>
27
- </table>
28
- </div>
29
- </div>
30
- </div>
31
-
32
- {% if "firmware.write" in request.user.permissions %}
33
- <div class="modal modal-lg fade" id="upload-modal">
34
- <div class="modal-dialog modal-dialog-centered modal-xl">
35
- <div class="modal-content">
36
- <div class="modal-header">
37
- <ul
38
- class="nav nav-underline nav-justified w-100"
39
- role="tablist"
40
- >
41
- <li class="nav-item">
42
- <button
43
- class="nav-link active"
44
- aria-current="page"
45
- id="upload-tab"
46
- data-bs-toggle="tab"
47
- data-bs-target="#upload-tab-content"
48
- type="button"
49
- role="tab"
50
- >
51
- Upload File
52
- </button>
53
- </li>
54
- <li class="nav-item">
55
- <button
56
- class="nav-link"
57
- id="url-tab"
58
- data-bs-toggle="tab"
59
- data-bs-target="#url-tab-content"
60
- type="button"
61
- role="tab"
62
- >
63
- Remote URL
64
- </button>
65
- </li>
66
- </ul>
67
- </div>
68
- <div class="tab-content">
69
- <div class="tab-pane active" id="upload-tab-content">
70
- <div class="modal-body">
71
- <form id="upload-form">
72
- <div class="row g-3 row-cols-1">
73
- <div id="upload-alerts"></div>
74
- <div class="col">
75
- <input
76
- class="form-control"
77
- type="file"
78
- accept=".swu"
79
- id="file-upload"
80
- name="file"
81
- />
82
- </div>
83
- <div class="col">
84
- <input
85
- class="btn btn-outline-light w-100"
86
- id="file-upload-submit"
87
- type="submit"
88
- value="Upload"
89
- />
90
- <div
91
- class="progress border border-light bg-dark d-none"
92
- style="height: 36px"
93
- role="progressbar"
94
- aria-valuenow="0"
95
- aria-valuemin="0"
96
- aria-valuemax="100"
97
- >
98
- <div
99
- class="progress-bar progress-bar-striped bg-success progress-bar-animated"
100
- id="upload-progress"
101
- style="width: 0%"
102
- >
103
- 0%
104
- </div>
105
- </div>
106
- </div>
107
- </div>
108
- </form>
109
- </div>
110
- </div>
111
- <div class="tab-pane" id="url-tab-content">
112
- <div class="modal-body">
113
- <form id="url-form">
114
- <div class="row g-3 row-cols-1">
115
- <div id="url-alerts"></div>
116
- <div class="col">
117
- <div class="input-group">
118
- <span class="input-group-text"
119
- >File URL</span
120
- >
121
- <input
122
- class="form-control"
123
- type="url"
124
- id="file-url"
125
- />
126
- </div>
127
- </div>
128
- <div class="col">
129
- <input
130
- class="btn btn-outline-light w-100"
131
- id="url-submit"
132
- type="submit"
133
- value="Upload"
134
- />
135
- <div
136
- class="progress border border-light bg-dark d-none"
137
- style="height: 36px"
138
- role="progressbar"
139
- aria-valuenow="0"
140
- aria-valuemin="0"
141
- aria-valuemax="100"
142
- >
143
- <div
144
- class="progress-bar progress-bar-striped bg-success progress-bar-animated"
145
- id="url-progress"
146
- style="width: 0%"
147
- >
148
- 0%
149
- </div>
150
- </div>
151
- </div>
152
- </div>
153
- </form>
154
- </div>
155
- </div>
156
- </div>
157
- </div>
158
- </div>
159
- </div>
160
- {% endif %}
161
- <script src="{{ url_for('static', path='js/util.js') }}"></script>
162
- <script src="{{ url_for('static', path='js/firmware.js') }}"></script>
163
- {% endblock content %}
@@ -1,23 +0,0 @@
1
- {% extends "nav.html" %} {% block content %}
2
- <div class="container-fluid">
3
- <div class="row p-2 d-flex justify-content-center">
4
- <div class="col">
5
- <table id="device-table" class="table table-hover">
6
- <thead>
7
- <tr>
8
- <th>Name</th>
9
- <th>Up</th>
10
- <th>UUID</th>
11
- <th>Firmware</th>
12
- <th>Progress</th>
13
- <th>Last IP</th>
14
- <th>Last Seen</th>
15
- </tr>
16
- </thead>
17
- <tbody id="devices-list"></tbody>
18
- </table>
19
- </div>
20
- </div>
21
- </div>
22
- <script src="{{ url_for('static', path='js/index.js') }}"></script>
23
- {% endblock content %}
@@ -1,65 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>Login</title>
7
- <link
8
- href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
9
- rel="stylesheet"
10
- integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
11
- crossorigin="anonymous"
12
- />
13
- <script
14
- src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
15
- integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
16
- crossorigin="anonymous"
17
- ></script>
18
- <link
19
- rel="stylesheet"
20
- href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
21
- />
22
- <link rel="icon" href="{{ url_for('static', path='favicon.svg') }}" />
23
- </head>
24
- <body data-bs-theme="dark">
25
- <div class="container py-5 h-100">
26
- <div
27
- class="row d-flex justify-content-center align-items-center h-100"
28
- >
29
- <div class="col-12 col-md-8 col-lg-6 col-xl-5">
30
- <div class="mb-md-5 mt-md-4 pb-5">
31
- <h2 class="fw-bold mb-3 text-uppercase">Login</h2>
32
- <form method="post">
33
- <div class="form-outline form-white mb-4">
34
- <input
35
- type="email"
36
- id="username"
37
- name="username"
38
- placeholder="Email"
39
- class="form-control form-control-lg"
40
- />
41
- </div>
42
-
43
- <div class="form-outline form-white mb-4">
44
- <input
45
- type="password"
46
- id="password"
47
- name="password"
48
- placeholder="Password"
49
- class="form-control form-control-lg"
50
- />
51
- </div>
52
-
53
- <button
54
- class="btn btn-outline-light btn-lg px-5 w-100"
55
- type="submit"
56
- >
57
- Login
58
- </button>
59
- </form>
60
- </div>
61
- </div>
62
- </div>
63
- </div>
64
- </body>
65
- </html>
@@ -1,36 +0,0 @@
1
- {% extends "nav.html" %} {% block content %}
2
- <div class="container-fluid">
3
- <div class="row p-2 d-flex justify-content-center">
4
- <div class="col col-12 col-lg-9">
5
- <div class="card border rounded">
6
- <div class="card-header">
7
- <h3>Logs - {{ device }}</h3>
8
- </div>
9
- <div class="card-header">
10
- <div
11
- class="progress m-2"
12
- role="progressbar"
13
- aria-label="Basic example"
14
- aria-valuenow="0"
15
- aria-valuemin="0"
16
- aria-valuemax="100"
17
- >
18
- <div
19
- class="progress-bar progress-bar-striped progress-bar-animated"
20
- id="install-progress"
21
- style="width: 0%"
22
- ></div>
23
- </div>
24
- </div>
25
- <div class="card-body">
26
- <pre id="device-log"></pre>
27
- </div>
28
- </div>
29
- </div>
30
- </div>
31
- </div>
32
- <script>
33
- device = "{{ device }}";
34
- </script>
35
- <script src="{{ url_for('static', path='js/logs.js') }}"></script>
36
- {% endblock content %}
@@ -1,117 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <script>
5
- const PERMISSIONS = {{request.user.get_json_permissions() | safe}};
6
- </script>
7
- <meta charset="utf-8" />
8
- <meta name="viewport" content="width=device-width, initial-scale=1" />
9
- <title>{{title}}</title>
10
- <!--bootstrap-->
11
- <link
12
- href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
13
- rel="stylesheet"
14
- integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
15
- crossorigin="anonymous"
16
- />
17
- <script
18
- src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
19
- integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
20
- crossorigin="anonymous"
21
- ></script>
22
- <link
23
- rel="stylesheet"
24
- href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
25
- />
26
- <!--data tables-->
27
- <link
28
- href="https://cdn.datatables.net/v/bs5/jq-3.7.0/dt-2.0.1/b-3.0.0/r-3.0.0/sl-2.0.0/datatables.min.css"
29
- rel="stylesheet"
30
- />
31
- <script src="https://cdn.datatables.net/v/bs5/jq-3.7.0/dt-2.0.1/b-3.0.0/r-3.0.0/sl-2.0.0/datatables.min.js"></script>
32
- <!--favicon-->
33
- <link rel="icon" href="{{ url_for('static', path='favicon.svg') }}" />
34
- <!--data tables alignment fix-->
35
- <style>
36
- th.dt-type-numeric {
37
- text-align: left !important;
38
- }
39
- td.dt-type-numeric {
40
- text-align: left !important;
41
- }
42
- .active {
43
- color: var(--bs-nav-pills-link-active-color);
44
- background-color: transparent;
45
- }
46
- </style>
47
- <script>
48
- const TABLE_UPDATE_TIME = 3000;
49
- </script>
50
- <script src="{{ url_for('static', path='js/util.js') }}"></script>
51
- </head>
52
- <body data-bs-theme="dark">
53
- <nav class="navbar navbar-expand-lg bg-body-tertiary">
54
- <div class="container-fluid">
55
- <a class="navbar-brand" href="/ui/home">
56
- <img
57
- src="{{ request.url_for('static', path='svg/goosebit-logo.svg') }}"
58
- class="me-2"
59
- style="height: 30px; width: 30px"
60
- />
61
- gooseBit
62
- </a>
63
- <button
64
- class="navbar-toggler"
65
- type="button"
66
- data-bs-toggle="collapse"
67
- data-bs-target="#navbar"
68
- aria-controls="navbar"
69
- aria-expanded="false"
70
- aria-label="Toggle navigation"
71
- >
72
- <span class="navbar-toggler-icon"></span>
73
- </button>
74
- <div class="collapse navbar-collapse" id="navbar">
75
- <div class="navbar-nav">
76
- {% if "home.read" in request.user.permissions %}
77
- <a
78
- class="nav-link{% if request.url.path.endswith('home') %} active{% endif %}"
79
- href="/ui/home"
80
- >Home</a
81
- >
82
- {% endif %} {% if "firmware.read" in
83
- request.user.permissions %}
84
- <a
85
- class="nav-link{% if request.url.path.endswith('firmware') %} active{% endif %}"
86
- href="/ui/firmware"
87
- >Firmware</a
88
- >
89
- {% endif %} {% if "device.read" in
90
- request.user.permissions %}
91
- <a
92
- class="nav-link{% if request.url.path.endswith('devices') %} active{% endif %}"
93
- href="/ui/devices"
94
- >Devices</a
95
- >
96
- {% endif %} {% if "rollout.read" in
97
- request.user.permissions %}
98
- <a
99
- class="nav-link{% if request.url.path.endswith('rollouts') %} active{% endif %}"
100
- href="/ui/rollouts"
101
- >Rollouts</a
102
- >
103
- {% endif %}
104
- </div>
105
- <div
106
- class="navbar-nav d-flex flex-fill justify-content-end"
107
- >
108
- <a class="nav-link" href="/logout"
109
- >Logout<i class="bi bi-box-arrow-right ps-2"></i
110
- ></a>
111
- </div>
112
- </div>
113
- </div>
114
- </nav>
115
- {% block content %} {% endblock content %}
116
- </body>
117
- </html>
@@ -1,76 +0,0 @@
1
- {% extends "nav.html" %} {% block content %}
2
- <div class="container-fluid">
3
- <div class="row p-2 d-flex justify-content-center">
4
- <div class="col">
5
- <table id="rollout-table" class="table table-hover">
6
- <thead>
7
- <tr>
8
- <th>Id</th>
9
- <th>Created</th>
10
- <th>Name</th>
11
- <th>Feed</th>
12
- <th>Flavour</th>
13
- <th>Firmware File</th>
14
- <th>Firmware Version</th>
15
- <th>Paused</th>
16
- <th>Success Count</th>
17
- <th>Failure Count</th>
18
- </tr>
19
- </thead>
20
- <tbody id="rollouts-list"></tbody>
21
- </table>
22
- </div>
23
- </div>
24
- </div>
25
- <div class="modal" id="rollout-create-modal">
26
- <div class="modal-dialog">
27
- <div class="modal-content">
28
- <div class="modal-header">
29
- <h5 class="modal-title">Create Rollout</h5>
30
- <button
31
- type="button"
32
- class="btn-close"
33
- data-bs-dismiss="modal"
34
- aria-label="Close"
35
- ></button>
36
- </div>
37
- <div class="modal-body">
38
- <input
39
- id="rollout-selected-name"
40
- class="form-control mb-3"
41
- placeholder="Name"
42
- />
43
- <input
44
- id="rollout-selected-feed"
45
- class="form-control mb-3"
46
- placeholder="Feed"
47
- />
48
- <input
49
- id="rollout-selected-flavor"
50
- class="form-control mb-3"
51
- placeholder="Flavor"
52
- />
53
- <select class="form-select" id="selected-fw"></select>
54
- </div>
55
- <div class="modal-footer">
56
- <button
57
- type="button"
58
- class="btn btn-secondary"
59
- data-bs-dismiss="modal"
60
- >
61
- Close
62
- </button>
63
- <button
64
- type="button"
65
- class="btn btn-outline-light"
66
- data-bs-dismiss="modal"
67
- onclick="createRollout()"
68
- >
69
- Save changes
70
- </button>
71
- </div>
72
- </div>
73
- </div>
74
- </div>
75
- <script src="{{ url_for('static', path='js/rollouts.js') }}"></script>
76
- {% endblock content %}