Free and open source ticket system written in python
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add status page, translations and design changes

+1570 -206
+1
.prettierignore
··· 1 + **/*.html
+1 -1
paw/__init__.py
··· 1 1 from django import get_version 2 2 3 - VERSION = (0, 1, 0, "beta", 14) 3 + VERSION = (0, 2, 0, "beta", 1) 4 4 5 5 __version__ = get_version(VERSION)
+302
paw/locale/de/LC_MESSAGES/django.po
··· 1 + # SOME DESCRIPTIVE TITLE. 2 + # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 + # This file is distributed under the same license as the PACKAGE package. 4 + # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. 5 + # 6 + #, fuzzy 7 + msgid "" 8 + msgstr "" 9 + "Project-Id-Version: PACKAGE VERSION\n" 10 + "Report-Msgid-Bugs-To: \n" 11 + "POT-Creation-Date: 2024-03-12 23:27+0000\n" 12 + "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 + "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 14 + "Language-Team: LANGUAGE <LL@li.org>\n" 15 + "Language: \n" 16 + "MIME-Version: 1.0\n" 17 + "Content-Type: text/plain; charset=UTF-8\n" 18 + "Content-Transfer-Encoding: 8bit\n" 19 + "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 + #: core/models.py:27 21 + msgid "Google SSO User" 22 + msgstr "" 23 + 24 + #: paw/settings.py:120 25 + msgid "English" 26 + msgstr "" 27 + 28 + #: paw/settings.py:121 29 + msgid "French" 30 + msgstr "" 31 + 32 + #: paw/settings.py:122 33 + msgid "German" 34 + msgstr "" 35 + 36 + #: paw/templates/core/account_finish.html:10 37 + msgid "Register a new account" 38 + msgstr "" 39 + 40 + #: paw/templates/core/account_finish.html:13 41 + msgid "Authenticate" 42 + msgstr "" 43 + 44 + #: paw/templates/core/account_finish.html:14 45 + msgid "Set up account" 46 + msgstr "Account einrichten" 47 + 48 + #: paw/templates/core/account_finish.html:15 49 + msgid "Done" 50 + msgstr "Fertig" 51 + 52 + #: paw/templates/core/account_finish.html:29 paw/templates/core/login.html:28 53 + msgid "Username" 54 + msgstr "Benutzername" 55 + 56 + #: paw/templates/core/account_finish.html:34 57 + #: paw/templates/core/settings.html:48 58 + msgid "Save" 59 + msgstr "Speichern" 60 + 61 + #: paw/templates/core/login.html:11 paw/templates/core/login.html:43 62 + msgid "Log In" 63 + msgstr "Anmelden" 64 + 65 + #: paw/templates/core/login.html:13 66 + msgid "Register Account" 67 + msgstr "Account erstellen" 68 + 69 + #: paw/templates/core/login.html:34 70 + msgid "Password" 71 + msgstr "Passwort" 72 + 73 + #: paw/templates/core/login.html:39 74 + msgid "Password Reset" 75 + msgstr "Passwort zurücksetzen" 76 + 77 + #: paw/templates/core/login.html:50 78 + msgid "Log in with Google" 79 + msgstr "Mit Google anmelden" 80 + 81 + #: paw/templates/core/settings.html:7 paw/templates/dashboard_base.html:51 82 + msgid "Settings" 83 + msgstr "Einstellungen" 84 + 85 + #: paw/templates/core/settings.html:12 86 + msgid "Mail Address" 87 + msgstr "Mail Adresse" 88 + 89 + #: paw/templates/core/settings.html:23 90 + msgid "Language" 91 + msgstr "Sprache" 92 + 93 + #: paw/templates/core/settings.html:30 94 + msgid "Use Darkmode" 95 + msgstr "Darkmode benutzen" 96 + 97 + #: paw/templates/core/settings.html:37 98 + msgid "Profile Picture" 99 + msgstr "Profilbild" 100 + 101 + #: paw/templates/core/settings.html:42 102 + #: paw/templates/ticketing/ticket_detail.html:127 103 + msgid "Contact" 104 + msgstr "Kontakt" 105 + 106 + #: paw/templates/dashboard_base.html:12 107 + #: paw/templates/ticketing/create_ticket.html:50 108 + msgid "Create Ticket" 109 + msgstr "Ticket erstellen" 110 + 111 + #: paw/templates/dashboard_base.html:16 112 + msgid "Tickets" 113 + msgstr "Tickets" 114 + 115 + #: paw/templates/dashboard_base.html:20 116 + msgid "History" 117 + msgstr "Historie" 118 + 119 + #: paw/templates/dashboard_base.html:55 120 + msgid "Logout" 121 + msgstr "Abmelden" 122 + 123 + #: paw/templates/partials/assigned_to.html:17 124 + #: paw/templates/ticketing/ticket_detail.html:176 125 + msgid "Unassigned" 126 + msgstr "Nicht zugewiesen" 127 + 128 + #: paw/templates/partials/ticket_status_badge.html:4 ticketing/models.py:37 129 + msgid "Open" 130 + msgstr "Offen" 131 + 132 + #: paw/templates/partials/ticket_status_badge.html:6 ticketing/models.py:38 133 + msgid "In Progress" 134 + msgstr "In Bearbeitung" 135 + 136 + #: paw/templates/partials/ticket_status_badge.html:8 ticketing/models.py:39 137 + msgid "Closed" 138 + msgstr "Geschlossen" 139 + 140 + #: paw/templates/ticketing/create_ticket.html:5 141 + msgid "Create a new ticket" 142 + msgstr "Neues Ticket erstellen" 143 + 144 + #: paw/templates/ticketing/create_ticket.html:12 145 + #: paw/templates/ticketing/ticket_detail.html:140 146 + #: paw/templates/ticketing/tickets.html:19 147 + msgid "Category" 148 + msgstr "Kategorie" 149 + 150 + #: paw/templates/ticketing/create_ticket.html:19 151 + #: paw/templates/ticketing/tickets.html:17 ticketing/forms.py:73 152 + msgid "Title" 153 + msgstr "Titel" 154 + 155 + #: paw/templates/ticketing/create_ticket.html:26 ticketing/forms.py:74 156 + msgid "Description" 157 + msgstr "Beschreibung" 158 + 159 + #: paw/templates/ticketing/create_ticket.html:34 160 + #: paw/templates/ticketing/ticket_detail.html:9 161 + msgid "Attachments" 162 + msgstr "Anhänge" 163 + 164 + #: paw/templates/ticketing/create_ticket.html:43 165 + msgid "Create as follow-up to a closed ticket" 166 + msgstr "Als Follow-Up zu einem geschlossenen Ticket erstellen" 167 + 168 + #: paw/templates/ticketing/ticket_detail.html:14 169 + msgid "Attachment" 170 + msgstr "Anhang" 171 + 172 + #: paw/templates/ticketing/ticket_detail.html:19 173 + msgid "Activity" 174 + msgstr "Aktivitäten" 175 + 176 + #: paw/templates/ticketing/ticket_detail.html:55 177 + msgid "Apply Template" 178 + msgstr "Vorlage anwenden" 179 + 180 + #: paw/templates/ticketing/ticket_detail.html:73 181 + msgid "Add Comment" 182 + msgstr "Kommentar hinzufügen" 183 + 184 + #: paw/templates/ticketing/ticket_detail.html:75 185 + msgid "Close Ticket" 186 + msgstr "Ticket schliessen" 187 + 188 + #: paw/templates/ticketing/ticket_detail.html:84 189 + msgid "Make this an internal comment" 190 + msgstr "Mache dies einen internen Kommentar" 191 + 192 + #: paw/templates/ticketing/ticket_detail.html:91 193 + msgid "Ticket has been closed" 194 + msgstr "Das Ticket wurde geschlossen" 195 + 196 + #: paw/templates/ticketing/ticket_detail.html:96 197 + msgid "Re-Open Ticket" 198 + msgstr "Ticket wieder öffnen" 199 + 200 + #: paw/templates/ticketing/ticket_detail.html:107 201 + msgid "Created by" 202 + msgstr "Erstellt von" 203 + 204 + #: paw/templates/ticketing/ticket_detail.html:120 205 + msgid "Created on" 206 + msgstr "Erstellt am" 207 + 208 + #: paw/templates/ticketing/ticket_detail.html:124 209 + msgid "Last updated" 210 + msgstr "Zuletzt aktualisiert" 211 + 212 + #: paw/templates/ticketing/ticket_detail.html:146 213 + #: paw/templates/ticketing/tickets.html:42 ticketing/forms.py:81 214 + #: ticketing/forms.py:104 215 + msgid "General" 216 + msgstr "Allgemein" 217 + 218 + #: paw/templates/ticketing/ticket_detail.html:152 219 + msgid "Assign to new category" 220 + msgstr "Kategorie zuweisen" 221 + 222 + #: paw/templates/ticketing/ticket_detail.html:155 223 + #: paw/templates/ticketing/ticket_detail.html:185 224 + msgid "Assign" 225 + msgstr "Zuweisen" 226 + 227 + #: paw/templates/ticketing/ticket_detail.html:160 228 + msgid "Assignees" 229 + msgstr "Bearbeiter" 230 + 231 + #: paw/templates/ticketing/ticket_detail.html:167 232 + msgid "Assign to me" 233 + msgstr "Weise mir zu" 234 + 235 + #: paw/templates/ticketing/ticket_detail.html:182 236 + msgid "Assign to new team" 237 + msgstr "Team zuweisen" 238 + 239 + #: paw/templates/ticketing/tickets.html:5 240 + msgid "Open Tickets" 241 + msgstr "Offene Tickets" 242 + 243 + #: paw/templates/ticketing/tickets.html:7 244 + msgid "for" 245 + msgstr "für" 246 + 247 + #: paw/templates/ticketing/tickets.html:18 248 + msgid "Assigned to" 249 + msgstr "Zugewiesen an" 250 + 251 + #: paw/templates/ticketing/tickets.html:20 252 + msgid "Status" 253 + msgstr "" 254 + 255 + #: paw/templates/ticketing/tickets.html:27 256 + msgid "No tickets found" 257 + msgstr "Keine Tickets gefunden" 258 + 259 + #: paw/templates/ticketing/tickets.html:49 260 + msgid "View" 261 + msgstr "Anzeigen" 262 + 263 + #: ticketing/forms.py:39 264 + msgid "File size must be under 5MB." 265 + msgstr "Dateigrösse muss unter 5MB sein." 266 + 267 + #: ticketing/forms.py:52 268 + msgid "File type not supported. Supported types are: .jpg, .png, .pdf" 269 + msgstr "Datei Typ nicht unterstützt. Unterstützte Typen sind: .jpg, .png, .pdf" 270 + 271 + #: ticketing/forms.py:73 272 + msgid "Please enter a title" 273 + msgstr "Gib einen Titel ein" 274 + 275 + #: ticketing/forms.py:74 276 + msgid "Please describe your issue" 277 + msgstr "Beschreibe dein Anliegen" 278 + 279 + #: ticketing/forms.py:82 280 + msgid "No Follow-up" 281 + msgstr "Kein Follow-Up" 282 + 283 + #: ticketing/forms.py:99 284 + msgid "No Team" 285 + msgstr "Kein Team" 286 + 287 + #: ticketing/models.py:28 288 + msgid "" 289 + "If a team is selected, new tickets will automatically assigned to this team." 290 + msgstr "" 291 + 292 + #: ticketing/models.py:42 293 + msgid "Low" 294 + msgstr "Niedrig" 295 + 296 + #: ticketing/models.py:43 297 + msgid "Medium" 298 + msgstr "Mittel" 299 + 300 + #: ticketing/models.py:44 301 + msgid "High" 302 + msgstr "Hoch"
+278 -8
paw/locale/en/LC_MESSAGES/django.po
··· 8 8 msgstr "" 9 9 "Project-Id-Version: PACKAGE VERSION\n" 10 10 "Report-Msgid-Bugs-To: \n" 11 - "POT-Creation-Date: 2024-03-07 15:10+0100\n" 11 + "POT-Creation-Date: 2024-03-12 23:27+0000\n" 12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 14 14 "Language-Team: LANGUAGE <LL@li.org>\n" ··· 18 18 "Content-Transfer-Encoding: 8bit\n" 19 19 "Plural-Forms: nplurals=2; plural=(n != 1);\n" 20 20 21 - #: paw/settings.py:114 21 + #: core/models.py:27 22 + msgid "Google SSO User" 23 + msgstr "" 24 + 25 + #: paw/settings.py:120 22 26 msgid "English" 23 27 msgstr "English" 24 28 25 - #: paw/settings.py:115 29 + #: paw/settings.py:121 26 30 msgid "French" 27 - msgstr "French" 31 + msgstr "Français" 28 32 29 - #: paw/settings.py:116 33 + #: paw/settings.py:122 30 34 msgid "German" 31 - msgstr "German" 35 + msgstr "Deutsch" 32 36 33 - #: paw/templates/core/settings.html:6 34 - msgid "SettingsHeading" 37 + #: paw/templates/core/account_finish.html:10 38 + msgid "Register a new account" 39 + msgstr "" 40 + 41 + #: paw/templates/core/account_finish.html:13 42 + msgid "Authenticate" 43 + msgstr "" 44 + 45 + #: paw/templates/core/account_finish.html:14 46 + msgid "Set up account" 47 + msgstr "" 48 + 49 + #: paw/templates/core/account_finish.html:15 50 + msgid "Done" 51 + msgstr "" 52 + 53 + #: paw/templates/core/account_finish.html:29 paw/templates/core/login.html:28 54 + msgid "Username" 55 + msgstr "" 56 + 57 + #: paw/templates/core/account_finish.html:34 58 + #: paw/templates/core/settings.html:48 59 + msgid "Save" 60 + msgstr "" 61 + 62 + #: paw/templates/core/login.html:11 paw/templates/core/login.html:43 63 + msgid "Log In" 64 + msgstr "" 65 + 66 + #: paw/templates/core/login.html:13 67 + msgid "Register Account" 68 + msgstr "" 69 + 70 + #: paw/templates/core/login.html:34 71 + msgid "Password" 72 + msgstr "" 73 + 74 + #: paw/templates/core/login.html:39 75 + msgid "Password Reset" 76 + msgstr "" 77 + 78 + #: paw/templates/core/login.html:50 79 + msgid "Log in with Google" 80 + msgstr "" 81 + 82 + #: paw/templates/core/settings.html:7 paw/templates/dashboard_base.html:51 83 + #, fuzzy 84 + #| msgid "SettingsHeading" 85 + msgid "Settings" 35 86 msgstr "Settings" 87 + 88 + #: paw/templates/core/settings.html:12 89 + msgid "Mail Address" 90 + msgstr "" 91 + 92 + #: paw/templates/core/settings.html:23 93 + msgid "Language" 94 + msgstr "" 95 + 96 + #: paw/templates/core/settings.html:30 97 + msgid "Use Darkmode" 98 + msgstr "" 99 + 100 + #: paw/templates/core/settings.html:37 101 + msgid "Profile Picture" 102 + msgstr "" 103 + 104 + #: paw/templates/core/settings.html:42 105 + #: paw/templates/ticketing/ticket_detail.html:127 106 + msgid "Contact" 107 + msgstr "" 108 + 109 + #: paw/templates/dashboard_base.html:12 110 + #: paw/templates/ticketing/create_ticket.html:50 111 + msgid "Create Ticket" 112 + msgstr "" 113 + 114 + #: paw/templates/dashboard_base.html:16 115 + msgid "Tickets" 116 + msgstr "" 117 + 118 + #: paw/templates/dashboard_base.html:20 119 + msgid "History" 120 + msgstr "" 121 + 122 + #: paw/templates/dashboard_base.html:55 123 + msgid "Logout" 124 + msgstr "" 125 + 126 + #: paw/templates/partials/assigned_to.html:17 127 + #: paw/templates/ticketing/ticket_detail.html:176 128 + msgid "Unassigned" 129 + msgstr "" 130 + 131 + #: paw/templates/partials/ticket_status_badge.html:4 ticketing/models.py:37 132 + msgid "Open" 133 + msgstr "" 134 + 135 + #: paw/templates/partials/ticket_status_badge.html:6 ticketing/models.py:38 136 + msgid "In Progress" 137 + msgstr "" 138 + 139 + #: paw/templates/partials/ticket_status_badge.html:8 ticketing/models.py:39 140 + msgid "Closed" 141 + msgstr "" 142 + 143 + #: paw/templates/ticketing/create_ticket.html:5 144 + msgid "Create a new ticket" 145 + msgstr "" 146 + 147 + #: paw/templates/ticketing/create_ticket.html:12 148 + #: paw/templates/ticketing/ticket_detail.html:140 149 + #: paw/templates/ticketing/tickets.html:19 150 + msgid "Category" 151 + msgstr "" 152 + 153 + #: paw/templates/ticketing/create_ticket.html:19 154 + #: paw/templates/ticketing/tickets.html:17 ticketing/forms.py:73 155 + msgid "Title" 156 + msgstr "" 157 + 158 + #: paw/templates/ticketing/create_ticket.html:26 ticketing/forms.py:74 159 + msgid "Description" 160 + msgstr "" 161 + 162 + #: paw/templates/ticketing/create_ticket.html:34 163 + #: paw/templates/ticketing/ticket_detail.html:9 164 + msgid "Attachments" 165 + msgstr "" 166 + 167 + #: paw/templates/ticketing/create_ticket.html:43 168 + msgid "Create as follow-up to a closed ticket" 169 + msgstr "" 170 + 171 + #: paw/templates/ticketing/ticket_detail.html:14 172 + msgid "Attachment" 173 + msgstr "" 174 + 175 + #: paw/templates/ticketing/ticket_detail.html:19 176 + msgid "Activity" 177 + msgstr "" 178 + 179 + #: paw/templates/ticketing/ticket_detail.html:55 180 + msgid "Apply Template" 181 + msgstr "" 182 + 183 + #: paw/templates/ticketing/ticket_detail.html:73 184 + msgid "Add Comment" 185 + msgstr "" 186 + 187 + #: paw/templates/ticketing/ticket_detail.html:75 188 + msgid "Close Ticket" 189 + msgstr "" 190 + 191 + #: paw/templates/ticketing/ticket_detail.html:84 192 + msgid "Make this an internal comment" 193 + msgstr "" 194 + 195 + #: paw/templates/ticketing/ticket_detail.html:91 196 + msgid "Ticket has been closed" 197 + msgstr "" 198 + 199 + #: paw/templates/ticketing/ticket_detail.html:96 200 + msgid "Re-Open Ticket" 201 + msgstr "" 202 + 203 + #: paw/templates/ticketing/ticket_detail.html:107 204 + msgid "Created by" 205 + msgstr "" 206 + 207 + #: paw/templates/ticketing/ticket_detail.html:120 208 + msgid "Created on" 209 + msgstr "" 210 + 211 + #: paw/templates/ticketing/ticket_detail.html:124 212 + msgid "Last updated" 213 + msgstr "" 214 + 215 + #: paw/templates/ticketing/ticket_detail.html:146 216 + #: paw/templates/ticketing/tickets.html:42 ticketing/forms.py:81 217 + #: ticketing/forms.py:104 218 + msgid "General" 219 + msgstr "" 220 + 221 + #: paw/templates/ticketing/ticket_detail.html:152 222 + msgid "Assign to new category" 223 + msgstr "" 224 + 225 + #: paw/templates/ticketing/ticket_detail.html:155 226 + #: paw/templates/ticketing/ticket_detail.html:185 227 + msgid "Assign" 228 + msgstr "" 229 + 230 + #: paw/templates/ticketing/ticket_detail.html:160 231 + msgid "Assignees" 232 + msgstr "" 233 + 234 + #: paw/templates/ticketing/ticket_detail.html:167 235 + msgid "Assign to me" 236 + msgstr "" 237 + 238 + #: paw/templates/ticketing/ticket_detail.html:182 239 + msgid "Assign to new team" 240 + msgstr "" 241 + 242 + #: paw/templates/ticketing/tickets.html:5 243 + msgid "Open Tickets" 244 + msgstr "" 245 + 246 + #: paw/templates/ticketing/tickets.html:7 247 + msgid "for" 248 + msgstr "" 249 + 250 + #: paw/templates/ticketing/tickets.html:18 251 + msgid "Assigned to" 252 + msgstr "" 253 + 254 + #: paw/templates/ticketing/tickets.html:20 255 + msgid "Status" 256 + msgstr "" 257 + 258 + #: paw/templates/ticketing/tickets.html:27 259 + msgid "No tickets found" 260 + msgstr "" 261 + 262 + #: paw/templates/ticketing/tickets.html:49 263 + msgid "View" 264 + msgstr "" 265 + 266 + #: ticketing/forms.py:39 267 + msgid "File size must be under 5MB." 268 + msgstr "" 269 + 270 + #: ticketing/forms.py:52 271 + msgid "File type not supported. Supported types are: .jpg, .png, .pdf" 272 + msgstr "" 273 + 274 + #: ticketing/forms.py:73 275 + msgid "Please enter a title" 276 + msgstr "" 277 + 278 + #: ticketing/forms.py:74 279 + msgid "Please describe your issue" 280 + msgstr "" 281 + 282 + #: ticketing/forms.py:82 283 + msgid "No Follow-up" 284 + msgstr "" 285 + 286 + #: ticketing/forms.py:99 287 + msgid "No Team" 288 + msgstr "" 289 + 290 + #: ticketing/models.py:28 291 + msgid "" 292 + "If a team is selected, new tickets will automatically assigned to this team." 293 + msgstr "" 294 + 295 + #: ticketing/models.py:42 296 + msgid "Low" 297 + msgstr "" 298 + 299 + #: ticketing/models.py:43 300 + msgid "Medium" 301 + msgstr "" 302 + 303 + #: ticketing/models.py:44 304 + msgid "High" 305 + msgstr ""
+180 -53
paw/locale/fr/LC_MESSAGES/django.po
··· 8 8 msgstr "" 9 9 "Project-Id-Version: PACKAGE VERSION\n" 10 10 "Report-Msgid-Bugs-To: \n" 11 - "POT-Creation-Date: 2024-03-08 01:27+0000\n" 11 + "POT-Creation-Date: 2024-03-12 23:27+0000\n" 12 12 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 13 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 14 14 "Language-Team: LANGUAGE <LL@li.org>\n" ··· 18 18 "Content-Transfer-Encoding: 8bit\n" 19 19 "Plural-Forms: nplurals=2; plural=(n > 1);\n" 20 20 21 - #: paw/settings.py:117 21 + #: core/models.py:27 22 + msgid "Google SSO User" 23 + msgstr "" 24 + 25 + #: paw/settings.py:120 22 26 msgid "English" 23 - msgstr "Anglais" 27 + msgstr "" 24 28 25 - #: paw/settings.py:118 29 + #: paw/settings.py:121 26 30 msgid "French" 27 - msgstr "Français" 31 + msgstr "" 28 32 29 - #: paw/settings.py:119 33 + #: paw/settings.py:122 30 34 msgid "German" 31 - msgstr "Allemand" 35 + msgstr "" 36 + 37 + #: paw/templates/core/account_finish.html:10 38 + msgid "Register a new account" 39 + msgstr "" 40 + 41 + #: paw/templates/core/account_finish.html:13 42 + msgid "Authenticate" 43 + msgstr "" 44 + 45 + #: paw/templates/core/account_finish.html:14 46 + msgid "Set up account" 47 + msgstr "" 48 + 49 + #: paw/templates/core/account_finish.html:15 50 + msgid "Done" 51 + msgstr "" 52 + 53 + #: paw/templates/core/account_finish.html:29 paw/templates/core/login.html:28 54 + msgid "Username" 55 + msgstr "" 56 + 57 + #: paw/templates/core/account_finish.html:34 58 + #: paw/templates/core/settings.html:48 59 + msgid "Save" 60 + msgstr "Enregistrer" 61 + 62 + #: paw/templates/core/login.html:11 paw/templates/core/login.html:43 63 + msgid "Log In" 64 + msgstr "" 65 + 66 + #: paw/templates/core/login.html:13 67 + msgid "Register Account" 68 + msgstr "" 69 + 70 + #: paw/templates/core/login.html:34 71 + msgid "Password" 72 + msgstr "" 73 + 74 + #: paw/templates/core/login.html:39 75 + msgid "Password Reset" 76 + msgstr "" 77 + 78 + #: paw/templates/core/login.html:50 79 + msgid "Log in with Google" 80 + msgstr "" 32 81 33 - #: paw/templates/core/settings.html:6 paw/templates/dashboard_base.html:53 82 + #: paw/templates/core/settings.html:7 paw/templates/dashboard_base.html:51 34 83 msgid "Settings" 35 84 msgstr "Paramètres" 36 85 37 - #: paw/templates/core/settings.html:11 86 + #: paw/templates/core/settings.html:12 38 87 msgid "Mail Address" 39 88 msgstr "Adresse e-mail" 40 89 41 - #: paw/templates/core/settings.html:18 90 + #: paw/templates/core/settings.html:23 42 91 msgid "Language" 43 92 msgstr "Langue" 44 93 45 - #: paw/templates/core/settings.html:25 94 + #: paw/templates/core/settings.html:30 95 + msgid "Use Darkmode" 96 + msgstr "" 97 + 98 + #: paw/templates/core/settings.html:37 46 99 msgid "Profile Picture" 47 100 msgstr "Image du profil" 48 101 49 - #: paw/templates/core/settings.html:30 50 - #: paw/templates/ticketing/ticket_detail.html:98 102 + #: paw/templates/core/settings.html:42 103 + #: paw/templates/ticketing/ticket_detail.html:127 51 104 msgid "Contact" 52 105 msgstr "" 53 106 54 - #: paw/templates/core/settings.html:36 55 - msgid "Save" 56 - msgstr "Enregistrer" 57 - 58 - #: paw/templates/dashboard_base.html:14 59 - #: paw/templates/ticketing/create_ticket.html:31 107 + #: paw/templates/dashboard_base.html:12 108 + #: paw/templates/ticketing/create_ticket.html:50 60 109 msgid "Create Ticket" 61 110 msgstr "Nouveau ticket" 62 111 63 - #: paw/templates/dashboard_base.html:18 112 + #: paw/templates/dashboard_base.html:16 64 113 msgid "Tickets" 65 114 msgstr "" 66 115 67 - #: paw/templates/dashboard_base.html:22 116 + #: paw/templates/dashboard_base.html:20 68 117 msgid "History" 69 118 msgstr "Historique" 70 119 71 - #: paw/templates/dashboard_base.html:57 120 + #: paw/templates/dashboard_base.html:55 72 121 msgid "Logout" 73 122 msgstr "Se déconnecter" 74 123 75 124 #: paw/templates/partials/assigned_to.html:17 76 - #: paw/templates/ticketing/ticket_detail.html:117 77 - #: paw/templates/ticketing/ticket_detail.html:147 125 + #: paw/templates/ticketing/ticket_detail.html:176 78 126 msgid "Unassigned" 79 127 msgstr "Non attribué" 80 128 81 - #: paw/templates/partials/ticket_status_badge.html:4 ticketing/models.py:30 129 + #: paw/templates/partials/ticket_status_badge.html:4 ticketing/models.py:37 82 130 msgid "Open" 83 131 msgstr "Ouvert" 84 132 85 - #: paw/templates/partials/ticket_status_badge.html:6 ticketing/models.py:31 133 + #: paw/templates/partials/ticket_status_badge.html:6 ticketing/models.py:38 86 134 msgid "In Progress" 87 135 msgstr "En cours" 88 136 89 - #: paw/templates/partials/ticket_status_badge.html:8 ticketing/models.py:32 137 + #: paw/templates/partials/ticket_status_badge.html:8 ticketing/models.py:39 90 138 msgid "Closed" 91 139 msgstr "Fermé" 92 140 ··· 95 143 msgstr "Créer un ticket" 96 144 97 145 #: paw/templates/ticketing/create_ticket.html:12 98 - #: paw/templates/ticketing/tickets.html:17 146 + #: paw/templates/ticketing/ticket_detail.html:140 147 + #: paw/templates/ticketing/tickets.html:19 148 + msgid "Category" 149 + msgstr "Catégorie" 150 + 151 + #: paw/templates/ticketing/create_ticket.html:19 152 + #: paw/templates/ticketing/tickets.html:17 ticketing/forms.py:73 99 153 msgid "Title" 100 154 msgstr "Titre" 101 155 102 - #: paw/templates/ticketing/create_ticket.html:19 156 + #: paw/templates/ticketing/create_ticket.html:26 ticketing/forms.py:74 103 157 msgid "Description" 104 158 msgstr "Description" 105 159 106 - #: paw/templates/ticketing/create_ticket.html:26 107 - #: paw/templates/ticketing/ticket_detail.html:111 108 - #: paw/templates/ticketing/tickets.html:19 109 - msgid "Category" 110 - msgstr "Catégorie" 160 + #: paw/templates/ticketing/create_ticket.html:34 161 + #: paw/templates/ticketing/ticket_detail.html:9 162 + msgid "Attachments" 163 + msgstr "" 164 + 165 + #: paw/templates/ticketing/create_ticket.html:43 166 + msgid "Create as follow-up to a closed ticket" 167 + msgstr "" 168 + 169 + #: paw/templates/ticketing/ticket_detail.html:14 170 + msgid "Attachment" 171 + msgstr "" 172 + 173 + #: paw/templates/ticketing/ticket_detail.html:19 174 + msgid "Activity" 175 + msgstr "" 176 + 177 + #: paw/templates/ticketing/ticket_detail.html:55 178 + msgid "Apply Template" 179 + msgstr "" 111 180 112 - #: paw/templates/ticketing/ticket_detail.html:56 181 + #: paw/templates/ticketing/ticket_detail.html:73 113 182 msgid "Add Comment" 114 183 msgstr "Ajouter un commentaire" 115 184 116 - #: paw/templates/ticketing/ticket_detail.html:58 117 - msgid "Comment and close" 118 - msgstr "Commentaire et fermer" 185 + #: paw/templates/ticketing/ticket_detail.html:75 186 + #, fuzzy 187 + #| msgid "Create Ticket" 188 + msgid "Close Ticket" 189 + msgstr "Nouveau ticket" 119 190 120 - #: paw/templates/ticketing/ticket_detail.html:63 191 + #: paw/templates/ticketing/ticket_detail.html:84 192 + msgid "Make this an internal comment" 193 + msgstr "" 194 + 195 + #: paw/templates/ticketing/ticket_detail.html:91 121 196 msgid "Ticket has been closed" 122 197 msgstr "Le ticket a été fermé" 123 198 124 - #: paw/templates/ticketing/ticket_detail.html:68 199 + #: paw/templates/ticketing/ticket_detail.html:96 125 200 msgid "Re-Open Ticket" 126 201 msgstr "Réouverture du ticket" 127 202 128 - #: paw/templates/ticketing/ticket_detail.html:78 203 + #: paw/templates/ticketing/ticket_detail.html:107 129 204 msgid "Created by" 130 205 msgstr "Créé par" 131 206 132 - #: paw/templates/ticketing/ticket_detail.html:91 207 + #: paw/templates/ticketing/ticket_detail.html:120 133 208 msgid "Created on" 134 209 msgstr "Créé le" 135 210 136 - #: paw/templates/ticketing/ticket_detail.html:95 211 + #: paw/templates/ticketing/ticket_detail.html:124 137 212 msgid "Last updated" 138 213 msgstr "Dernière mise à jour le" 139 214 140 - #: paw/templates/ticketing/ticket_detail.html:123 215 + #: paw/templates/ticketing/ticket_detail.html:146 216 + #: paw/templates/ticketing/tickets.html:42 ticketing/forms.py:81 217 + #: ticketing/forms.py:104 218 + msgid "General" 219 + msgstr "" 220 + 221 + #: paw/templates/ticketing/ticket_detail.html:152 141 222 #, fuzzy 142 223 #| msgid "Assign to me" 143 224 msgid "Assign to new category" 144 225 msgstr "Me l'attribuer" 145 226 146 - #: paw/templates/ticketing/ticket_detail.html:138 227 + #: paw/templates/ticketing/ticket_detail.html:155 228 + #: paw/templates/ticketing/ticket_detail.html:185 229 + #, fuzzy 230 + #| msgid "Assign to me" 231 + msgid "Assign" 232 + msgstr "Me l'attribuer" 233 + 234 + #: paw/templates/ticketing/ticket_detail.html:160 235 + #, fuzzy 236 + #| msgid "Assign to me" 237 + msgid "Assignees" 238 + msgstr "Me l'attribuer" 239 + 240 + #: paw/templates/ticketing/ticket_detail.html:167 147 241 msgid "Assign to me" 242 + msgstr "Me l'attribuer" 243 + 244 + #: paw/templates/ticketing/ticket_detail.html:182 245 + #, fuzzy 246 + #| msgid "Assign to me" 247 + msgid "Assign to new team" 148 248 msgstr "Me l'attribuer" 149 249 150 250 #: paw/templates/ticketing/tickets.html:5 ··· 171 271 msgid "No tickets found" 172 272 msgstr "Aucun ticket trouvé" 173 273 174 - #: paw/templates/ticketing/tickets.html:41 274 + #: paw/templates/ticketing/tickets.html:49 175 275 msgid "View" 176 276 msgstr "Ouvrir" 177 277 178 - #: ticketing/forms.py:31 278 + #: ticketing/forms.py:39 279 + msgid "File size must be under 5MB." 280 + msgstr "" 281 + 282 + #: ticketing/forms.py:52 283 + msgid "File type not supported. Supported types are: .jpg, .png, .pdf" 284 + msgstr "" 285 + 286 + #: ticketing/forms.py:73 287 + msgid "Please enter a title" 288 + msgstr "" 289 + 290 + #: ticketing/forms.py:74 291 + msgid "Please describe your issue" 292 + msgstr "" 293 + 294 + #: ticketing/forms.py:82 295 + msgid "No Follow-up" 296 + msgstr "" 297 + 298 + #: ticketing/forms.py:99 179 299 msgid "No Team" 180 300 msgstr "Aucune Team" 181 301 182 - #: ticketing/forms.py:36 183 - msgid "No Category" 184 - msgstr "Aucune catégorie" 302 + #: ticketing/models.py:28 303 + msgid "" 304 + "If a team is selected, new tickets will automatically assigned to this team." 305 + msgstr "" 185 306 186 - #: ticketing/models.py:35 307 + #: ticketing/models.py:42 187 308 msgid "Low" 188 309 msgstr "" 189 310 190 - #: ticketing/models.py:36 311 + #: ticketing/models.py:43 191 312 msgid "Medium" 192 313 msgstr "" 193 314 194 - #: ticketing/models.py:37 315 + #: ticketing/models.py:44 195 316 msgid "High" 196 317 msgstr "" 318 + 319 + #~ msgid "Comment and close" 320 + #~ msgstr "Commentaire et fermer" 321 + 322 + #~ msgid "No Category" 323 + #~ msgstr "Aucune catégorie"
+1 -1
paw/settings.py
··· 41 41 "django.contrib.sessions", 42 42 "django.contrib.messages", 43 43 "django.contrib.staticfiles", 44 - "colorfield", 44 + "status", 45 45 ] 46 46 47 47 AUTH_USER_MODEL = "core.PawUser"
+20 -5
paw/templates/base.html
··· 1 1 <!DOCTYPE html> 2 2 {% load static %} 3 - <html lang="en"{% if request.user and request.user.use_darkmode %} data-theme="dark" {% endif %}> 3 + <html lang="en"{% if request.user.is_authenticated %}{% if request.user.use_darkmode %} data-theme="dark"{% else %} data-theme="light" {% endif %}{% endif %}> 4 4 <head> 5 5 <meta charset="UTF-8"> 6 6 <meta http-equiv="X-UA-Compatible" content="IE=edge"> ··· 9 9 <title>paw</title> 10 10 </head> 11 11 <body> 12 - 13 - {% block content %} 14 - {% endblock %} 15 - 12 + <div class="container h-full min-h-screen mx-auto flex flex-col w-full"> 13 + <div class="navbar"> 14 + <div class="navbar-start"> 15 + <a class="" href="/">{% include 'partials/logo.html' with responsive=False %}</a> 16 + </div> 17 + <div class="navbar-center"></div> 18 + <div class="navbar-end"> 19 + <a class="btn mr-4" href="{% url 'all_tickets' %}">Tickets</a> 20 + <a class="btn" href="{% url 'incident-list' %}">Status</a> 21 + </div> 22 + </div> 23 + <div class="flex-grow flex"> 24 + {% block content %} 25 + {% endblock %} 26 + </div> 27 + <div class="footer w-full flex justify-end p-2"> 28 + <p class="text-sm text-base-content">v{{ app_version }}</p> 29 + </div> 30 + </div> 16 31 </body> 17 32 </html>
+41 -46
paw/templates/core/login.html
··· 2 2 {% extends 'base.html' %} 3 3 {% block content %} 4 4 {% load i18n %} 5 - <div class="flex flex-col w-full max-w-xl mx-auto h-full min-h-screen justify-center"> 6 - <div class="p-4"> 7 - <div class="mb-4"> 8 - {% include 'partials/logo.html' with responsive=False %} 9 - </div> 10 - <div class="flex items-center"> 11 - <h1 class="text-3xl font-bold p-2">{% trans 'Log In' %}</h1> 12 - <div class="flex-grow"></div> 13 - <a href="{% url 'register' %}" class="btn btn-sm btn-neutral">{% trans 'Register Account' %}</a> 14 - </div> 15 - <div class="bg-base-200 rounded p-8"> 16 - <form method="post"> 17 - {% csrf_token %} 5 + <div class="self-center w-full max-w-xl mx-auto"> 6 + <div class="flex items-center"> 7 + <h1 class="text-3xl font-bold p-2">{% trans 'Log In' %}</h1> 8 + <div class="flex-grow"></div> 9 + <a href="{% url 'register' %}" class="btn btn-sm btn-neutral">{% trans 'Register Account' %}</a> 10 + </div> 11 + <div class="bg-base-200 rounded p-8"> 12 + <form method="post"> 13 + {% csrf_token %} 18 14 19 - {% if form.non_field_errors %} 20 - <div role="alert" class="alert alert-error mb-4"> 21 - <svg xmlns="http://www.w3.org/2000/svg" class="hidden sm:block stroke-current shrink-0 h-6 w-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 10l4 4m0 -4l-4 4" /><path d="M12 3c7.2 0 9 1.8 9 9s-1.8 9 -9 9s-9 -1.8 -9 -9s1.8 -9 9 -9z" /></svg> 22 - <span>{{ form.non_field_errors }}</span> 15 + {% if form.non_field_errors %} 16 + <div role="alert" class="alert alert-error mb-4"> 17 + <svg xmlns="http://www.w3.org/2000/svg" class="hidden sm:block stroke-current shrink-0 h-6 w-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 10l4 4m0 -4l-4 4" /><path d="M12 3c7.2 0 9 1.8 9 9s-1.8 9 -9 9s-9 -1.8 -9 -9s1.8 -9 9 -9z" /></svg> 18 + <span>{{ form.non_field_errors }}</span> 19 + </div> 20 + {% endif %} 21 + 22 + <div> 23 + <label class="label"> 24 + <span class="text-base label-text" for="{{ form.username.id_for_label }}">{% trans 'Username' %}</span> 25 + </label> 26 + <input type="text" name="username" placeholder="Username" class="w-full input input-bordered" /> 27 + </div> 28 + <label class="form-control w-full"> 29 + <div class="label"> 30 + <span class="text-base label-text" for="{{ form.password.id_for_label }}">{% trans 'Password' %}</span> 23 31 </div> 24 - {% endif %} 25 - 26 - <div> 27 - <label class="label"> 28 - <span class="text-base label-text" for="{{ form.username.id_for_label }}">{% trans 'Username' %}</span> 29 - </label> 30 - <input type="text" name="username" placeholder="Username" class="w-full input input-bordered" /> 32 + <input type="password" name="password" placeholder="Enter Password" 33 + class="w-full input input-bordered" /> 34 + <div class="label"> 35 + <span class="label-text-alt"><a href="" class="link">{% trans 'Password Reset' %}</a></span> 31 36 </div> 32 - <label class="form-control w-full"> 33 - <div class="label"> 34 - <span class="text-base label-text" for="{{ form.password.id_for_label }}">{% trans 'Password' %}</span> 35 - </div> 36 - <input type="password" name="password" placeholder="Enter Password" 37 - class="w-full input input-bordered" /> 38 - <div class="label"> 39 - <span class="label-text-alt"><a href="" class="link">{% trans 'Password Reset' %}</a></span> 40 - </div> 41 - </label> 42 - <div class="flex justify-end mt-2"> 43 - <button type="submit" class="btn btn-accent">{% trans 'Log In' %}</button> 44 - </div> 45 - </form> 46 - {% if google_sso_enabled %} 47 - <div class="divider"></div> 48 - <a href="{{ google_sso_auth_url }}" class="btn w-full bg-[#4285F4] hover:bg-[#4285F4]/90 border-[#4285F4] text-white"> 49 - <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 2a9.96 9.96 0 0 1 6.29 2.226a1 1 0 0 1 .04 1.52l-1.51 1.362a1 1 0 0 1 -1.265 .06a6 6 0 1 0 2.103 6.836l.001 -.004h-3.66a1 1 0 0 1 -.992 -.883l-.007 -.117v-2a1 1 0 0 1 1 -1h6.945a1 1 0 0 1 .994 .89c.04 .367 .061 .737 .061 1.11c0 5.523 -4.477 10 -10 10s-10 -4.477 -10 -10s4.477 -10 10 -10z" stroke-width="0" fill="currentColor" /></svg> 50 - {% trans 'Log in with Google' %} 51 - </a> 52 - {% endif %} 53 - </div> 37 + </label> 38 + <div class="flex justify-end mt-2"> 39 + <button type="submit" class="btn btn-accent">{% trans 'Log In' %}</button> 40 + </div> 41 + </form> 42 + {% if google_sso_enabled %} 43 + <div class="divider"></div> 44 + <a href="{{ google_sso_auth_url }}" class="btn w-full bg-[#4285F4] hover:bg-[#4285F4]/90 border-[#4285F4] text-white"> 45 + <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 2a9.96 9.96 0 0 1 6.29 2.226a1 1 0 0 1 .04 1.52l-1.51 1.362a1 1 0 0 1 -1.265 .06a6 6 0 1 0 2.103 6.836l.001 -.004h-3.66a1 1 0 0 1 -.992 -.883l-.007 -.117v-2a1 1 0 0 1 1 -1h6.945a1 1 0 0 1 .994 .89c.04 .367 .061 .737 .061 1.11c0 5.523 -4.477 10 -10 10s-10 -4.477 -10 -10s4.477 -10 10 -10z" stroke-width="0" fill="currentColor" /></svg> 46 + {% trans 'Log in with Google' %} 47 + </a> 48 + {% endif %} 54 49 </div> 55 50 </div> 56 51 {% endblock %}
+35 -40
paw/templates/core/register.html
··· 2 2 {% extends 'base.html' %} 3 3 {% block content %} 4 4 {% load i18n %} 5 - <div class="flex flex-col w-full max-w-xl mx-auto h-full min-h-screen justify-center"> 6 - <div class="p-4"> 7 - <div class="mb-4"> 8 - {% include 'partials/logo.html' with responsive=False %} 9 - </div> 10 - <h1 class="text-3xl font-bold p-2">Register a new account</h1> 11 - <div class="bg-base-200 rounded p-8"> 12 - <form method="post"> 13 - {% csrf_token %} 5 + <div class="self-center w-full max-w-xl mx-auto p-4"> 6 + <h1 class="text-3xl font-bold p-2">Register a new account</h1> 7 + <div class="bg-base-200 rounded p-8"> 8 + <form method="post"> 9 + {% csrf_token %} 14 10 15 - {% if form.non_field_errors %} 16 - <div role="alert" class="alert alert-error mb-4"> 17 - <svg xmlns="http://www.w3.org/2000/svg" class="hidden sm:block stroke-current shrink-0 h-6 w-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 10l4 4m0 -4l-4 4" /><path d="M12 3c7.2 0 9 1.8 9 9s-1.8 9 -9 9s-9 -1.8 -9 -9s1.8 -9 9 -9z" /></svg> 18 - <span>{{ form.non_field_errors }}</span> 19 - </div> 20 - {% endif %} 11 + {% if form.non_field_errors %} 12 + <div role="alert" class="alert alert-error mb-4"> 13 + <svg xmlns="http://www.w3.org/2000/svg" class="hidden sm:block stroke-current shrink-0 h-6 w-6" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10 10l4 4m0 -4l-4 4" /><path d="M12 3c7.2 0 9 1.8 9 9s-1.8 9 -9 9s-9 -1.8 -9 -9s1.8 -9 9 -9z" /></svg> 14 + <span>{{ form.non_field_errors }}</span> 15 + </div> 16 + {% endif %} 21 17 22 - <div> 18 + <div> 19 + <label class="label"> 20 + <span class="text-base label-text" for="{{ form.username.id_for_label }}">Username</span> 21 + </label> 22 + {{ form.username }} 23 + </div> 24 + <div> 25 + <label class="label"> 26 + <span class="text-base label-text" for="{{ form.email.id_for_label }}">Email Address</span> 27 + </label> 28 + {{ form.email}} 29 + </div> 30 + <div> 23 31 <label class="label"> 24 - <span class="text-base label-text" for="{{ form.username.id_for_label }}">Username</span> 32 + <span class="text-base label-text" for="{{ form.password.id_for_label }}">Password</span> 25 33 </label> 26 - {{ form.username }} 27 - </div> 28 - <div> 29 - <label class="label"> 30 - <span class="text-base label-text" for="{{ form.email.id_for_label }}">Email Address</span> 31 - </label> 32 - {{ form.email}} 33 - </div> 34 - <div> 35 - <label class="label"> 36 - <span class="text-base label-text" for="{{ form.password.id_for_label }}">Password</span> 37 - </label> 38 - {{ form.password }} 39 - </div> 40 - <div> 41 - <label class="label"> 42 - <span class="text-base label-text" for="{{ form.password_confirm.id_for_label }}">Confirm Password</span> 43 - </label> 44 - {{ form.password_confirm }} 34 + {{ form.password }} 45 35 </div> 46 - <div class="flex justify-end mt-4"> 47 - <button type="submit" class="btn btn-accent">Register</button> 48 - </div> 49 - </form> 36 + <div> 37 + <label class="label"> 38 + <span class="text-base label-text" for="{{ form.password_confirm.id_for_label }}">Confirm Password</span> 39 + </label> 40 + {{ form.password_confirm }} 50 41 </div> 42 + <div class="flex justify-end mt-4"> 43 + <button type="submit" class="btn btn-accent">Register</button> 44 + </div> 45 + </form> 51 46 </div> 52 47 </div> 53 48 {% endblock %}
+14 -2
paw/templates/dashboard_base.html
··· 1 - {% extends 'base.html' %} 1 + <!DOCTYPE html> 2 + {% load static %} 3 + <html lang="en"{% if request.user %}{% if request.user.use_darkmode %} data-theme="dark"{% else %} data-theme="light" {% endif %}{% endif %}> 4 + <head> 5 + <meta charset="UTF-8"> 6 + <meta http-equiv="X-UA-Compatible" content="IE=edge"> 7 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 8 + <link href="{% static 'css/paw.css' %}?v={{ website_version }}" rel="stylesheet"> 9 + <title>paw</title> 10 + </head> 11 + <body> 2 12 {% block content %} 3 13 {% load i18n %} 4 14 <div class="flex h-full min-h-screen"> ··· 61 71 {% endblock %} 62 72 </div> 63 73 </div> 64 - {% endblock %} 74 + {% endblock %} 75 + </body> 76 + </html>
+21 -4
paw/templates/ticketing/ticket_detail.html
··· 6 6 <h1 class="text-2xl font-bold mb-4">{{ ticket.title }}</h1> 7 7 <div class="card bg-base-300 rounded-box p-4 mb-4 whitespace-pre-line">{{ ticket.description }}</div> 8 8 {% if attachments %} 9 - <h2 class="font-semibold mb-2">{% trans 'Attachments' %}</h2> 10 - <div class="flex flex-wrap mb-6"> 9 + <h2 class="font-semibold text-sm mb-1">{% trans 'Attachments' %}</h2> 10 + <div class="flex flex-wrap mb-2"> 11 11 {% for attachment in attachments %} 12 - <a href="{{ attachment.url }}" target="_blank" class="badge badge-lg badge-accent flex items-center mr-2 mb-2"> 12 + <a href="{{ attachment.url }}" target="_blank" class="badge badge-lg badge-accent flex items-center mr-1 mb-1"> 13 13 <svg xmlns="http://www.w3.org/2000/svg"class="w-4 h-4 mr-1" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 7l-6.5 6.5a1.5 1.5 0 0 0 3 3l6.5 -6.5a3 3 0 0 0 -6 -6l-6.5 6.5a4.5 4.5 0 0 0 9 9l6.5 -6.5" /></svg> 14 14 {% trans 'Attachment' %} {{ forloop.counter }} 15 15 </a> 16 16 {% endfor %} 17 17 </div> 18 18 {% endif %} 19 - <h1 class="text-xl font-bold mb-4">{% trans 'Activity' %}</h1> 19 + 20 + {% if ticket.follow_up_to %} 21 + <h2 class="font-semibold text-sm mb-1">{% trans 'Follow-Up Ticket to' %}</h2> 22 + <a href="{% url 'ticket_detail' ticket.follow_up_to.id %}" class="w-full block py-1 px-2 bg-base-200 border border-base-300 rounded-box mb-1"> 23 + {{ ticket.follow_up_to.title }} 24 + </a> 25 + {% endif %} 26 + 27 + {% if ticket.followed_up_by %} 28 + <h2 class="font-semibold text-sm mb-1">{% trans 'Followed-Up by' %}</h2> 29 + {% for related_ticket in ticket.followed_up_by %} 30 + <a href="{% url 'ticket_detail' related_ticket.id %}" class="w-full block py-1 px-2 bg-base-200 border border-base-300 rounded-box mb-1"> 31 + {{ related_ticket.title }} 32 + </a> 33 + {% endfor %} 34 + {% endif %} 35 + 36 + <h1 class="text-xl font-bold my-4">{% trans 'Activity' %}</h1> 20 37 <div class="mb-4"> 21 38 {% for comment in comments %} 22 39 {% if not comment.is_only_for_staff or comment.is_only_for_staff and request.user.is_staff %}
+1
paw/urls.py
··· 25 25 path("accounts/", include("django.contrib.auth.urls")), 26 26 path("", include("core.urls")), 27 27 path("", include("ticketing.urls")), 28 + path("status", include("status.urls")), 28 29 ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 29 30 30 31 if settings.DEBUG:
+541 -38
static/css/paw.css
··· 740 740 --tw-backdrop-sepia: ; 741 741 } 742 742 743 + .container { 744 + width: 100%; 745 + } 746 + 747 + @media (min-width: 640px) { 748 + .container { 749 + max-width: 640px; 750 + } 751 + } 752 + 753 + @media (min-width: 768px) { 754 + .container { 755 + max-width: 768px; 756 + } 757 + } 758 + 759 + @media (min-width: 1024px) { 760 + .container { 761 + max-width: 1024px; 762 + } 763 + } 764 + 765 + @media (min-width: 1280px) { 766 + .container { 767 + max-width: 1280px; 768 + } 769 + } 770 + 771 + @media (min-width: 1536px) { 772 + .container { 773 + max-width: 1536px; 774 + } 775 + } 776 + 743 777 .alert { 744 778 display: grid; 745 779 width: 100%; ··· 830 864 .label a:hover { 831 865 --tw-text-opacity: 1; 832 866 color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); 867 + } 868 + 869 + .menu li > *:not(ul, .menu-title, details, .btn):active, 870 + .menu li > *:not(ul, .menu-title, details, .btn).active, 871 + .menu li > details > summary:active { 872 + --tw-bg-opacity: 1; 873 + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); 874 + --tw-text-opacity: 1; 875 + color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity))); 833 876 } 834 877 835 878 .table tr.hover:hover, ··· 1112 1155 background-color: var(--fallback-bc,oklch(var(--bc)/0.1)); 1113 1156 } 1114 1157 1158 + .dropdown { 1159 + position: relative; 1160 + display: inline-block; 1161 + } 1162 + 1163 + .dropdown > *:not(summary):focus { 1164 + outline: 2px solid transparent; 1165 + outline-offset: 2px; 1166 + } 1167 + 1168 + .dropdown .dropdown-content { 1169 + position: absolute; 1170 + } 1171 + 1172 + .dropdown:is(:not(details)) .dropdown-content { 1173 + visibility: hidden; 1174 + opacity: 0; 1175 + transform-origin: top; 1176 + --tw-scale-x: .95; 1177 + --tw-scale-y: .95; 1178 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 1179 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; 1180 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; 1181 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; 1182 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 1183 + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); 1184 + transition-duration: 200ms; 1185 + } 1186 + 1187 + .dropdown-end .dropdown-content { 1188 + inset-inline-end: 0px; 1189 + } 1190 + 1191 + .dropdown-left .dropdown-content { 1192 + bottom: auto; 1193 + inset-inline-end: 100%; 1194 + top: 0px; 1195 + transform-origin: right; 1196 + } 1197 + 1198 + .dropdown-right .dropdown-content { 1199 + bottom: auto; 1200 + inset-inline-start: 100%; 1201 + top: 0px; 1202 + transform-origin: left; 1203 + } 1204 + 1205 + .dropdown-bottom .dropdown-content { 1206 + bottom: auto; 1207 + top: 100%; 1208 + transform-origin: top; 1209 + } 1210 + 1211 + .dropdown-top .dropdown-content { 1212 + bottom: 100%; 1213 + top: auto; 1214 + transform-origin: bottom; 1215 + } 1216 + 1217 + .dropdown-end.dropdown-right .dropdown-content { 1218 + bottom: 0px; 1219 + top: auto; 1220 + } 1221 + 1222 + .dropdown-end.dropdown-left .dropdown-content { 1223 + bottom: 0px; 1224 + top: auto; 1225 + } 1226 + 1227 + .dropdown.dropdown-open .dropdown-content, 1228 + .dropdown:not(.dropdown-hover):focus .dropdown-content, 1229 + .dropdown:focus-within .dropdown-content { 1230 + visibility: visible; 1231 + opacity: 1; 1232 + } 1233 + 1115 1234 @media (hover: hover) { 1235 + .dropdown.dropdown-hover:hover .dropdown-content { 1236 + visibility: visible; 1237 + opacity: 1; 1238 + } 1239 + 1116 1240 .btn:hover { 1117 1241 --tw-border-opacity: 1; 1118 1242 border-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity))); ··· 1157 1281 } 1158 1282 } 1159 1283 1284 + .btn-outline.btn-secondary:hover { 1285 + --tw-text-opacity: 1; 1286 + color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity))); 1287 + } 1288 + 1289 + @supports (color: color-mix(in oklab, black, black)) { 1290 + .btn-outline.btn-secondary:hover { 1291 + background-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black); 1292 + border-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black); 1293 + } 1294 + } 1295 + 1160 1296 .btn-outline.btn-accent:hover { 1161 1297 --tw-text-opacity: 1; 1162 1298 color: var(--fallback-ac,oklch(var(--ac)/var(--tw-text-opacity))); ··· 1221 1357 border-color: color-mix(in oklab, var(--fallback-p,oklch(var(--p)/1)) 90%, black); 1222 1358 } 1223 1359 } 1360 + 1361 + .dropdown.dropdown-hover:hover .dropdown-content { 1362 + --tw-scale-x: 1; 1363 + --tw-scale-y: 1; 1364 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 1365 + } 1366 + 1367 + :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):not(.active, .btn):hover, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):not(.active, .btn):hover { 1368 + cursor: pointer; 1369 + outline: 2px solid transparent; 1370 + outline-offset: 2px; 1371 + } 1372 + 1373 + @supports (color: oklch(0 0 0)) { 1374 + :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):not(.active, .btn):hover, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):not(.active, .btn):hover { 1375 + background-color: var(--fallback-bc,oklch(var(--bc)/0.1)); 1376 + } 1377 + } 1378 + } 1379 + 1380 + .dropdown:is(details) summary::-webkit-details-marker { 1381 + display: none; 1224 1382 } 1225 1383 1226 1384 .file-input { ··· 1277 1435 animation: button-pop var(--animation-btn, 0.25s) ease-out; 1278 1436 } 1279 1437 1438 + .footer { 1439 + display: grid; 1440 + width: 100%; 1441 + grid-auto-flow: row; 1442 + place-items: start; 1443 + -moz-column-gap: 1rem; 1444 + column-gap: 1rem; 1445 + row-gap: 2.5rem; 1446 + font-size: 0.875rem; 1447 + line-height: 1.25rem; 1448 + } 1449 + 1450 + .footer > * { 1451 + display: grid; 1452 + place-items: start; 1453 + gap: 0.5rem; 1454 + } 1455 + 1456 + @media (min-width: 48rem) { 1457 + .footer { 1458 + grid-auto-flow: column; 1459 + } 1460 + 1461 + .footer-center { 1462 + grid-auto-flow: row dense; 1463 + } 1464 + } 1465 + 1280 1466 .form-control { 1281 1467 display: flex; 1282 1468 flex-direction: column; ··· 1388 1574 text-decoration-line: underline; 1389 1575 } 1390 1576 1577 + .menu { 1578 + display: flex; 1579 + flex-direction: column; 1580 + flex-wrap: wrap; 1581 + font-size: 0.875rem; 1582 + line-height: 1.25rem; 1583 + padding: 0.5rem; 1584 + } 1585 + 1586 + .menu :where(li ul) { 1587 + position: relative; 1588 + white-space: nowrap; 1589 + margin-inline-start: 1rem; 1590 + padding-inline-start: 0.5rem; 1591 + } 1592 + 1593 + .menu :where(li:not(.menu-title) > *:not(ul, details, .menu-title, .btn)), .menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) { 1594 + display: grid; 1595 + grid-auto-flow: column; 1596 + align-content: flex-start; 1597 + align-items: center; 1598 + gap: 0.5rem; 1599 + grid-auto-columns: minmax(auto, max-content) auto max-content; 1600 + -webkit-user-select: none; 1601 + -moz-user-select: none; 1602 + user-select: none; 1603 + } 1604 + 1605 + .menu li.disabled { 1606 + cursor: not-allowed; 1607 + -webkit-user-select: none; 1608 + -moz-user-select: none; 1609 + user-select: none; 1610 + color: var(--fallback-bc,oklch(var(--bc)/0.3)); 1611 + } 1612 + 1613 + .menu :where(li > .menu-dropdown:not(.menu-dropdown-show)) { 1614 + display: none; 1615 + } 1616 + 1617 + :where(.menu li) { 1618 + position: relative; 1619 + display: flex; 1620 + flex-shrink: 0; 1621 + flex-direction: column; 1622 + flex-wrap: wrap; 1623 + align-items: stretch; 1624 + } 1625 + 1391 1626 :where(.menu li) .badge { 1392 1627 justify-self: end; 1393 1628 } 1394 1629 1630 + .navbar { 1631 + display: flex; 1632 + align-items: center; 1633 + padding: var(--navbar-padding, 0.5rem); 1634 + min-height: 4rem; 1635 + width: 100%; 1636 + } 1637 + 1638 + :where(.navbar > *:not(script, style)) { 1639 + display: inline-flex; 1640 + align-items: center; 1641 + } 1642 + 1643 + .navbar-start { 1644 + width: 50%; 1645 + justify-content: flex-start; 1646 + } 1647 + 1648 + .navbar-center { 1649 + flex-shrink: 0; 1650 + } 1651 + 1652 + .navbar-end { 1653 + width: 50%; 1654 + justify-content: flex-end; 1655 + } 1656 + 1395 1657 .select { 1396 1658 display: inline-flex; 1397 1659 cursor: pointer; ··· 1570 1832 var(--togglehandleborder); 1571 1833 } 1572 1834 1835 + .alert-success { 1836 + border-color: var(--fallback-su,oklch(var(--su)/0.2)); 1837 + --tw-text-opacity: 1; 1838 + color: var(--fallback-suc,oklch(var(--suc)/var(--tw-text-opacity))); 1839 + --alert-bg: var(--fallback-su,oklch(var(--su)/1)); 1840 + --alert-bg-mix: var(--fallback-b1,oklch(var(--b1)/1)); 1841 + } 1842 + 1843 + .alert-warning { 1844 + border-color: var(--fallback-wa,oklch(var(--wa)/0.2)); 1845 + --tw-text-opacity: 1; 1846 + color: var(--fallback-wac,oklch(var(--wac)/var(--tw-text-opacity))); 1847 + --alert-bg: var(--fallback-wa,oklch(var(--wa)/1)); 1848 + --alert-bg-mix: var(--fallback-b1,oklch(var(--b1)/1)); 1849 + } 1850 + 1573 1851 .alert-error { 1574 1852 border-color: var(--fallback-er,oklch(var(--er)/0.2)); 1575 1853 --tw-text-opacity: 1; ··· 1670 1948 border-color: var(--btn-color, var(--fallback-b2)); 1671 1949 } 1672 1950 1951 + .btn-secondary { 1952 + --btn-color: var(--fallback-s); 1953 + } 1954 + 1673 1955 .btn-accent { 1674 1956 --btn-color: var(--fallback-a); 1675 1957 } ··· 1692 1974 } 1693 1975 1694 1976 @supports (color: color-mix(in oklab, black, black)) { 1977 + .btn-outline.btn-secondary.btn-active { 1978 + background-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black); 1979 + border-color: color-mix(in oklab, var(--fallback-s,oklch(var(--s)/1)) 90%, black); 1980 + } 1981 + 1695 1982 .btn-outline.btn-accent.btn-active { 1696 1983 background-color: color-mix(in oklab, var(--fallback-a,oklch(var(--a)/1)) 90%, black); 1697 1984 border-color: color-mix(in oklab, var(--fallback-a,oklch(var(--a)/1)) 90%, black); ··· 1720 2007 } 1721 2008 1722 2009 @supports (color: oklch(0 0 0)) { 2010 + .btn-secondary { 2011 + --btn-color: var(--s); 2012 + } 2013 + 1723 2014 .btn-accent { 1724 2015 --btn-color: var(--a); 1725 2016 } ··· 1739 2030 .btn-error { 1740 2031 --btn-color: var(--er); 1741 2032 } 2033 + } 2034 + 2035 + .btn-secondary { 2036 + --tw-text-opacity: 1; 2037 + color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity))); 2038 + outline-color: var(--fallback-s,oklch(var(--s)/1)); 1742 2039 } 1743 2040 1744 2041 .btn-accent { ··· 1797 2094 .btn-ghost.btn-active { 1798 2095 border-color: transparent; 1799 2096 background-color: var(--fallback-bc,oklch(var(--bc)/0.2)); 2097 + } 2098 + 2099 + .btn-outline.btn-secondary { 2100 + --tw-text-opacity: 1; 2101 + color: var(--fallback-s,oklch(var(--s)/var(--tw-text-opacity))); 2102 + } 2103 + 2104 + .btn-outline.btn-secondary.btn-active { 2105 + --tw-text-opacity: 1; 2106 + color: var(--fallback-sc,oklch(var(--sc)/var(--tw-text-opacity))); 1800 2107 } 1801 2108 1802 2109 .btn-outline.btn-accent { ··· 2003 2310 gap: 1rem; 2004 2311 } 2005 2312 2313 + .dropdown.dropdown-open .dropdown-content, 2314 + .dropdown:focus .dropdown-content, 2315 + .dropdown:focus-within .dropdown-content { 2316 + --tw-scale-x: 1; 2317 + --tw-scale-y: 1; 2318 + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); 2319 + } 2320 + 2006 2321 .file-input-bordered { 2007 2322 --tw-border-opacity: 0.2; 2008 2323 } ··· 2133 2448 outline-offset: 2px; 2134 2449 } 2135 2450 2451 + :where(.menu li:empty) { 2452 + --tw-bg-opacity: 1; 2453 + background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity))); 2454 + opacity: 0.1; 2455 + margin: 0.5rem 1rem; 2456 + height: 1px; 2457 + } 2458 + 2459 + .menu :where(li ul):before { 2460 + position: absolute; 2461 + bottom: 0.75rem; 2462 + inset-inline-start: 0px; 2463 + top: 0.75rem; 2464 + width: 1px; 2465 + --tw-bg-opacity: 1; 2466 + background-color: var(--fallback-bc,oklch(var(--bc)/var(--tw-bg-opacity))); 2467 + opacity: 0.1; 2468 + content: ""; 2469 + } 2470 + 2471 + .menu :where(li:not(.menu-title) > *:not(ul, details, .menu-title, .btn)), 2472 + .menu :where(li:not(.menu-title) > details > summary:not(.menu-title)) { 2473 + border-radius: var(--rounded-btn, 0.5rem); 2474 + padding-left: 1rem; 2475 + padding-right: 1rem; 2476 + padding-top: 0.5rem; 2477 + padding-bottom: 0.5rem; 2478 + text-align: start; 2479 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter; 2480 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; 2481 + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-backdrop-filter; 2482 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 2483 + transition-timing-function: cubic-bezier(0, 0, 0.2, 1); 2484 + transition-duration: 200ms; 2485 + text-wrap: balance; 2486 + } 2487 + 2488 + :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):not(summary, .active, .btn).focus, :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):not(summary, .active, .btn):focus, :where(.menu li:not(.menu-title, .disabled) > *:not(ul, details, .menu-title)):is(summary):not(.active, .btn):focus-visible, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):not(summary, .active, .btn).focus, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):not(summary, .active, .btn):focus, :where(.menu li:not(.menu-title, .disabled) > details > summary:not(.menu-title)):is(summary):not(.active, .btn):focus-visible { 2489 + cursor: pointer; 2490 + background-color: var(--fallback-bc,oklch(var(--bc)/0.1)); 2491 + --tw-text-opacity: 1; 2492 + color: var(--fallback-bc,oklch(var(--bc)/var(--tw-text-opacity))); 2493 + outline: 2px solid transparent; 2494 + outline-offset: 2px; 2495 + } 2496 + 2497 + .menu li > *:not(ul, .menu-title, details, .btn):active, 2498 + .menu li > *:not(ul, .menu-title, details, .btn).active, 2499 + .menu li > details > summary:active { 2500 + --tw-bg-opacity: 1; 2501 + background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); 2502 + --tw-text-opacity: 1; 2503 + color: var(--fallback-nc,oklch(var(--nc)/var(--tw-text-opacity))); 2504 + } 2505 + 2506 + .menu :where(li > details > summary)::-webkit-details-marker { 2507 + display: none; 2508 + } 2509 + 2510 + .menu :where(li > details > summary):after, 2511 + .menu :where(li > .menu-dropdown-toggle):after { 2512 + justify-self: end; 2513 + display: block; 2514 + margin-top: -0.5rem; 2515 + height: 0.5rem; 2516 + width: 0.5rem; 2517 + transform: rotate(45deg); 2518 + transition-property: transform, margin-top; 2519 + transition-duration: 0.3s; 2520 + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); 2521 + content: ""; 2522 + transform-origin: 75% 75%; 2523 + box-shadow: 2px 2px; 2524 + pointer-events: none; 2525 + } 2526 + 2527 + .menu :where(li > details[open] > summary):after, 2528 + .menu :where(li > .menu-dropdown-toggle.menu-dropdown-show):after { 2529 + transform: rotate(225deg); 2530 + margin-top: 0; 2531 + } 2532 + 2136 2533 .mockup-browser .mockup-browser-toolbar .input { 2137 2534 position: relative; 2138 2535 margin-left: auto; ··· 2675 3072 border-start-end-radius: inherit; 2676 3073 } 2677 3074 3075 + .menu-horizontal { 3076 + display: inline-flex; 3077 + flex-direction: row; 3078 + } 3079 + 3080 + .menu-horizontal > li:not(.menu-title) > details > ul { 3081 + position: absolute; 3082 + } 3083 + 2678 3084 .select-sm { 2679 3085 height: 2rem; 2680 3086 min-height: 2rem; ··· 2749 3155 margin-inline-start: -1px; 2750 3156 } 2751 3157 3158 + .menu-horizontal > li:not(.menu-title) > details > ul { 3159 + margin-inline-start: 0px; 3160 + margin-top: 1rem; 3161 + padding-top: 0.5rem; 3162 + padding-bottom: 0.5rem; 3163 + padding-inline-end: 0.5rem; 3164 + } 3165 + 3166 + .menu-horizontal > li > details > ul:before { 3167 + content: none; 3168 + } 3169 + 3170 + :where(.menu-horizontal > li:not(.menu-title) > details > ul) { 3171 + border-radius: var(--rounded-box, 1rem); 3172 + --tw-bg-opacity: 1; 3173 + background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity))); 3174 + --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); 3175 + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); 3176 + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 3177 + } 3178 + 3179 + .menu-sm :where(li:not(.menu-title) > *:not(ul, details, .menu-title)), .menu-sm :where(li:not(.menu-title) > details > summary:not(.menu-title)) { 3180 + border-radius: var(--rounded-btn, 0.5rem); 3181 + padding-left: 0.75rem; 3182 + padding-right: 0.75rem; 3183 + padding-top: 0.25rem; 3184 + padding-bottom: 0.25rem; 3185 + font-size: 0.875rem; 3186 + line-height: 1.25rem; 3187 + } 3188 + 3189 + .menu-sm .menu-title { 3190 + padding-left: 0.75rem; 3191 + padding-right: 0.75rem; 3192 + padding-top: 0.5rem; 3193 + padding-bottom: 0.5rem; 3194 + } 3195 + 2752 3196 .steps-horizontal .step { 2753 3197 grid-template-rows: 40px 1fr; 2754 3198 grid-template-columns: auto; ··· 2800 3244 position: fixed; 2801 3245 } 2802 3246 3247 + .z-\[1\] { 3248 + z-index: 1; 3249 + } 3250 + 2803 3251 .order-first { 2804 3252 order: -9999; 3253 + } 3254 + 3255 + .m-4 { 3256 + margin: 1rem; 2805 3257 } 2806 3258 2807 3259 .mx-auto { ··· 2858 3310 margin-right: 1rem; 2859 3311 } 2860 3312 3313 + .mt-10 { 3314 + margin-top: 2.5rem; 3315 + } 3316 + 2861 3317 .mt-2 { 2862 3318 margin-top: 0.5rem; 2863 3319 } ··· 2868 3324 2869 3325 .mt-8 { 2870 3326 margin-top: 2rem; 3327 + } 3328 + 3329 + .mt-3 { 3330 + margin-top: 0.75rem; 2871 3331 } 2872 3332 2873 3333 .block { ··· 2950 3410 width: 1.25rem; 2951 3411 } 2952 3412 2953 - .w-52 { 2954 - width: 13rem; 2955 - } 2956 - 2957 3413 .w-6 { 2958 3414 width: 1.5rem; 2959 3415 } ··· 2966 3422 width: 100%; 2967 3423 } 2968 3424 3425 + .w-52 { 3426 + width: 13rem; 3427 + } 3428 + 3429 + .max-w-2xl { 3430 + max-width: 42rem; 3431 + } 3432 + 2969 3433 .max-w-4xl { 2970 3434 max-width: 56rem; 2971 3435 } ··· 2982 3446 max-width: 20rem; 2983 3447 } 2984 3448 3449 + .max-w-3xl { 3450 + max-width: 48rem; 3451 + } 3452 + 2985 3453 .flex-none { 2986 3454 flex: none; 3455 + } 3456 + 3457 + .flex-1 { 3458 + flex: 1 1 0%; 2987 3459 } 2988 3460 2989 3461 .shrink-0 { ··· 3014 3486 flex-wrap: wrap; 3015 3487 } 3016 3488 3017 - .items-start { 3018 - align-items: flex-start; 3019 - } 3020 - 3021 3489 .items-center { 3022 3490 align-items: center; 3491 + } 3492 + 3493 + .items-stretch { 3494 + align-items: stretch; 3023 3495 } 3024 3496 3025 3497 .justify-start { ··· 3042 3514 align-self: flex-end; 3043 3515 } 3044 3516 3517 + .self-center { 3518 + align-self: center; 3519 + } 3520 + 3045 3521 .overflow-y-auto { 3046 3522 overflow-y: auto; 3047 3523 } ··· 3062 3538 border-radius: 9999px; 3063 3539 } 3064 3540 3541 + .border { 3542 + border-width: 1px; 3543 + } 3544 + 3065 3545 .border-l-2 { 3066 3546 border-left-width: 2px; 3067 3547 } 3068 3548 3549 + .border-r-4 { 3550 + border-right-width: 4px; 3551 + } 3552 + 3553 + .border-l-8 { 3554 + border-left-width: 8px; 3555 + } 3556 + 3069 3557 .border-\[\#4285F4\] { 3070 3558 --tw-border-opacity: 1; 3071 3559 border-color: rgb(66 133 244 / var(--tw-border-opacity)); ··· 3076 3564 border-color: var(--fallback-b3,oklch(var(--b3)/var(--tw-border-opacity))); 3077 3565 } 3078 3566 3567 + .border-success { 3568 + --tw-border-opacity: 1; 3569 + border-color: var(--fallback-su,oklch(var(--su)/var(--tw-border-opacity))); 3570 + } 3571 + 3572 + .border-error { 3573 + --tw-border-opacity: 1; 3574 + border-color: var(--fallback-er,oklch(var(--er)/var(--tw-border-opacity))); 3575 + } 3576 + 3079 3577 .bg-\[\#4285F4\] { 3080 3578 --tw-bg-opacity: 1; 3081 3579 background-color: rgb(66 133 244 / var(--tw-bg-opacity)); ··· 3096 3594 background-color: var(--fallback-n,oklch(var(--n)/var(--tw-bg-opacity))); 3097 3595 } 3098 3596 3597 + .bg-base-100 { 3598 + --tw-bg-opacity: 1; 3599 + background-color: var(--fallback-b1,oklch(var(--b1)/var(--tw-bg-opacity))); 3600 + } 3601 + 3099 3602 .stroke-current { 3100 3603 stroke: currentColor; 3101 3604 } ··· 3120 3623 padding: 2rem; 3121 3624 } 3122 3625 3626 + .px-2 { 3627 + padding-left: 0.5rem; 3628 + padding-right: 0.5rem; 3629 + } 3630 + 3631 + .py-1 { 3632 + padding-top: 0.25rem; 3633 + padding-bottom: 0.25rem; 3634 + } 3635 + 3123 3636 .py-2 { 3124 3637 padding-top: 0.5rem; 3125 3638 padding-bottom: 0.5rem; 3639 + } 3640 + 3641 + .px-1 { 3642 + padding-left: 0.25rem; 3643 + padding-right: 0.25rem; 3644 + } 3645 + 3646 + .px-4 { 3647 + padding-left: 1rem; 3648 + padding-right: 1rem; 3126 3649 } 3127 3650 3128 3651 .text-center { ··· 3231 3754 opacity: 0.7; 3232 3755 } 3233 3756 3757 + .shadow { 3758 + --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); 3759 + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); 3760 + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); 3761 + } 3762 + 3234 3763 @media (min-width: 1024px) { 3235 3764 .lg\:btn-sm { 3236 3765 height: 2rem; ··· 3283 3812 .sm\:block { 3284 3813 display: block; 3285 3814 } 3286 - 3287 - .sm\:max-w-lg { 3288 - max-width: 32rem; 3289 - } 3290 - } 3291 - 3292 - @media (min-width: 768px) { 3293 - .md\:max-w-lg { 3294 - max-width: 32rem; 3295 - } 3296 3815 } 3297 3816 3298 3817 @media (min-width: 1024px) { ··· 3310 3829 3311 3830 .lg\:flex { 3312 3831 display: flex; 3832 + } 3833 + 3834 + .lg\:hidden { 3835 + display: none; 3313 3836 } 3314 3837 3315 3838 .lg\:w-72 { ··· 3343 3866 .lg\:px-3 { 3344 3867 padding-left: 0.75rem; 3345 3868 padding-right: 0.75rem; 3346 - } 3347 - } 3348 - 3349 - @media (min-width: 1280px) { 3350 - .xl\:max-w-lg { 3351 - max-width: 32rem; 3352 - } 3353 - } 3354 - 3355 - @media (min-width: 1536px) { 3356 - .\32xl\:mr-4 { 3357 - margin-right: 1rem; 3358 - } 3359 - 3360 - .\32xl\:max-w-lg { 3361 - max-width: 32rem; 3362 - } 3363 - 3364 - .\32xl\:flex-row { 3365 - flex-direction: row; 3366 3869 } 3367 3870 }
status/__init__.py

This is a binary file and will not be displayed.

+4
status/admin.py
··· 1 + from django.contrib import admin 2 + from .models import Incident 3 + 4 + admin.site.register(Incident)
+6
status/apps.py
··· 1 + from django.apps import AppConfig 2 + 3 + 4 + class StatusConfig(AppConfig): 5 + default_auto_field = "django.db.models.BigAutoField" 6 + name = "status"
+33
status/migrations/0001_initial.py
··· 1 + # Generated by Django 5.0.3 on 2024-03-12 23:48 2 + 3 + from django.db import migrations, models 4 + 5 + 6 + class Migration(migrations.Migration): 7 + 8 + initial = True 9 + 10 + dependencies = [] 11 + 12 + operations = [ 13 + migrations.CreateModel( 14 + name="Incident", 15 + fields=[ 16 + ( 17 + "id", 18 + models.BigAutoField( 19 + auto_created=True, 20 + primary_key=True, 21 + serialize=False, 22 + verbose_name="ID", 23 + ), 24 + ), 25 + ("title", models.CharField(max_length=200)), 26 + ("description", models.TextField()), 27 + ("created_at", models.DateTimeField(auto_now_add=True)), 28 + ("updated_at", models.DateTimeField(auto_now=True)), 29 + ("public", models.BooleanField(default=False)), 30 + ("resolved", models.BooleanField(default=False)), 31 + ], 32 + ), 33 + ]
status/migrations/__init__.py

This is a binary file and will not be displayed.

+13
status/models.py
··· 1 + from django.db import models 2 + 3 + 4 + class Incident(models.Model): 5 + title = models.CharField(max_length=200) 6 + description = models.TextField() 7 + created_at = models.DateTimeField(auto_now_add=True) 8 + updated_at = models.DateTimeField(auto_now=True) 9 + public = models.BooleanField(default=False) 10 + resolved = models.BooleanField(default=False) 11 + 12 + def __str__(self): 13 + return self.title
+40
status/templates/status/incident_list.html
··· 1 + {% extends 'base.html' %} {% block content %} 2 + {% load i18n %} 3 + <div class="flex flex-col w-full p-4"> 4 + 5 + {% comment %} Incidents {% endcomment %} 6 + <div class="w-full max-w-3xl mx-auto"> 7 + {% if existing_incidents %} 8 + <div role="alert" class="alert alert-warning"> 9 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="stroke-current shrink-0 h-6 w-6"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 5a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-14z" /><path d="M12 8v4" /><path d="M12 16h.01" /></svg> 10 + <span>{% trans 'Some services might not be fully operational' %}</span> 11 + </div> 12 + {% else %} 13 + <div role="alert" class="alert alert-success"> 14 + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="stroke-current shrink-0 h-6 w-6"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 3m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z" /><path d="M9 12l2 2l4 -4" /></svg> 15 + <span>{% trans 'All services are operational' %}</span> 16 + </div> 17 + {% endif %} 18 + 19 + <h1 class="text-2xl font-semibold mt-10 mb-2"> 20 + Incidents 21 + </h1> 22 + 23 + {% for incident in object_list %} 24 + <div class="w-full bg-base-200 rounded mb-4 p-4 border-l-8 {% if incident.resolved %}border-success{% else %}border-error{% endif %}"> 25 + <div class="text-xl mb-4 font-semibold flex items-center"> 26 + <span class="flex-grow">{{ incident.title }}</span> 27 + {% if incident.resolved %} 28 + <span class="badge badge-success">Resolved</span> 29 + {% else %} 30 + <span class="badge badge-error">Unresolved</span> 31 + {% endif %} 32 + </div> 33 + <p class="whitespace-pre-line">{{ incident.description }}</p> 34 + </div> 35 + {% empty %} 36 + <div>No incidents yet.</div> 37 + {% endfor %} 38 + </div> 39 + </div> 40 + {% endblock %}
+3
status/tests.py
··· 1 + from django.test import TestCase 2 + 3 + # Create your tests here.
+7
status/urls.py
··· 1 + from django.urls import path 2 + 3 + from .views import IncidentListView 4 + 5 + urlpatterns = [ 6 + path("", IncidentListView.as_view(), name="incident-list"), 7 + ]
+15
status/views.py
··· 1 + from django.shortcuts import render 2 + from django.views.generic import ListView 3 + from .models import Incident 4 + 5 + 6 + class IncidentListView(ListView): 7 + model = Incident 8 + 9 + def get_context_data(self, **kwargs): 10 + context = super().get_context_data(**kwargs) 11 + context["existing_incidents"] = Incident.objects.filter(public=True, resolved=False).exists() 12 + return context 13 + 14 + def get_queryset(self): 15 + return Incident.objects.filter(public=True).order_by('resolved')
+10 -8
theme/tailwind.config.js
··· 1 1 /** @type {import('tailwindcss').Config} */ 2 2 module.exports = { 3 - content: ["../paw/templates/**/*.{html,js}"], 3 + content: [ 4 + "../paw/templates/**/*.{html,js}", 5 + "../status/templates/**/*.{html,js}", 6 + ], 4 7 theme: { 5 8 extend: {}, 6 9 }, ··· 13 16 }, 14 17 dark: { 15 18 ...require("daisyui/src/theming/themes")["dark"], 16 - "accent": "#88C0D0", 17 - "secondary": "#81A1C1", 18 - "success": "#A3BE8C", 19 - "warning": "#EBCB8B", 20 - "error": "#BF616A", 19 + accent: "#88C0D0", 20 + secondary: "#81A1C1", 21 + success: "#A3BE8C", 22 + warning: "#EBCB8B", 23 + error: "#BF616A", 21 24 "--rounded-box": "0.4rem", 22 25 "--rounded-btn": "0.2rem", 23 26 "--rounded-badge": "0.4rem", ··· 26 29 }, 27 30 ], 28 31 }, 29 - } 30 - 32 + };
+3
ticketing/models.py
··· 76 76 77 77 self.assigned_team = team 78 78 self.save() 79 + 80 + def followed_up_by(self): 81 + return Ticket.objects.filter(follow_up_to=self) 79 82 80 83 def get_priority(self): 81 84 return self.Priority(self.priority).label