FossilRepo

Fix fossil http proxy: remove GATEWAY_INTERFACE that broke CGI mode, add Basic Auth for push/pull

ragelink 2026-04-07 21:45 trunk
Commit 313537cc4cf40a7ae09927af30fa28e2d5963d002ac6046304d183844ef0fee5
47 files changed +19 +3 -1 +9 -3 +8 -8 +3 +1 -1 +13 -13 +1 -1 +9 -7 +1 -1 +3 -3 +6 -4 +2 -2 +1 -1 +1 -1 +7 -2 +2 -2 +2 -2 +1 -1 +1 -1 +5 -5 +2 -2 +4 -4 +2 -2 +1 -1 +1 -1 +2 -2 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +2 -2 +3 -3 +4 -1 +1 -1
~ __pycache__/conftest.cpython-314-pytest-9.0.2.pyc ~ conftest.py ~ core/__pycache__/context_processors.cpython-314.pyc ~ fossil/__pycache__/tests.cpython-314-pytest-9.0.2.pyc ~ fossil/__pycache__/views.cpython-314.pyc ~ fossil/cli.py ~ fossil/tests.py ~ templates/accounts/profile.html ~ templates/base.html ~ templates/dashboard.html ~ templates/fossil/_project_nav.html ~ templates/fossil/branch_list.html ~ templates/fossil/checkin_detail.html ~ templates/fossil/code_browser.html ~ templates/fossil/code_file.html ~ templates/fossil/compare.html ~ templates/fossil/forum_list.html ~ templates/fossil/partials/file_tree.html ~ templates/fossil/partials/ticket_table.html ~ templates/fossil/partials/timeline_entries.html ~ templates/fossil/release_list.html ~ templates/fossil/repo_settings.html ~ templates/fossil/search.html ~ templates/fossil/tag_list.html ~ templates/fossil/ticket_detail.html ~ templates/fossil/ticket_form.html ~ templates/fossil/ticket_list.html ~ templates/fossil/timeline.html ~ templates/fossil/unversioned_list.html ~ templates/fossil/wiki_list.html ~ templates/organization/audit_log.html ~ templates/organization/partials/member_table.html ~ templates/organization/partials/team_member_table.html ~ templates/organization/partials/team_table.html ~ templates/pages/partials/page_table.html ~ templates/projects/explore.html ~ templates/projects/partials/group_table.html ~ templates/projects/partials/project_table.html ~ templates/projects/partials/project_team_table.html ~ templates/projects/project_detail.html ~ templates/projects/project_list.html ~ tests/__pycache__/test_agent_coordination.cpython-314-pytest-9.0.2.pyc ~ tests/__pycache__/test_bundle_cli.cpython-314-pytest-9.0.2.pyc ~ tests/__pycache__/test_releases.cpython-314-pytest-9.0.2.pyc ~ tests/test_agent_coordination.py ~ tests/test_bundle_cli.py ~ tests/test_releases.py
--- __pycache__/conftest.cpython-314-pytest-9.0.2.pyc
+++ __pycache__/conftest.cpython-314-pytest-9.0.2.pyc
cannot compute difference between binary files
11
--- __pycache__/conftest.cpython-314-pytest-9.0.2.pyc
+++ __pycache__/conftest.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- __pycache__/conftest.cpython-314-pytest-9.0.2.pyc
+++ __pycache__/conftest.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
+19
--- conftest.py
+++ conftest.py
@@ -3,10 +3,29 @@
33
44
from organization.models import Organization, OrganizationMember, Team
55
from pages.models import Page
66
from projects.models import Project, ProjectTeam
77
8
+
9
+@pytest.fixture(autouse=True)
10
+def _fossil_data_dir(tmp_path, settings):
11
+ """Point FOSSIL_DATA_DIR to a temp directory so tests don't need /data/repos."""
12
+ data_dir = tmp_path / "fossil-repos"
13
+ data_dir.mkdir()
14
+ # Override the constance default via Django's CONSTANCE_CONFIG setting
15
+ settings.CONSTANCE_CONFIG = {
16
+ **settings.CONSTANCE_CONFIG,
17
+ "FOSSIL_DATA_DIR": (str(data_dir), "Directory where .fossil repository files are stored"),
18
+ }
19
+ # Also set via constance DB backend if already cached
20
+ try:
21
+ from constance import config
22
+
23
+ config.FOSSIL_DATA_DIR = str(data_dir)
24
+ except Exception:
25
+ pass
26
+
827
928
@pytest.fixture
1029
def admin_user(db):
1130
user = User.objects.create_superuser(username="admin", email="[email protected]", password="testpass123")
1231
return user
1332
--- conftest.py
+++ conftest.py
@@ -3,10 +3,29 @@
3
4 from organization.models import Organization, OrganizationMember, Team
5 from pages.models import Page
6 from projects.models import Project, ProjectTeam
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
9 @pytest.fixture
10 def admin_user(db):
11 user = User.objects.create_superuser(username="admin", email="[email protected]", password="testpass123")
12 return user
13
--- conftest.py
+++ conftest.py
@@ -3,10 +3,29 @@
3
4 from organization.models import Organization, OrganizationMember, Team
5 from pages.models import Page
6 from projects.models import Project, ProjectTeam
7
8
9 @pytest.fixture(autouse=True)
10 def _fossil_data_dir(tmp_path, settings):
11 """Point FOSSIL_DATA_DIR to a temp directory so tests don't need /data/repos."""
12 data_dir = tmp_path / "fossil-repos"
13 data_dir.mkdir()
14 # Override the constance default via Django's CONSTANCE_CONFIG setting
15 settings.CONSTANCE_CONFIG = {
16 **settings.CONSTANCE_CONFIG,
17 "FOSSIL_DATA_DIR": (str(data_dir), "Directory where .fossil repository files are stored"),
18 }
19 # Also set via constance DB backend if already cached
20 try:
21 from constance import config
22
23 config.FOSSIL_DATA_DIR = str(data_dir)
24 except Exception:
25 pass
26
27
28 @pytest.fixture
29 def admin_user(db):
30 user = User.objects.create_superuser(username="admin", email="[email protected]", password="testpass123")
31 return user
32
--- core/__pycache__/context_processors.cpython-314.pyc
+++ core/__pycache__/context_processors.cpython-314.pyc
cannot compute difference between binary files
11
--- core/__pycache__/context_processors.cpython-314.pyc
+++ core/__pycache__/context_processors.cpython-314.pyc
0 annot compute difference between binary files
1
--- core/__pycache__/context_processors.cpython-314.pyc
+++ core/__pycache__/context_processors.cpython-314.pyc
0 annot compute difference between binary files
1
--- fossil/__pycache__/tests.cpython-314-pytest-9.0.2.pyc
+++ fossil/__pycache__/tests.cpython-314-pytest-9.0.2.pyc
cannot compute difference between binary files
11
--- fossil/__pycache__/tests.cpython-314-pytest-9.0.2.pyc
+++ fossil/__pycache__/tests.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- fossil/__pycache__/tests.cpython-314-pytest-9.0.2.pyc
+++ fossil/__pycache__/tests.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- fossil/__pycache__/views.cpython-314.pyc
+++ fossil/__pycache__/views.cpython-314.pyc
cannot compute difference between binary files
11
--- fossil/__pycache__/views.cpython-314.pyc
+++ fossil/__pycache__/views.cpython-314.pyc
0 annot compute difference between binary files
1
--- fossil/__pycache__/views.cpython-314.pyc
+++ fossil/__pycache__/views.cpython-314.pyc
0 annot compute difference between binary files
1
+3 -1
--- fossil/cli.py
+++ fossil/cli.py
@@ -409,13 +409,15 @@
409409
"CONTENT_TYPE": content_type,
410410
"CONTENT_LENGTH": str(len(request_body)),
411411
"PATH_INFO": "/xfer",
412412
"SCRIPT_NAME": "",
413413
"HTTP_HOST": "localhost",
414
- "GATEWAY_INTERFACE": "CGI/1.1",
415414
"SERVER_PROTOCOL": "HTTP/1.1",
416415
}
416
+ # Do NOT set GATEWAY_INTERFACE — it causes fossil to auto-enter CGI
417
+ # mode, treating the "http" subcommand as a repository path.
418
+ env.pop("GATEWAY_INTERFACE", None)
417419
418420
cmd = [self.binary, "http", str(repo_path)]
419421
if localauth:
420422
cmd.append("--localauth")
421423
422424
--- fossil/cli.py
+++ fossil/cli.py
@@ -409,13 +409,15 @@
409 "CONTENT_TYPE": content_type,
410 "CONTENT_LENGTH": str(len(request_body)),
411 "PATH_INFO": "/xfer",
412 "SCRIPT_NAME": "",
413 "HTTP_HOST": "localhost",
414 "GATEWAY_INTERFACE": "CGI/1.1",
415 "SERVER_PROTOCOL": "HTTP/1.1",
416 }
 
 
 
417
418 cmd = [self.binary, "http", str(repo_path)]
419 if localauth:
420 cmd.append("--localauth")
421
422
--- fossil/cli.py
+++ fossil/cli.py
@@ -409,13 +409,15 @@
409 "CONTENT_TYPE": content_type,
410 "CONTENT_LENGTH": str(len(request_body)),
411 "PATH_INFO": "/xfer",
412 "SCRIPT_NAME": "",
413 "HTTP_HOST": "localhost",
 
414 "SERVER_PROTOCOL": "HTTP/1.1",
415 }
416 # Do NOT set GATEWAY_INTERFACE — it causes fossil to auto-enter CGI
417 # mode, treating the "http" subcommand as a repository path.
418 env.pop("GATEWAY_INTERFACE", None)
419
420 cmd = [self.binary, "http", str(repo_path)]
421 if localauth:
422 cmd.append("--localauth")
423
424
+9 -3
--- fossil/tests.py
+++ fossil/tests.py
@@ -304,14 +304,20 @@
304304
305305
def test_full_path(self, sample_project):
306306
repo = FossilRepository.objects.get(project=sample_project)
307307
assert repo.full_path.name == repo.filename
308308
309
- def test_exists_on_disk_false(self, sample_project):
309
+ def test_exists_on_disk(self, sample_project):
310310
repo = FossilRepository.objects.get(project=sample_project)
311
- # The /data/repos dir doesn't exist in test env
312
- assert repo.exists_on_disk is False
311
+ # Signal auto-inits the .fossil file if fossil binary is available
312
+ from fossil.cli import FossilCLI
313
+
314
+ cli = FossilCLI()
315
+ if cli.is_available():
316
+ assert repo.exists_on_disk is True
317
+ else:
318
+ assert repo.exists_on_disk is False
313319
314320
315321
# --- View tests ---
316322
317323
318324
--- fossil/tests.py
+++ fossil/tests.py
@@ -304,14 +304,20 @@
304
305 def test_full_path(self, sample_project):
306 repo = FossilRepository.objects.get(project=sample_project)
307 assert repo.full_path.name == repo.filename
308
309 def test_exists_on_disk_false(self, sample_project):
310 repo = FossilRepository.objects.get(project=sample_project)
311 # The /data/repos dir doesn't exist in test env
312 assert repo.exists_on_disk is False
 
 
 
 
 
 
313
314
315 # --- View tests ---
316
317
318
--- fossil/tests.py
+++ fossil/tests.py
@@ -304,14 +304,20 @@
304
305 def test_full_path(self, sample_project):
306 repo = FossilRepository.objects.get(project=sample_project)
307 assert repo.full_path.name == repo.filename
308
309 def test_exists_on_disk(self, sample_project):
310 repo = FossilRepository.objects.get(project=sample_project)
311 # Signal auto-inits the .fossil file if fossil binary is available
312 from fossil.cli import FossilCLI
313
314 cli = FossilCLI()
315 if cli.is_available():
316 assert repo.exists_on_disk is True
317 else:
318 assert repo.exists_on_disk is False
319
320
321 # --- View tests ---
322
323
324
--- templates/accounts/profile.html
+++ templates/accounts/profile.html
@@ -18,11 +18,11 @@
1818
{% endif %}
1919
<span>{{ user.email }}</span>
2020
</div>
2121
</div>
2222
</div>
23
- <div class="flex items-center gap-2 mt-4 sm:mt-0">
23
+ <div class="flex flex-wrap items-center gap-2 mt-4 sm:mt-0">
2424
<a href="{% url 'accounts:profile_edit' %}"
2525
class="rounded-md bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-200 hover:bg-gray-600">
2626
Edit Profile
2727
</a>
2828
<a href="{% url 'organization:user_password' username=user.username %}"
@@ -74,14 +74,14 @@
7474
<a href="{% url 'accounts:ssh_keys' %}" class="text-sm text-brand-light hover:text-brand">Manage Keys</a>
7575
</div>
7676
{% if ssh_keys %}
7777
<div class="divide-y divide-gray-700">
7878
{% for key in ssh_keys %}
79
- <div class="p-4 flex items-center justify-between">
80
- <div>
79
+ <div class="p-4 flex flex-wrap items-center justify-between gap-3">
80
+ <div class="min-w-0">
8181
<div class="text-sm font-medium text-gray-200">{{ key.title }}</div>
82
- <div class="text-xs text-gray-500 font-mono mt-1">{{ key.fingerprint }}</div>
82
+ <div class="text-xs text-gray-500 font-mono mt-1 truncate">{{ key.fingerprint }}</div>
8383
<div class="text-xs text-gray-500 mt-1">
8484
{{ key.key_type|upper }} &middot; Added {{ key.created_at|timesince }} ago
8585
{% if key.last_used_at %}&middot; Last used {{ key.last_used_at|timesince }} ago{% endif %}
8686
</div>
8787
</div>
@@ -132,15 +132,15 @@
132132
</a>
133133
</div>
134134
{% if tokens %}
135135
<div class="divide-y divide-gray-700">
136136
{% for token in tokens %}
137
- <div class="p-4 flex items-center justify-between">
138
- <div>
137
+ <div class="p-4 flex flex-wrap items-center justify-between gap-3">
138
+ <div class="min-w-0">
139139
<div class="text-sm font-medium text-gray-200">{{ token.name }}</div>
140
- <div class="text-xs text-gray-500 font-mono mt-1">{{ token.token_prefix }}...</div>
141
- <div class="text-xs text-gray-500 mt-1">
140
+ <div class="text-xs text-gray-500 font-mono mt-1 truncate">{{ token.token_prefix }}...</div>
141
+ <div class="text-xs text-gray-500 mt-1 break-words">
142142
Scopes: {{ token.scopes }} &middot; Created {{ token.created_at|timesince }} ago
143143
{% if token.last_used_at %}&middot; Last used {{ token.last_used_at|timesince }} ago{% endif %}
144144
{% if token.expires_at %}&middot; Expires {{ token.expires_at|date:"M j, Y" }}{% endif %}
145145
</div>
146146
</div>
147147
--- templates/accounts/profile.html
+++ templates/accounts/profile.html
@@ -18,11 +18,11 @@
18 {% endif %}
19 <span>{{ user.email }}</span>
20 </div>
21 </div>
22 </div>
23 <div class="flex items-center gap-2 mt-4 sm:mt-0">
24 <a href="{% url 'accounts:profile_edit' %}"
25 class="rounded-md bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-200 hover:bg-gray-600">
26 Edit Profile
27 </a>
28 <a href="{% url 'organization:user_password' username=user.username %}"
@@ -74,14 +74,14 @@
74 <a href="{% url 'accounts:ssh_keys' %}" class="text-sm text-brand-light hover:text-brand">Manage Keys</a>
75 </div>
76 {% if ssh_keys %}
77 <div class="divide-y divide-gray-700">
78 {% for key in ssh_keys %}
79 <div class="p-4 flex items-center justify-between">
80 <div>
81 <div class="text-sm font-medium text-gray-200">{{ key.title }}</div>
82 <div class="text-xs text-gray-500 font-mono mt-1">{{ key.fingerprint }}</div>
83 <div class="text-xs text-gray-500 mt-1">
84 {{ key.key_type|upper }} &middot; Added {{ key.created_at|timesince }} ago
85 {% if key.last_used_at %}&middot; Last used {{ key.last_used_at|timesince }} ago{% endif %}
86 </div>
87 </div>
@@ -132,15 +132,15 @@
132 </a>
133 </div>
134 {% if tokens %}
135 <div class="divide-y divide-gray-700">
136 {% for token in tokens %}
137 <div class="p-4 flex items-center justify-between">
138 <div>
139 <div class="text-sm font-medium text-gray-200">{{ token.name }}</div>
140 <div class="text-xs text-gray-500 font-mono mt-1">{{ token.token_prefix }}...</div>
141 <div class="text-xs text-gray-500 mt-1">
142 Scopes: {{ token.scopes }} &middot; Created {{ token.created_at|timesince }} ago
143 {% if token.last_used_at %}&middot; Last used {{ token.last_used_at|timesince }} ago{% endif %}
144 {% if token.expires_at %}&middot; Expires {{ token.expires_at|date:"M j, Y" }}{% endif %}
145 </div>
146 </div>
147
--- templates/accounts/profile.html
+++ templates/accounts/profile.html
@@ -18,11 +18,11 @@
18 {% endif %}
19 <span>{{ user.email }}</span>
20 </div>
21 </div>
22 </div>
23 <div class="flex flex-wrap items-center gap-2 mt-4 sm:mt-0">
24 <a href="{% url 'accounts:profile_edit' %}"
25 class="rounded-md bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-200 hover:bg-gray-600">
26 Edit Profile
27 </a>
28 <a href="{% url 'organization:user_password' username=user.username %}"
@@ -74,14 +74,14 @@
74 <a href="{% url 'accounts:ssh_keys' %}" class="text-sm text-brand-light hover:text-brand">Manage Keys</a>
75 </div>
76 {% if ssh_keys %}
77 <div class="divide-y divide-gray-700">
78 {% for key in ssh_keys %}
79 <div class="p-4 flex flex-wrap items-center justify-between gap-3">
80 <div class="min-w-0">
81 <div class="text-sm font-medium text-gray-200">{{ key.title }}</div>
82 <div class="text-xs text-gray-500 font-mono mt-1 truncate">{{ key.fingerprint }}</div>
83 <div class="text-xs text-gray-500 mt-1">
84 {{ key.key_type|upper }} &middot; Added {{ key.created_at|timesince }} ago
85 {% if key.last_used_at %}&middot; Last used {{ key.last_used_at|timesince }} ago{% endif %}
86 </div>
87 </div>
@@ -132,15 +132,15 @@
132 </a>
133 </div>
134 {% if tokens %}
135 <div class="divide-y divide-gray-700">
136 {% for token in tokens %}
137 <div class="p-4 flex flex-wrap items-center justify-between gap-3">
138 <div class="min-w-0">
139 <div class="text-sm font-medium text-gray-200">{{ token.name }}</div>
140 <div class="text-xs text-gray-500 font-mono mt-1 truncate">{{ token.token_prefix }}...</div>
141 <div class="text-xs text-gray-500 mt-1 break-words">
142 Scopes: {{ token.scopes }} &middot; Created {{ token.created_at|timesince }} ago
143 {% if token.last_used_at %}&middot; Last used {{ token.last_used_at|timesince }} ago{% endif %}
144 {% if token.expires_at %}&middot; Expires {{ token.expires_at|date:"M j, Y" }}{% endif %}
145 </div>
146 </div>
147
--- templates/base.html
+++ templates/base.html
@@ -45,10 +45,13 @@
4545
focus:border-brand focus:ring-brand sm:text-sm;
4646
}
4747
}
4848
</style>
4949
<style>
50
+ /* Hide scrollbar on horizontal-scroll navs (tabs, filter pills) */
51
+ .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
52
+ .scrollbar-hide::-webkit-scrollbar { display: none; }
5053
/* Focus visible outlines for keyboard navigation */
5154
a:focus-visible, button:focus-visible, [role="button"]:focus-visible {
5255
outline: 2px solid #DC394C;
5356
outline-offset: 2px;
5457
border-radius: 4px;
5558
--- templates/base.html
+++ templates/base.html
@@ -45,10 +45,13 @@
45 focus:border-brand focus:ring-brand sm:text-sm;
46 }
47 }
48 </style>
49 <style>
 
 
 
50 /* Focus visible outlines for keyboard navigation */
51 a:focus-visible, button:focus-visible, [role="button"]:focus-visible {
52 outline: 2px solid #DC394C;
53 outline-offset: 2px;
54 border-radius: 4px;
55
--- templates/base.html
+++ templates/base.html
@@ -45,10 +45,13 @@
45 focus:border-brand focus:ring-brand sm:text-sm;
46 }
47 }
48 </style>
49 <style>
50 /* Hide scrollbar on horizontal-scroll navs (tabs, filter pills) */
51 .scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
52 .scrollbar-hide::-webkit-scrollbar { display: none; }
53 /* Focus visible outlines for keyboard navigation */
54 a:focus-visible, button:focus-visible, [role="button"]:focus-visible {
55 outline: 2px solid #DC394C;
56 outline-offset: 2px;
57 border-radius: 4px;
58
--- templates/dashboard.html
+++ templates/dashboard.html
@@ -75,11 +75,11 @@
7575
<div class="w-2.5 h-2.5 rounded-full bg-brand"></div>
7676
</div>
7777
<div class="flex-1 min-w-0">
7878
<a href="{% url 'fossil:checkin_detail' slug=item.project.slug checkin_uuid=item.entry.uuid %}"
7979
class="text-sm text-gray-200 hover:text-brand-light">{{ item.entry.comment|truncatechars:70 }}</a>
80
- <div class="mt-0.5 flex items-center gap-3 text-xs text-gray-500">
80
+ <div class="mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-gray-500">
8181
<a href="{% url 'projects:detail' slug=item.project.slug %}" class="text-brand-light hover:text-brand">{{ item.project.name }}</a>
8282
<a href="{% url 'fossil:user_activity' slug=item.project.slug username=item.entry.user %}" class="hover:text-gray-300">{{ item.entry.user }}</a>
8383
<a href="{% url 'fossil:checkin_detail' slug=item.project.slug checkin_uuid=item.entry.uuid %}" class="font-mono text-brand-light hover:text-brand">{{ item.entry.uuid|truncatechars:10 }}</a>
8484
<span>{{ item.entry.timestamp|timesince }} ago</span>
8585
</div>
8686
--- templates/dashboard.html
+++ templates/dashboard.html
@@ -75,11 +75,11 @@
75 <div class="w-2.5 h-2.5 rounded-full bg-brand"></div>
76 </div>
77 <div class="flex-1 min-w-0">
78 <a href="{% url 'fossil:checkin_detail' slug=item.project.slug checkin_uuid=item.entry.uuid %}"
79 class="text-sm text-gray-200 hover:text-brand-light">{{ item.entry.comment|truncatechars:70 }}</a>
80 <div class="mt-0.5 flex items-center gap-3 text-xs text-gray-500">
81 <a href="{% url 'projects:detail' slug=item.project.slug %}" class="text-brand-light hover:text-brand">{{ item.project.name }}</a>
82 <a href="{% url 'fossil:user_activity' slug=item.project.slug username=item.entry.user %}" class="hover:text-gray-300">{{ item.entry.user }}</a>
83 <a href="{% url 'fossil:checkin_detail' slug=item.project.slug checkin_uuid=item.entry.uuid %}" class="font-mono text-brand-light hover:text-brand">{{ item.entry.uuid|truncatechars:10 }}</a>
84 <span>{{ item.entry.timestamp|timesince }} ago</span>
85 </div>
86
--- templates/dashboard.html
+++ templates/dashboard.html
@@ -75,11 +75,11 @@
75 <div class="w-2.5 h-2.5 rounded-full bg-brand"></div>
76 </div>
77 <div class="flex-1 min-w-0">
78 <a href="{% url 'fossil:checkin_detail' slug=item.project.slug checkin_uuid=item.entry.uuid %}"
79 class="text-sm text-gray-200 hover:text-brand-light">{{ item.entry.comment|truncatechars:70 }}</a>
80 <div class="mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-gray-500">
81 <a href="{% url 'projects:detail' slug=item.project.slug %}" class="text-brand-light hover:text-brand">{{ item.project.name }}</a>
82 <a href="{% url 'fossil:user_activity' slug=item.project.slug username=item.entry.user %}" class="hover:text-gray-300">{{ item.entry.user }}</a>
83 <a href="{% url 'fossil:checkin_detail' slug=item.project.slug checkin_uuid=item.entry.uuid %}" class="font-mono text-brand-light hover:text-brand">{{ item.entry.uuid|truncatechars:10 }}</a>
84 <span>{{ item.entry.timestamp|timesince }} ago</span>
85 </div>
86
--- templates/fossil/_project_nav.html
+++ templates/fossil/_project_nav.html
@@ -1,52 +1,52 @@
1
-<nav aria-label="Project sections" class="flex space-x-1 border-b border-gray-700 mb-6 overflow-x-auto">
1
+<nav aria-label="Project sections" class="flex space-x-1 border-b border-gray-700 mb-6 overflow-x-auto scrollbar-hide">
22
<a href="{% url 'projects:detail' slug=project.slug %}"
3
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'overview' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
3
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'overview' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
44
Overview
55
</a>
66
<a href="{% url 'fossil:code' slug=project.slug %}"
7
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'code' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
7
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'code' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
88
Code
99
</a>
1010
<a href="{% url 'fossil:branches' slug=project.slug %}"
11
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'branches' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
11
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'branches' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
1212
Branches
1313
</a>
1414
<a href="{% url 'fossil:timeline' slug=project.slug %}"
15
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'timeline' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
15
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'timeline' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
1616
Timeline
1717
</a>
1818
<a href="{% url 'fossil:tickets' slug=project.slug %}"
19
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'tickets' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
19
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'tickets' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
2020
Tickets
2121
</a>
2222
<a href="{% url 'fossil:wiki' slug=project.slug %}"
23
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'wiki' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
23
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'wiki' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
2424
Wiki
2525
</a>
2626
<a href="{% url 'fossil:forum' slug=project.slug %}"
27
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'forum' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
27
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'forum' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
2828
Forum
2929
</a>
3030
<a href="{% url 'fossil:releases' slug=project.slug %}"
31
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'releases' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
31
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'releases' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
3232
Releases
3333
</a>
3434
<a href="{% url 'fossil:unversioned' slug=project.slug %}"
35
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'files' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
35
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'files' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
3636
Files
3737
</a>
3838
{% if perms.projects.change_project %}
3939
<a href="{% url 'fossil:sync' slug=project.slug %}"
40
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'sync' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
40
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'sync' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
4141
{% if fossil_repo.remote_url %}Sync{% else %}Setup Sync{% endif %}
4242
</a>
4343
<a href="{% url 'fossil:repo_settings' slug=project.slug %}"
44
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'settings' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
44
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'settings' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
4545
Settings
4646
</a>
4747
<a href="{% url 'fossil:explorer' slug=project.slug %}"
48
- class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'explorer' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
48
+ class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'explorer' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
4949
Explorer
5050
</a>
5151
{% endif %}
5252
</nav>
5353
--- templates/fossil/_project_nav.html
+++ templates/fossil/_project_nav.html
@@ -1,52 +1,52 @@
1 <nav aria-label="Project sections" class="flex space-x-1 border-b border-gray-700 mb-6 overflow-x-auto">
2 <a href="{% url 'projects:detail' slug=project.slug %}"
3 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'overview' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
4 Overview
5 </a>
6 <a href="{% url 'fossil:code' slug=project.slug %}"
7 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'code' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
8 Code
9 </a>
10 <a href="{% url 'fossil:branches' slug=project.slug %}"
11 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'branches' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
12 Branches
13 </a>
14 <a href="{% url 'fossil:timeline' slug=project.slug %}"
15 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'timeline' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
16 Timeline
17 </a>
18 <a href="{% url 'fossil:tickets' slug=project.slug %}"
19 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'tickets' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
20 Tickets
21 </a>
22 <a href="{% url 'fossil:wiki' slug=project.slug %}"
23 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'wiki' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
24 Wiki
25 </a>
26 <a href="{% url 'fossil:forum' slug=project.slug %}"
27 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'forum' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
28 Forum
29 </a>
30 <a href="{% url 'fossil:releases' slug=project.slug %}"
31 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'releases' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
32 Releases
33 </a>
34 <a href="{% url 'fossil:unversioned' slug=project.slug %}"
35 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'files' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
36 Files
37 </a>
38 {% if perms.projects.change_project %}
39 <a href="{% url 'fossil:sync' slug=project.slug %}"
40 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'sync' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
41 {% if fossil_repo.remote_url %}Sync{% else %}Setup Sync{% endif %}
42 </a>
43 <a href="{% url 'fossil:repo_settings' slug=project.slug %}"
44 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'settings' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
45 Settings
46 </a>
47 <a href="{% url 'fossil:explorer' slug=project.slug %}"
48 class="px-4 py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'explorer' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
49 Explorer
50 </a>
51 {% endif %}
52 </nav>
53
--- templates/fossil/_project_nav.html
+++ templates/fossil/_project_nav.html
@@ -1,52 +1,52 @@
1 <nav aria-label="Project sections" class="flex space-x-1 border-b border-gray-700 mb-6 overflow-x-auto scrollbar-hide">
2 <a href="{% url 'projects:detail' slug=project.slug %}"
3 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'overview' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
4 Overview
5 </a>
6 <a href="{% url 'fossil:code' slug=project.slug %}"
7 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'code' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
8 Code
9 </a>
10 <a href="{% url 'fossil:branches' slug=project.slug %}"
11 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'branches' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
12 Branches
13 </a>
14 <a href="{% url 'fossil:timeline' slug=project.slug %}"
15 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'timeline' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
16 Timeline
17 </a>
18 <a href="{% url 'fossil:tickets' slug=project.slug %}"
19 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'tickets' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
20 Tickets
21 </a>
22 <a href="{% url 'fossil:wiki' slug=project.slug %}"
23 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'wiki' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
24 Wiki
25 </a>
26 <a href="{% url 'fossil:forum' slug=project.slug %}"
27 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'forum' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
28 Forum
29 </a>
30 <a href="{% url 'fossil:releases' slug=project.slug %}"
31 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'releases' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
32 Releases
33 </a>
34 <a href="{% url 'fossil:unversioned' slug=project.slug %}"
35 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'files' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
36 Files
37 </a>
38 {% if perms.projects.change_project %}
39 <a href="{% url 'fossil:sync' slug=project.slug %}"
40 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'sync' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
41 {% if fossil_repo.remote_url %}Sync{% else %}Setup Sync{% endif %}
42 </a>
43 <a href="{% url 'fossil:repo_settings' slug=project.slug %}"
44 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'settings' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
45 Settings
46 </a>
47 <a href="{% url 'fossil:explorer' slug=project.slug %}"
48 class="px-3 py-2.5 sm:px-4 sm:py-2 text-sm font-medium rounded-t-md whitespace-nowrap {% if active_tab == 'explorer' %}bg-gray-800 text-gray-100 border-b-2 border-brand{% else %}text-gray-400 hover:text-gray-200 hover:bg-gray-800/50{% endif %}">
49 Explorer
50 </a>
51 {% endif %}
52 </nav>
53
--- templates/fossil/branch_list.html
+++ templates/fossil/branch_list.html
@@ -25,11 +25,11 @@
2525
</span>
2626
</div>
2727
</div>
2828
2929
<div id="branch-content">
30
-<div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
30
+<div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm overflow-x-auto">
3131
<table class="min-w-full divide-y divide-gray-700">
3232
<thead class="bg-gray-900">
3333
<tr>
3434
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Branch</th>
3535
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Last Checkin</th>
3636
--- templates/fossil/branch_list.html
+++ templates/fossil/branch_list.html
@@ -25,11 +25,11 @@
25 </span>
26 </div>
27 </div>
28
29 <div id="branch-content">
30 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
31 <table class="min-w-full divide-y divide-gray-700">
32 <thead class="bg-gray-900">
33 <tr>
34 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Branch</th>
35 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Last Checkin</th>
36
--- templates/fossil/branch_list.html
+++ templates/fossil/branch_list.html
@@ -25,11 +25,11 @@
25 </span>
26 </div>
27 </div>
28
29 <div id="branch-content">
30 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm overflow-x-auto">
31 <table class="min-w-full divide-y divide-gray-700">
32 <thead class="bg-gray-900">
33 <tr>
34 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Branch</th>
35 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Last Checkin</th>
36
--- templates/fossil/checkin_detail.html
+++ templates/fossil/checkin_detail.html
@@ -18,13 +18,15 @@
1818
.diff-gutter a { color: inherit; text-decoration: none; display: block; }
1919
.line-row:target { background: rgba(220, 57, 76, 0.15) !important; }
2020
.line-row:target .diff-gutter { color: #DC394C; font-weight: 600; }
2121
.line-row { scroll-margin-top: 40vh; }
2222
/* Split diff view */
23
- .split-diff { display: grid; grid-template-columns: 1fr 1fr; }
23
+ .split-diff { display: grid; grid-template-columns: 1fr; }
24
+ @media (min-width: 768px) { .split-diff { grid-template-columns: 1fr 1fr; } }
2425
.split-diff-side { overflow-x: auto; }
25
- .split-diff-side:first-child { border-right: 1px solid #374151; }
26
+ @media (min-width: 768px) { .split-diff-side:first-child { border-right: 1px solid #374151; } }
27
+ @media (max-width: 767px) { .split-diff-side:first-child { border-bottom: 1px solid #374151; } }
2628
.split-diff-side .diff-table td:last-child { width: 100%; }
2729
.split-line-add { background: rgba(34, 197, 94, 0.1); }
2830
.split-line-add td:last-child { color: #86efac; }
2931
.split-line-del { background: rgba(239, 68, 68, 0.1); }
3032
.split-line-del td:last-child { color: #fca5a5; }
@@ -57,11 +59,11 @@
5759
<div class="space-y-4">
5860
<!-- Commit header -->
5961
<div class="rounded-lg bg-gray-800 border border-gray-700">
6062
<div class="px-6 py-5">
6163
<p class="text-lg text-gray-100 leading-relaxed">{{ checkin.comment }}</p>
62
- <div class="mt-3 flex items-center gap-4 flex-wrap text-sm">
64
+ <div class="mt-3 flex items-center gap-x-4 gap-y-1 flex-wrap text-sm">
6365
<a href="{% url 'fossil:user_activity' slug=project.slug username=checkin.user %}" class="font-medium text-gray-200 hover:text-brand-light">{{ checkin.user|display_user }}</a>
6466
<span class="text-gray-500">{{ checkin.timestamp|date:"Y-m-d H:i" }}</span>
6567
{% if checkin.branch %}
6668
<span class="inline-flex items-center rounded-md bg-brand/10 border border-brand/20 px-2 py-0.5 text-xs text-brand-light">
6769
{{ checkin.branch }}
@@ -76,11 +78,11 @@
7678
<div class="px-6 py-3 border-t border-gray-700 bg-gray-800/50">
7779
<div class="flex items-center gap-2 mb-2">
7880
<span class="text-xs font-medium text-gray-400">CI Status</span>
7981
<img src="{% url 'fossil:status_badge' slug=project.slug checkin_uuid=checkin.uuid %}" alt="CI Status" class="h-5">
8082
</div>
81
- <div class="flex flex-wrap gap-2">
83
+ <div class="flex flex-wrap gap-x-2 gap-y-1.5">
8284
{% for check in status_checks %}
8385
<a {% if check.target_url and check.target_url|slice:":4" == "http" %}href="{{ check.target_url }}" target="_blank" rel="noopener"{% endif %}
8486
class="inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs
8587
{% if check.state == 'success' %}border-green-800 bg-green-900/30 text-green-300
8688
{% elif check.state == 'failure' %}border-red-800 bg-red-900/30 text-red-300
@@ -104,11 +106,11 @@
104106
</a>
105107
{% endfor %}
106108
</div>
107109
</div>
108110
{% endif %}
109
- <div class="px-6 py-3 border-t border-gray-700 bg-gray-800/50 flex items-center gap-6 flex-wrap text-xs">
111
+ <div class="px-6 py-3 border-t border-gray-700 bg-gray-800/50 flex items-center gap-x-6 gap-y-2 flex-wrap text-xs">
110112
<div class="flex items-center gap-2">
111113
<span class="text-gray-500">Commit</span>
112114
<code class="font-mono text-gray-300 break-all">{{ checkin.uuid }}</code>
113115
</div>
114116
{% if checkin.parent_uuid %}
@@ -135,13 +137,13 @@
135137
<span class="text-red-400">-{{ fd.deletions }}</span>
136138
{% endif %}
137139
{% endfor %}
138140
{% endwith %}
139141
</div>
140
- <div class="mt-2 flex flex-wrap gap-2">
142
+ <div class="mt-2 flex flex-wrap gap-x-2 gap-y-1">
141143
{% for fd in file_diffs %}
142
- <a href="#diff-{{ forloop.counter }}" class="text-xs font-mono text-brand-light hover:text-brand">
144
+ <a href="#diff-{{ forloop.counter }}" class="text-xs font-mono text-brand-light hover:text-brand break-all">
143145
{% if fd.change_type == "added" %}
144146
<span class="text-green-400">+</span>
145147
{% elif fd.change_type == "deleted" %}
146148
<span class="text-red-400">-</span>
147149
{% else %}
148150
--- templates/fossil/checkin_detail.html
+++ templates/fossil/checkin_detail.html
@@ -18,13 +18,15 @@
18 .diff-gutter a { color: inherit; text-decoration: none; display: block; }
19 .line-row:target { background: rgba(220, 57, 76, 0.15) !important; }
20 .line-row:target .diff-gutter { color: #DC394C; font-weight: 600; }
21 .line-row { scroll-margin-top: 40vh; }
22 /* Split diff view */
23 .split-diff { display: grid; grid-template-columns: 1fr 1fr; }
 
24 .split-diff-side { overflow-x: auto; }
25 .split-diff-side:first-child { border-right: 1px solid #374151; }
 
26 .split-diff-side .diff-table td:last-child { width: 100%; }
27 .split-line-add { background: rgba(34, 197, 94, 0.1); }
28 .split-line-add td:last-child { color: #86efac; }
29 .split-line-del { background: rgba(239, 68, 68, 0.1); }
30 .split-line-del td:last-child { color: #fca5a5; }
@@ -57,11 +59,11 @@
57 <div class="space-y-4">
58 <!-- Commit header -->
59 <div class="rounded-lg bg-gray-800 border border-gray-700">
60 <div class="px-6 py-5">
61 <p class="text-lg text-gray-100 leading-relaxed">{{ checkin.comment }}</p>
62 <div class="mt-3 flex items-center gap-4 flex-wrap text-sm">
63 <a href="{% url 'fossil:user_activity' slug=project.slug username=checkin.user %}" class="font-medium text-gray-200 hover:text-brand-light">{{ checkin.user|display_user }}</a>
64 <span class="text-gray-500">{{ checkin.timestamp|date:"Y-m-d H:i" }}</span>
65 {% if checkin.branch %}
66 <span class="inline-flex items-center rounded-md bg-brand/10 border border-brand/20 px-2 py-0.5 text-xs text-brand-light">
67 {{ checkin.branch }}
@@ -76,11 +78,11 @@
76 <div class="px-6 py-3 border-t border-gray-700 bg-gray-800/50">
77 <div class="flex items-center gap-2 mb-2">
78 <span class="text-xs font-medium text-gray-400">CI Status</span>
79 <img src="{% url 'fossil:status_badge' slug=project.slug checkin_uuid=checkin.uuid %}" alt="CI Status" class="h-5">
80 </div>
81 <div class="flex flex-wrap gap-2">
82 {% for check in status_checks %}
83 <a {% if check.target_url and check.target_url|slice:":4" == "http" %}href="{{ check.target_url }}" target="_blank" rel="noopener"{% endif %}
84 class="inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs
85 {% if check.state == 'success' %}border-green-800 bg-green-900/30 text-green-300
86 {% elif check.state == 'failure' %}border-red-800 bg-red-900/30 text-red-300
@@ -104,11 +106,11 @@
104 </a>
105 {% endfor %}
106 </div>
107 </div>
108 {% endif %}
109 <div class="px-6 py-3 border-t border-gray-700 bg-gray-800/50 flex items-center gap-6 flex-wrap text-xs">
110 <div class="flex items-center gap-2">
111 <span class="text-gray-500">Commit</span>
112 <code class="font-mono text-gray-300 break-all">{{ checkin.uuid }}</code>
113 </div>
114 {% if checkin.parent_uuid %}
@@ -135,13 +137,13 @@
135 <span class="text-red-400">-{{ fd.deletions }}</span>
136 {% endif %}
137 {% endfor %}
138 {% endwith %}
139 </div>
140 <div class="mt-2 flex flex-wrap gap-2">
141 {% for fd in file_diffs %}
142 <a href="#diff-{{ forloop.counter }}" class="text-xs font-mono text-brand-light hover:text-brand">
143 {% if fd.change_type == "added" %}
144 <span class="text-green-400">+</span>
145 {% elif fd.change_type == "deleted" %}
146 <span class="text-red-400">-</span>
147 {% else %}
148
--- templates/fossil/checkin_detail.html
+++ templates/fossil/checkin_detail.html
@@ -18,13 +18,15 @@
18 .diff-gutter a { color: inherit; text-decoration: none; display: block; }
19 .line-row:target { background: rgba(220, 57, 76, 0.15) !important; }
20 .line-row:target .diff-gutter { color: #DC394C; font-weight: 600; }
21 .line-row { scroll-margin-top: 40vh; }
22 /* Split diff view */
23 .split-diff { display: grid; grid-template-columns: 1fr; }
24 @media (min-width: 768px) { .split-diff { grid-template-columns: 1fr 1fr; } }
25 .split-diff-side { overflow-x: auto; }
26 @media (min-width: 768px) { .split-diff-side:first-child { border-right: 1px solid #374151; } }
27 @media (max-width: 767px) { .split-diff-side:first-child { border-bottom: 1px solid #374151; } }
28 .split-diff-side .diff-table td:last-child { width: 100%; }
29 .split-line-add { background: rgba(34, 197, 94, 0.1); }
30 .split-line-add td:last-child { color: #86efac; }
31 .split-line-del { background: rgba(239, 68, 68, 0.1); }
32 .split-line-del td:last-child { color: #fca5a5; }
@@ -57,11 +59,11 @@
59 <div class="space-y-4">
60 <!-- Commit header -->
61 <div class="rounded-lg bg-gray-800 border border-gray-700">
62 <div class="px-6 py-5">
63 <p class="text-lg text-gray-100 leading-relaxed">{{ checkin.comment }}</p>
64 <div class="mt-3 flex items-center gap-x-4 gap-y-1 flex-wrap text-sm">
65 <a href="{% url 'fossil:user_activity' slug=project.slug username=checkin.user %}" class="font-medium text-gray-200 hover:text-brand-light">{{ checkin.user|display_user }}</a>
66 <span class="text-gray-500">{{ checkin.timestamp|date:"Y-m-d H:i" }}</span>
67 {% if checkin.branch %}
68 <span class="inline-flex items-center rounded-md bg-brand/10 border border-brand/20 px-2 py-0.5 text-xs text-brand-light">
69 {{ checkin.branch }}
@@ -76,11 +78,11 @@
78 <div class="px-6 py-3 border-t border-gray-700 bg-gray-800/50">
79 <div class="flex items-center gap-2 mb-2">
80 <span class="text-xs font-medium text-gray-400">CI Status</span>
81 <img src="{% url 'fossil:status_badge' slug=project.slug checkin_uuid=checkin.uuid %}" alt="CI Status" class="h-5">
82 </div>
83 <div class="flex flex-wrap gap-x-2 gap-y-1.5">
84 {% for check in status_checks %}
85 <a {% if check.target_url and check.target_url|slice:":4" == "http" %}href="{{ check.target_url }}" target="_blank" rel="noopener"{% endif %}
86 class="inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs
87 {% if check.state == 'success' %}border-green-800 bg-green-900/30 text-green-300
88 {% elif check.state == 'failure' %}border-red-800 bg-red-900/30 text-red-300
@@ -104,11 +106,11 @@
106 </a>
107 {% endfor %}
108 </div>
109 </div>
110 {% endif %}
111 <div class="px-6 py-3 border-t border-gray-700 bg-gray-800/50 flex items-center gap-x-6 gap-y-2 flex-wrap text-xs">
112 <div class="flex items-center gap-2">
113 <span class="text-gray-500">Commit</span>
114 <code class="font-mono text-gray-300 break-all">{{ checkin.uuid }}</code>
115 </div>
116 {% if checkin.parent_uuid %}
@@ -135,13 +137,13 @@
137 <span class="text-red-400">-{{ fd.deletions }}</span>
138 {% endif %}
139 {% endfor %}
140 {% endwith %}
141 </div>
142 <div class="mt-2 flex flex-wrap gap-x-2 gap-y-1">
143 {% for fd in file_diffs %}
144 <a href="#diff-{{ forloop.counter }}" class="text-xs font-mono text-brand-light hover:text-brand break-all">
145 {% if fd.change_type == "added" %}
146 <span class="text-green-400">+</span>
147 {% elif fd.change_type == "deleted" %}
148 <span class="text-red-400">-</span>
149 {% else %}
150
--- templates/fossil/code_browser.html
+++ templates/fossil/code_browser.html
@@ -33,11 +33,11 @@
3333
{% endif %}
3434
</div>
3535
3636
<!-- Latest commit info -->
3737
{% if latest_commit %}
38
- <div class="flex items-center gap-3 mt-2 text-xs text-gray-500">
38
+ <div class="flex flex-wrap items-center gap-x-3 gap-y-1 mt-2 text-xs text-gray-500">
3939
<a href="{% url 'fossil:user_activity' slug=project.slug username=latest_commit.user %}" class="font-medium text-gray-300 hover:text-brand-light">{{ latest_commit.user|display_user }}</a>
4040
<a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=latest_commit.uuid %}" class="text-gray-400 truncate hover:text-brand-light">{{ latest_commit.comment|truncatechars:80 }}</a>
4141
<a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=latest_commit.uuid %}" class="font-mono text-brand-light hover:text-brand">{{ latest_commit.uuid|truncatechars:10 }}</a>
4242
<span>{{ latest_commit.timestamp|date:"Y-m-d H:i" }}</span>
4343
</div>
4444
--- templates/fossil/code_browser.html
+++ templates/fossil/code_browser.html
@@ -33,11 +33,11 @@
33 {% endif %}
34 </div>
35
36 <!-- Latest commit info -->
37 {% if latest_commit %}
38 <div class="flex items-center gap-3 mt-2 text-xs text-gray-500">
39 <a href="{% url 'fossil:user_activity' slug=project.slug username=latest_commit.user %}" class="font-medium text-gray-300 hover:text-brand-light">{{ latest_commit.user|display_user }}</a>
40 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=latest_commit.uuid %}" class="text-gray-400 truncate hover:text-brand-light">{{ latest_commit.comment|truncatechars:80 }}</a>
41 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=latest_commit.uuid %}" class="font-mono text-brand-light hover:text-brand">{{ latest_commit.uuid|truncatechars:10 }}</a>
42 <span>{{ latest_commit.timestamp|date:"Y-m-d H:i" }}</span>
43 </div>
44
--- templates/fossil/code_browser.html
+++ templates/fossil/code_browser.html
@@ -33,11 +33,11 @@
33 {% endif %}
34 </div>
35
36 <!-- Latest commit info -->
37 {% if latest_commit %}
38 <div class="flex flex-wrap items-center gap-x-3 gap-y-1 mt-2 text-xs text-gray-500">
39 <a href="{% url 'fossil:user_activity' slug=project.slug username=latest_commit.user %}" class="font-medium text-gray-300 hover:text-brand-light">{{ latest_commit.user|display_user }}</a>
40 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=latest_commit.uuid %}" class="text-gray-400 truncate hover:text-brand-light">{{ latest_commit.comment|truncatechars:80 }}</a>
41 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=latest_commit.uuid %}" class="font-mono text-brand-light hover:text-brand">{{ latest_commit.uuid|truncatechars:10 }}</a>
42 <span>{{ latest_commit.timestamp|date:"Y-m-d H:i" }}</span>
43 </div>
44
--- templates/fossil/code_file.html
+++ templates/fossil/code_file.html
@@ -43,12 +43,12 @@
4343
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
4444
{% include "fossil/_project_nav.html" %}
4545
4646
<div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700">
4747
<!-- File path breadcrumb + stats -->
48
- <div class="px-4 py-3 border-b border-gray-700 flex flex-wrap items-center justify-between gap-2">
49
- <div class="flex items-center gap-1 text-sm font-mono">
48
+ <div class="px-4 py-3 border-b border-gray-700 flex flex-wrap items-center justify-between gap-x-2 gap-y-2">
49
+ <div class="flex flex-wrap items-center gap-1 text-sm font-mono min-w-0">
5050
<a href="{% url 'fossil:code' slug=project.slug %}" class="text-brand-light hover:text-brand">{{ project.slug }}</a>
5151
{% for crumb in file_breadcrumbs %}
5252
<span class="text-gray-600">/</span>
5353
{% if forloop.last %}
5454
<span class="text-gray-200">{{ crumb.name }}</span>
@@ -55,11 +55,11 @@
5555
{% else %}
5656
<a href="{% url 'fossil:code_dir' slug=project.slug dirpath=crumb.path %}" class="text-brand-light hover:text-brand">{{ crumb.name }}</a>
5757
{% endif %}
5858
{% endfor %}
5959
</div>
60
- <div class="flex items-center gap-3">
60
+ <div class="flex flex-wrap items-center gap-2">
6161
{% if can_render %}
6262
<div class="flex items-center gap-1 text-xs">
6363
<a href="?mode=source" class="px-2 py-1 rounded {% if view_mode == 'source' %}bg-brand text-white{% else %}text-gray-500 hover:text-white{% endif %}">Source</a>
6464
<a href="?mode=rendered" class="px-2 py-1 rounded {% if view_mode == 'rendered' %}bg-brand text-white{% else %}text-gray-500 hover:text-white{% endif %}">Rendered</a>
6565
</div>
6666
--- templates/fossil/code_file.html
+++ templates/fossil/code_file.html
@@ -43,12 +43,12 @@
43 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
44 {% include "fossil/_project_nav.html" %}
45
46 <div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700">
47 <!-- File path breadcrumb + stats -->
48 <div class="px-4 py-3 border-b border-gray-700 flex flex-wrap items-center justify-between gap-2">
49 <div class="flex items-center gap-1 text-sm font-mono">
50 <a href="{% url 'fossil:code' slug=project.slug %}" class="text-brand-light hover:text-brand">{{ project.slug }}</a>
51 {% for crumb in file_breadcrumbs %}
52 <span class="text-gray-600">/</span>
53 {% if forloop.last %}
54 <span class="text-gray-200">{{ crumb.name }}</span>
@@ -55,11 +55,11 @@
55 {% else %}
56 <a href="{% url 'fossil:code_dir' slug=project.slug dirpath=crumb.path %}" class="text-brand-light hover:text-brand">{{ crumb.name }}</a>
57 {% endif %}
58 {% endfor %}
59 </div>
60 <div class="flex items-center gap-3">
61 {% if can_render %}
62 <div class="flex items-center gap-1 text-xs">
63 <a href="?mode=source" class="px-2 py-1 rounded {% if view_mode == 'source' %}bg-brand text-white{% else %}text-gray-500 hover:text-white{% endif %}">Source</a>
64 <a href="?mode=rendered" class="px-2 py-1 rounded {% if view_mode == 'rendered' %}bg-brand text-white{% else %}text-gray-500 hover:text-white{% endif %}">Rendered</a>
65 </div>
66
--- templates/fossil/code_file.html
+++ templates/fossil/code_file.html
@@ -43,12 +43,12 @@
43 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
44 {% include "fossil/_project_nav.html" %}
45
46 <div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700">
47 <!-- File path breadcrumb + stats -->
48 <div class="px-4 py-3 border-b border-gray-700 flex flex-wrap items-center justify-between gap-x-2 gap-y-2">
49 <div class="flex flex-wrap items-center gap-1 text-sm font-mono min-w-0">
50 <a href="{% url 'fossil:code' slug=project.slug %}" class="text-brand-light hover:text-brand">{{ project.slug }}</a>
51 {% for crumb in file_breadcrumbs %}
52 <span class="text-gray-600">/</span>
53 {% if forloop.last %}
54 <span class="text-gray-200">{{ crumb.name }}</span>
@@ -55,11 +55,11 @@
55 {% else %}
56 <a href="{% url 'fossil:code_dir' slug=project.slug dirpath=crumb.path %}" class="text-brand-light hover:text-brand">{{ crumb.name }}</a>
57 {% endif %}
58 {% endfor %}
59 </div>
60 <div class="flex flex-wrap items-center gap-2">
61 {% if can_render %}
62 <div class="flex items-center gap-1 text-xs">
63 <a href="?mode=source" class="px-2 py-1 rounded {% if view_mode == 'source' %}bg-brand text-white{% else %}text-gray-500 hover:text-white{% endif %}">Source</a>
64 <a href="?mode=rendered" class="px-2 py-1 rounded {% if view_mode == 'rendered' %}bg-brand text-white{% else %}text-gray-500 hover:text-white{% endif %}">Rendered</a>
65 </div>
66
--- templates/fossil/compare.html
+++ templates/fossil/compare.html
@@ -13,13 +13,15 @@
1313
.diff-line-hunk { background: rgba(96, 165, 250, 0.08); }
1414
.diff-line-hunk td { color: #93c5fd; }
1515
.diff-line-header td { color: #6b7280; }
1616
.diff-gutter { width: 1%; user-select: none; color: #4b5563; text-align: right; padding: 0 6px; border-right: 1px solid #374151; white-space: nowrap; }
1717
/* Split diff view */
18
- .split-diff { display: grid; grid-template-columns: 1fr 1fr; }
18
+ .split-diff { display: grid; grid-template-columns: 1fr; }
19
+ @media (min-width: 768px) { .split-diff { grid-template-columns: 1fr 1fr; } }
1920
.split-diff-side { overflow-x: auto; }
20
- .split-diff-side:first-child { border-right: 1px solid #374151; }
21
+ @media (min-width: 768px) { .split-diff-side:first-child { border-right: 1px solid #374151; } }
22
+ @media (max-width: 767px) { .split-diff-side:first-child { border-bottom: 1px solid #374151; } }
2123
.split-diff-side .diff-table td:last-child { width: 100%; }
2224
.split-line-add { background: rgba(34, 197, 94, 0.1); }
2325
.split-line-add td:last-child { color: #86efac; }
2426
.split-line-del { background: rgba(239, 68, 68, 0.1); }
2527
.split-line-del td:last-child { color: #fca5a5; }
@@ -35,11 +37,11 @@
3537
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
3638
{% include "fossil/_project_nav.html" %}
3739
3840
<div class="mb-6">
3941
<h2 class="text-lg font-semibold text-gray-200 mb-3">Compare Checkins</h2>
40
- <form method="get" class="flex items-end gap-3">
42
+ <form method="get" class="flex flex-col sm:flex-row sm:items-end gap-3">
4143
<div class="flex-1">
4244
<label class="block text-xs text-gray-500 mb-1">From (older)</label>
4345
<input type="text" name="from" value="{{ from_uuid }}" placeholder="Checkin hash..."
4446
aria-label="From checkin hash"
4547
class="w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 text-sm px-3 py-2 font-mono focus:border-brand focus:ring-brand">
@@ -53,11 +55,11 @@
5355
<button type="submit" class="rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white hover:bg-brand-hover">Compare</button>
5456
</form>
5557
</div>
5658
5759
{% if from_detail and to_detail %}
58
-<div class="grid grid-cols-2 gap-4 mb-6">
60
+<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6">
5961
<div class="rounded-lg bg-gray-800 border border-gray-700 p-4">
6062
<div class="text-xs text-gray-500 mb-1">From</div>
6163
<a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=from_detail.uuid %}" class="text-sm text-brand-light hover:text-brand">{{ from_detail.comment|truncatechars:60 }}</a>
6264
<div class="mt-1 text-xs text-gray-500">{{ from_detail.user|display_user }} &middot; {{ from_detail.timestamp|date:"Y-m-d H:i" }}</div>
6365
</div>
6466
--- templates/fossil/compare.html
+++ templates/fossil/compare.html
@@ -13,13 +13,15 @@
13 .diff-line-hunk { background: rgba(96, 165, 250, 0.08); }
14 .diff-line-hunk td { color: #93c5fd; }
15 .diff-line-header td { color: #6b7280; }
16 .diff-gutter { width: 1%; user-select: none; color: #4b5563; text-align: right; padding: 0 6px; border-right: 1px solid #374151; white-space: nowrap; }
17 /* Split diff view */
18 .split-diff { display: grid; grid-template-columns: 1fr 1fr; }
 
19 .split-diff-side { overflow-x: auto; }
20 .split-diff-side:first-child { border-right: 1px solid #374151; }
 
21 .split-diff-side .diff-table td:last-child { width: 100%; }
22 .split-line-add { background: rgba(34, 197, 94, 0.1); }
23 .split-line-add td:last-child { color: #86efac; }
24 .split-line-del { background: rgba(239, 68, 68, 0.1); }
25 .split-line-del td:last-child { color: #fca5a5; }
@@ -35,11 +37,11 @@
35 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
36 {% include "fossil/_project_nav.html" %}
37
38 <div class="mb-6">
39 <h2 class="text-lg font-semibold text-gray-200 mb-3">Compare Checkins</h2>
40 <form method="get" class="flex items-end gap-3">
41 <div class="flex-1">
42 <label class="block text-xs text-gray-500 mb-1">From (older)</label>
43 <input type="text" name="from" value="{{ from_uuid }}" placeholder="Checkin hash..."
44 aria-label="From checkin hash"
45 class="w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 text-sm px-3 py-2 font-mono focus:border-brand focus:ring-brand">
@@ -53,11 +55,11 @@
53 <button type="submit" class="rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white hover:bg-brand-hover">Compare</button>
54 </form>
55 </div>
56
57 {% if from_detail and to_detail %}
58 <div class="grid grid-cols-2 gap-4 mb-6">
59 <div class="rounded-lg bg-gray-800 border border-gray-700 p-4">
60 <div class="text-xs text-gray-500 mb-1">From</div>
61 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=from_detail.uuid %}" class="text-sm text-brand-light hover:text-brand">{{ from_detail.comment|truncatechars:60 }}</a>
62 <div class="mt-1 text-xs text-gray-500">{{ from_detail.user|display_user }} &middot; {{ from_detail.timestamp|date:"Y-m-d H:i" }}</div>
63 </div>
64
--- templates/fossil/compare.html
+++ templates/fossil/compare.html
@@ -13,13 +13,15 @@
13 .diff-line-hunk { background: rgba(96, 165, 250, 0.08); }
14 .diff-line-hunk td { color: #93c5fd; }
15 .diff-line-header td { color: #6b7280; }
16 .diff-gutter { width: 1%; user-select: none; color: #4b5563; text-align: right; padding: 0 6px; border-right: 1px solid #374151; white-space: nowrap; }
17 /* Split diff view */
18 .split-diff { display: grid; grid-template-columns: 1fr; }
19 @media (min-width: 768px) { .split-diff { grid-template-columns: 1fr 1fr; } }
20 .split-diff-side { overflow-x: auto; }
21 @media (min-width: 768px) { .split-diff-side:first-child { border-right: 1px solid #374151; } }
22 @media (max-width: 767px) { .split-diff-side:first-child { border-bottom: 1px solid #374151; } }
23 .split-diff-side .diff-table td:last-child { width: 100%; }
24 .split-line-add { background: rgba(34, 197, 94, 0.1); }
25 .split-line-add td:last-child { color: #86efac; }
26 .split-line-del { background: rgba(239, 68, 68, 0.1); }
27 .split-line-del td:last-child { color: #fca5a5; }
@@ -35,11 +37,11 @@
37 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
38 {% include "fossil/_project_nav.html" %}
39
40 <div class="mb-6">
41 <h2 class="text-lg font-semibold text-gray-200 mb-3">Compare Checkins</h2>
42 <form method="get" class="flex flex-col sm:flex-row sm:items-end gap-3">
43 <div class="flex-1">
44 <label class="block text-xs text-gray-500 mb-1">From (older)</label>
45 <input type="text" name="from" value="{{ from_uuid }}" placeholder="Checkin hash..."
46 aria-label="From checkin hash"
47 class="w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 text-sm px-3 py-2 font-mono focus:border-brand focus:ring-brand">
@@ -53,11 +55,11 @@
55 <button type="submit" class="rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white hover:bg-brand-hover">Compare</button>
56 </form>
57 </div>
58
59 {% if from_detail and to_detail %}
60 <div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6">
61 <div class="rounded-lg bg-gray-800 border border-gray-700 p-4">
62 <div class="text-xs text-gray-500 mb-1">From</div>
63 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=from_detail.uuid %}" class="text-sm text-brand-light hover:text-brand">{{ from_detail.comment|truncatechars:60 }}</a>
64 <div class="mt-1 text-xs text-gray-500">{{ from_detail.user|display_user }} &middot; {{ from_detail.timestamp|date:"Y-m-d H:i" }}</div>
65 </div>
66
--- templates/fossil/forum_list.html
+++ templates/fossil/forum_list.html
@@ -4,13 +4,13 @@
44
55
{% block content %}
66
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
77
{% include "fossil/_project_nav.html" %}
88
9
-<div class="flex items-center justify-between mb-6">
9
+<div class="flex flex-wrap items-center justify-between gap-3 mb-6">
1010
<h2 class="text-lg font-semibold text-gray-200">Forum</h2>
11
- <div class="flex items-center gap-3">
11
+ <div class="flex flex-wrap items-center gap-3">
1212
<span class="search-wrap">
1313
<input type="search"
1414
name="search"
1515
value="{{ search }}"
1616
placeholder="Search forum..."
1717
--- templates/fossil/forum_list.html
+++ templates/fossil/forum_list.html
@@ -4,13 +4,13 @@
4
5 {% block content %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="flex items-center justify-between mb-6">
10 <h2 class="text-lg font-semibold text-gray-200">Forum</h2>
11 <div class="flex items-center gap-3">
12 <span class="search-wrap">
13 <input type="search"
14 name="search"
15 value="{{ search }}"
16 placeholder="Search forum..."
17
--- templates/fossil/forum_list.html
+++ templates/fossil/forum_list.html
@@ -4,13 +4,13 @@
4
5 {% block content %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="flex flex-wrap items-center justify-between gap-3 mb-6">
10 <h2 class="text-lg font-semibold text-gray-200">Forum</h2>
11 <div class="flex flex-wrap items-center gap-3">
12 <span class="search-wrap">
13 <input type="search"
14 name="search"
15 value="{{ search }}"
16 placeholder="Search forum..."
17
--- templates/fossil/partials/file_tree.html
+++ templates/fossil/partials/file_tree.html
@@ -1,6 +1,6 @@
1
-<div id="file-tree">
1
+<div id="file-tree" class="overflow-x-auto">
22
{% if tree %}
33
<table class="min-w-full">
44
<tbody class="divide-y divide-gray-700">
55
{% for entry in tree %}
66
<tr class="hover:bg-gray-700/30">
77
--- templates/fossil/partials/file_tree.html
+++ templates/fossil/partials/file_tree.html
@@ -1,6 +1,6 @@
1 <div id="file-tree">
2 {% if tree %}
3 <table class="min-w-full">
4 <tbody class="divide-y divide-gray-700">
5 {% for entry in tree %}
6 <tr class="hover:bg-gray-700/30">
7
--- templates/fossil/partials/file_tree.html
+++ templates/fossil/partials/file_tree.html
@@ -1,6 +1,6 @@
1 <div id="file-tree" class="overflow-x-auto">
2 {% if tree %}
3 <table class="min-w-full">
4 <tbody class="divide-y divide-gray-700">
5 {% for entry in tree %}
6 <tr class="hover:bg-gray-700/30">
7
--- templates/fossil/partials/ticket_table.html
+++ templates/fossil/partials/ticket_table.html
@@ -1,7 +1,7 @@
11
<div id="ticket-table">
2
- <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2
+ <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
33
<table class="min-w-full divide-y divide-gray-700">
44
<thead class="bg-gray-900">
55
<tr>
66
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Title</th>
77
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400 w-24">Status</th>
88
--- templates/fossil/partials/ticket_table.html
+++ templates/fossil/partials/ticket_table.html
@@ -1,7 +1,7 @@
1 <div id="ticket-table">
2 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Title</th>
7 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400 w-24">Status</th>
8
--- templates/fossil/partials/ticket_table.html
+++ templates/fossil/partials/ticket_table.html
@@ -1,7 +1,7 @@
1 <div id="ticket-table">
2 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Title</th>
7 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400 w-24">Status</th>
8
--- templates/fossil/partials/timeline_entries.html
+++ templates/fossil/partials/timeline_entries.html
@@ -27,17 +27,22 @@
2727
top: 20%; border-radius: 4px 4px 0 0;
2828
border-top: 2px solid; border-left: 2px solid; border-right: 2px solid;
2929
border-bottom: none; height: 30%; opacity: 0.5;
3030
}
3131
.tl-date { font-size: 0.8rem; font-weight: 700; color: #d1d5db; padding: 8px 0 4px; border-bottom: 1px solid #374151; margin-bottom: 2px; }
32
- .tl-row { display: flex; min-height: 28px; align-items: center; }
32
+ .tl-row { display: flex; min-height: 28px; align-items: center; flex-wrap: wrap; }
3333
.tl-row:hover { background: rgba(255,255,255,0.02); }
3434
.tl-time { width: 42px; flex-shrink: 0; text-align: right; font-size: 0.75rem; color: #6b7280; font-variant-numeric: tabular-nums; }
3535
.tl-msg { flex: 1; min-width: 0; font-size: 0.8125rem; color: #e5e5e5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
3636
.tl-msg a { color: #e5e5e5; text-decoration: none; }
3737
.tl-msg a:hover { color: #e8677a; }
38
- .tl-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-left: 12px; }
38
+ .tl-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-left: 12px; flex-wrap: wrap; }
39
+ @media (max-width: 639px) {
40
+ .tl-meta { display: none; }
41
+ .tl-dag { display: none; }
42
+ .tl-row { padding: 4px 0; }
43
+ }
3944
.tl-hash { font-family: ui-monospace, monospace; font-size: 0.7rem; color: #DC394C; text-decoration: none; }
4045
.tl-hash:hover { color: #e8677a; text-decoration: underline; }
4146
.tl-user { font-size: 0.7rem; color: #9ca3af; text-decoration: none; }
4247
.tl-user:hover { color: #e8677a; }
4348
.tl-branch { font-size: 0.65rem; padding: 1px 6px; border-radius: 9999px; background: rgba(220,57,76,0.1); border: 1px solid rgba(220,57,76,0.2); color: #e8677a; white-space: nowrap; }
4449
--- templates/fossil/partials/timeline_entries.html
+++ templates/fossil/partials/timeline_entries.html
@@ -27,17 +27,22 @@
27 top: 20%; border-radius: 4px 4px 0 0;
28 border-top: 2px solid; border-left: 2px solid; border-right: 2px solid;
29 border-bottom: none; height: 30%; opacity: 0.5;
30 }
31 .tl-date { font-size: 0.8rem; font-weight: 700; color: #d1d5db; padding: 8px 0 4px; border-bottom: 1px solid #374151; margin-bottom: 2px; }
32 .tl-row { display: flex; min-height: 28px; align-items: center; }
33 .tl-row:hover { background: rgba(255,255,255,0.02); }
34 .tl-time { width: 42px; flex-shrink: 0; text-align: right; font-size: 0.75rem; color: #6b7280; font-variant-numeric: tabular-nums; }
35 .tl-msg { flex: 1; min-width: 0; font-size: 0.8125rem; color: #e5e5e5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
36 .tl-msg a { color: #e5e5e5; text-decoration: none; }
37 .tl-msg a:hover { color: #e8677a; }
38 .tl-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-left: 12px; }
 
 
 
 
 
39 .tl-hash { font-family: ui-monospace, monospace; font-size: 0.7rem; color: #DC394C; text-decoration: none; }
40 .tl-hash:hover { color: #e8677a; text-decoration: underline; }
41 .tl-user { font-size: 0.7rem; color: #9ca3af; text-decoration: none; }
42 .tl-user:hover { color: #e8677a; }
43 .tl-branch { font-size: 0.65rem; padding: 1px 6px; border-radius: 9999px; background: rgba(220,57,76,0.1); border: 1px solid rgba(220,57,76,0.2); color: #e8677a; white-space: nowrap; }
44
--- templates/fossil/partials/timeline_entries.html
+++ templates/fossil/partials/timeline_entries.html
@@ -27,17 +27,22 @@
27 top: 20%; border-radius: 4px 4px 0 0;
28 border-top: 2px solid; border-left: 2px solid; border-right: 2px solid;
29 border-bottom: none; height: 30%; opacity: 0.5;
30 }
31 .tl-date { font-size: 0.8rem; font-weight: 700; color: #d1d5db; padding: 8px 0 4px; border-bottom: 1px solid #374151; margin-bottom: 2px; }
32 .tl-row { display: flex; min-height: 28px; align-items: center; flex-wrap: wrap; }
33 .tl-row:hover { background: rgba(255,255,255,0.02); }
34 .tl-time { width: 42px; flex-shrink: 0; text-align: right; font-size: 0.75rem; color: #6b7280; font-variant-numeric: tabular-nums; }
35 .tl-msg { flex: 1; min-width: 0; font-size: 0.8125rem; color: #e5e5e5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
36 .tl-msg a { color: #e5e5e5; text-decoration: none; }
37 .tl-msg a:hover { color: #e8677a; }
38 .tl-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-left: 12px; flex-wrap: wrap; }
39 @media (max-width: 639px) {
40 .tl-meta { display: none; }
41 .tl-dag { display: none; }
42 .tl-row { padding: 4px 0; }
43 }
44 .tl-hash { font-family: ui-monospace, monospace; font-size: 0.7rem; color: #DC394C; text-decoration: none; }
45 .tl-hash:hover { color: #e8677a; text-decoration: underline; }
46 .tl-user { font-size: 0.7rem; color: #9ca3af; text-decoration: none; }
47 .tl-user:hover { color: #e8677a; }
48 .tl-branch { font-size: 0.65rem; padding: 1px 6px; border-radius: 9999px; background: rgba(220,57,76,0.1); border: 1px solid rgba(220,57,76,0.2); color: #e8677a; white-space: nowrap; }
49
--- templates/fossil/release_list.html
+++ templates/fossil/release_list.html
@@ -4,13 +4,13 @@
44
55
{% block content %}
66
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
77
{% include "fossil/_project_nav.html" %}
88
9
-<div class="flex items-center justify-between mb-6">
9
+<div class="flex flex-wrap items-center justify-between gap-3 mb-6">
1010
<h2 class="text-lg font-semibold text-gray-200">Releases</h2>
11
- <div class="flex items-center gap-3">
11
+ <div class="flex flex-wrap items-center gap-3">
1212
<span class="search-wrap">
1313
<input type="search"
1414
name="search"
1515
value="{{ search }}"
1616
placeholder="Search releases..."
1717
--- templates/fossil/release_list.html
+++ templates/fossil/release_list.html
@@ -4,13 +4,13 @@
4
5 {% block content %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="flex items-center justify-between mb-6">
10 <h2 class="text-lg font-semibold text-gray-200">Releases</h2>
11 <div class="flex items-center gap-3">
12 <span class="search-wrap">
13 <input type="search"
14 name="search"
15 value="{{ search }}"
16 placeholder="Search releases..."
17
--- templates/fossil/release_list.html
+++ templates/fossil/release_list.html
@@ -4,13 +4,13 @@
4
5 {% block content %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="flex flex-wrap items-center justify-between gap-3 mb-6">
10 <h2 class="text-lg font-semibold text-gray-200">Releases</h2>
11 <div class="flex flex-wrap items-center gap-3">
12 <span class="search-wrap">
13 <input type="search"
14 name="search"
15 value="{{ search }}"
16 placeholder="Search releases..."
17
--- templates/fossil/repo_settings.html
+++ templates/fossil/repo_settings.html
@@ -105,11 +105,11 @@
105105
</div>
106106
107107
<!-- Actions -->
108108
<div class="rounded-lg bg-gray-800 border border-gray-700 p-5">
109109
<h2 class="text-lg font-semibold text-gray-200 mb-4">Actions</h2>
110
- <div class="flex flex-wrap items-center gap-3">
110
+ <div class="flex flex-wrap items-center gap-x-3 gap-y-2">
111111
<form method="post">
112112
{% csrf_token %}
113113
<input type="hidden" name="action" value="sync_metadata">
114114
<button type="submit"
115115
class="inline-flex items-center gap-2 rounded-md bg-gray-700 px-4 py-2 text-sm font-medium text-gray-200 ring-1 ring-inset ring-gray-600 hover:bg-gray-600"
@@ -176,11 +176,11 @@
176176
177177
<!-- Danger Zone -->
178178
<div class="rounded-lg border-2 border-red-900/50 p-5">
179179
<h2 class="text-lg font-semibold text-red-400 mb-2">Danger Zone</h2>
180180
<p class="text-sm text-gray-400 mb-4">Destructive operations that cannot be undone.</p>
181
- <div class="rounded-md bg-gray-800 border border-gray-700 px-4 py-3 flex items-center justify-between">
181
+ <div class="rounded-md bg-gray-800 border border-gray-700 px-4 py-3 flex flex-wrap items-center justify-between gap-3">
182182
<div>
183183
<p class="text-sm font-medium text-gray-200">Delete this repository</p>
184184
<p class="text-xs text-gray-500">Permanently removes the .fossil file and all associated data.</p>
185185
</div>
186186
<button disabled
187187
--- templates/fossil/repo_settings.html
+++ templates/fossil/repo_settings.html
@@ -105,11 +105,11 @@
105 </div>
106
107 <!-- Actions -->
108 <div class="rounded-lg bg-gray-800 border border-gray-700 p-5">
109 <h2 class="text-lg font-semibold text-gray-200 mb-4">Actions</h2>
110 <div class="flex flex-wrap items-center gap-3">
111 <form method="post">
112 {% csrf_token %}
113 <input type="hidden" name="action" value="sync_metadata">
114 <button type="submit"
115 class="inline-flex items-center gap-2 rounded-md bg-gray-700 px-4 py-2 text-sm font-medium text-gray-200 ring-1 ring-inset ring-gray-600 hover:bg-gray-600"
@@ -176,11 +176,11 @@
176
177 <!-- Danger Zone -->
178 <div class="rounded-lg border-2 border-red-900/50 p-5">
179 <h2 class="text-lg font-semibold text-red-400 mb-2">Danger Zone</h2>
180 <p class="text-sm text-gray-400 mb-4">Destructive operations that cannot be undone.</p>
181 <div class="rounded-md bg-gray-800 border border-gray-700 px-4 py-3 flex items-center justify-between">
182 <div>
183 <p class="text-sm font-medium text-gray-200">Delete this repository</p>
184 <p class="text-xs text-gray-500">Permanently removes the .fossil file and all associated data.</p>
185 </div>
186 <button disabled
187
--- templates/fossil/repo_settings.html
+++ templates/fossil/repo_settings.html
@@ -105,11 +105,11 @@
105 </div>
106
107 <!-- Actions -->
108 <div class="rounded-lg bg-gray-800 border border-gray-700 p-5">
109 <h2 class="text-lg font-semibold text-gray-200 mb-4">Actions</h2>
110 <div class="flex flex-wrap items-center gap-x-3 gap-y-2">
111 <form method="post">
112 {% csrf_token %}
113 <input type="hidden" name="action" value="sync_metadata">
114 <button type="submit"
115 class="inline-flex items-center gap-2 rounded-md bg-gray-700 px-4 py-2 text-sm font-medium text-gray-200 ring-1 ring-inset ring-gray-600 hover:bg-gray-600"
@@ -176,11 +176,11 @@
176
177 <!-- Danger Zone -->
178 <div class="rounded-lg border-2 border-red-900/50 p-5">
179 <h2 class="text-lg font-semibold text-red-400 mb-2">Danger Zone</h2>
180 <p class="text-sm text-gray-400 mb-4">Destructive operations that cannot be undone.</p>
181 <div class="rounded-md bg-gray-800 border border-gray-700 px-4 py-3 flex flex-wrap items-center justify-between gap-3">
182 <div>
183 <p class="text-sm font-medium text-gray-200">Delete this repository</p>
184 <p class="text-xs text-gray-500">Permanently removes the .fossil file and all associated data.</p>
185 </div>
186 <button disabled
187
--- templates/fossil/search.html
+++ templates/fossil/search.html
@@ -5,11 +5,11 @@
55
{% block content %}
66
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
77
{% include "fossil/_project_nav.html" %}
88
99
<form method="get" class="mb-6">
10
- <div class="flex gap-2">
10
+ <div class="flex flex-col sm:flex-row gap-2">
1111
<input type="text" name="q" value="{{ query }}" placeholder="Search checkins, tickets, wiki..."
1212
aria-label="Search repository"
1313
class="flex-1 rounded-md border-gray-700 bg-gray-800 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm px-4 py-2"
1414
autofocus>
1515
<button type="submit" class="rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white hover:bg-brand-hover">Search</button>
1616
--- templates/fossil/search.html
+++ templates/fossil/search.html
@@ -5,11 +5,11 @@
5 {% block content %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <form method="get" class="mb-6">
10 <div class="flex gap-2">
11 <input type="text" name="q" value="{{ query }}" placeholder="Search checkins, tickets, wiki..."
12 aria-label="Search repository"
13 class="flex-1 rounded-md border-gray-700 bg-gray-800 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm px-4 py-2"
14 autofocus>
15 <button type="submit" class="rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white hover:bg-brand-hover">Search</button>
16
--- templates/fossil/search.html
+++ templates/fossil/search.html
@@ -5,11 +5,11 @@
5 {% block content %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <form method="get" class="mb-6">
10 <div class="flex flex-col sm:flex-row gap-2">
11 <input type="text" name="q" value="{{ query }}" placeholder="Search checkins, tickets, wiki..."
12 aria-label="Search repository"
13 class="flex-1 rounded-md border-gray-700 bg-gray-800 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm px-4 py-2"
14 autofocus>
15 <button type="submit" class="rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white hover:bg-brand-hover">Search</button>
16
--- templates/fossil/tag_list.html
+++ templates/fossil/tag_list.html
@@ -25,11 +25,11 @@
2525
</span>
2626
</div>
2727
</div>
2828
2929
<div id="tag-content">
30
-<div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
30
+<div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3131
<table class="min-w-full divide-y divide-gray-700">
3232
<thead class="bg-gray-900">
3333
<tr>
3434
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Tag</th>
3535
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Checkin</th>
3636
--- templates/fossil/tag_list.html
+++ templates/fossil/tag_list.html
@@ -25,11 +25,11 @@
25 </span>
26 </div>
27 </div>
28
29 <div id="tag-content">
30 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
31 <table class="min-w-full divide-y divide-gray-700">
32 <thead class="bg-gray-900">
33 <tr>
34 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Tag</th>
35 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Checkin</th>
36
--- templates/fossil/tag_list.html
+++ templates/fossil/tag_list.html
@@ -25,11 +25,11 @@
25 </span>
26 </div>
27 </div>
28
29 <div id="tag-content">
30 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
31 <table class="min-w-full divide-y divide-gray-700">
32 <thead class="bg-gray-900">
33 <tr>
34 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Tag</th>
35 <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Checkin</th>
36
--- templates/fossil/ticket_detail.html
+++ templates/fossil/ticket_detail.html
@@ -5,18 +5,18 @@
55
{% block content %}
66
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
77
{% include "fossil/_project_nav.html" %}
88
99
<div class="mb-4">
10
- <a href="{% url 'fossil:tickets' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">&larr; Back to tickets</a>
10
+ <a href="{% url 'fossil:tickets' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">&larr; Back to Tickets</a>
1111
</div>
1212
1313
<div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700">
1414
<div class="px-6 py-5 border-b border-gray-700">
15
- <div class="flex items-start justify-between gap-4">
16
- <div class="flex-1">
17
- <h2 class="text-xl font-bold text-gray-100">{{ ticket.title|default:"(untitled)" }}</h2>
15
+ <div class="flex flex-wrap items-start justify-between gap-3">
16
+ <div class="flex-1 min-w-0">
17
+ <h2 class="text-xl font-bold text-gray-100 break-words">{{ ticket.title|default:"(untitled)" }}</h2>
1818
</div>
1919
<div class="flex items-center gap-2 flex-shrink-0">
2020
{% if perms.projects.change_project %}
2121
<a href="{% url 'fossil:ticket_edit' slug=project.slug ticket_uuid=ticket.uuid %}" class="rounded-md bg-gray-700 px-3 py-1.5 text-xs font-semibold text-gray-300 hover:bg-gray-600">Edit</a>
2222
{% endif %}
@@ -35,11 +35,11 @@
3535
</p>
3636
</div>
3737
3838
<!-- Metadata grid -->
3939
<div class="px-6 py-4 border-b border-gray-700">
40
- <dl class="grid grid-cols-2 gap-x-6 gap-y-3 sm:grid-cols-4">
40
+ <dl class="grid grid-cols-1 gap-x-6 gap-y-3 sm:grid-cols-2 lg:grid-cols-4">
4141
<div>
4242
<dt class="text-xs font-medium text-gray-500 uppercase">Type</dt>
4343
<dd class="mt-0.5 text-sm text-gray-200">{{ ticket.type|default:"—" }}</dd>
4444
</div>
4545
<div>
4646
--- templates/fossil/ticket_detail.html
+++ templates/fossil/ticket_detail.html
@@ -5,18 +5,18 @@
5 {% block content %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="mb-4">
10 <a href="{% url 'fossil:tickets' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">&larr; Back to tickets</a>
11 </div>
12
13 <div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700">
14 <div class="px-6 py-5 border-b border-gray-700">
15 <div class="flex items-start justify-between gap-4">
16 <div class="flex-1">
17 <h2 class="text-xl font-bold text-gray-100">{{ ticket.title|default:"(untitled)" }}</h2>
18 </div>
19 <div class="flex items-center gap-2 flex-shrink-0">
20 {% if perms.projects.change_project %}
21 <a href="{% url 'fossil:ticket_edit' slug=project.slug ticket_uuid=ticket.uuid %}" class="rounded-md bg-gray-700 px-3 py-1.5 text-xs font-semibold text-gray-300 hover:bg-gray-600">Edit</a>
22 {% endif %}
@@ -35,11 +35,11 @@
35 </p>
36 </div>
37
38 <!-- Metadata grid -->
39 <div class="px-6 py-4 border-b border-gray-700">
40 <dl class="grid grid-cols-2 gap-x-6 gap-y-3 sm:grid-cols-4">
41 <div>
42 <dt class="text-xs font-medium text-gray-500 uppercase">Type</dt>
43 <dd class="mt-0.5 text-sm text-gray-200">{{ ticket.type|default:"—" }}</dd>
44 </div>
45 <div>
46
--- templates/fossil/ticket_detail.html
+++ templates/fossil/ticket_detail.html
@@ -5,18 +5,18 @@
5 {% block content %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="mb-4">
10 <a href="{% url 'fossil:tickets' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">&larr; Back to Tickets</a>
11 </div>
12
13 <div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700">
14 <div class="px-6 py-5 border-b border-gray-700">
15 <div class="flex flex-wrap items-start justify-between gap-3">
16 <div class="flex-1 min-w-0">
17 <h2 class="text-xl font-bold text-gray-100 break-words">{{ ticket.title|default:"(untitled)" }}</h2>
18 </div>
19 <div class="flex items-center gap-2 flex-shrink-0">
20 {% if perms.projects.change_project %}
21 <a href="{% url 'fossil:ticket_edit' slug=project.slug ticket_uuid=ticket.uuid %}" class="rounded-md bg-gray-700 px-3 py-1.5 text-xs font-semibold text-gray-300 hover:bg-gray-600">Edit</a>
22 {% endif %}
@@ -35,11 +35,11 @@
35 </p>
36 </div>
37
38 <!-- Metadata grid -->
39 <div class="px-6 py-4 border-b border-gray-700">
40 <dl class="grid grid-cols-1 gap-x-6 gap-y-3 sm:grid-cols-2 lg:grid-cols-4">
41 <div>
42 <dt class="text-xs font-medium text-gray-500 uppercase">Type</dt>
43 <dd class="mt-0.5 text-sm text-gray-200">{{ ticket.type|default:"—" }}</dd>
44 </div>
45 <div>
46
--- templates/fossil/ticket_form.html
+++ templates/fossil/ticket_form.html
@@ -19,11 +19,11 @@
1919
<label class="block text-sm font-medium text-gray-300 mb-1">Title <span class="text-red-400">*</span></label>
2020
<input type="text" name="title" required placeholder="Ticket title"
2121
class="w-full rounded-md border-gray-700 bg-gray-900 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm">
2222
</div>
2323
24
- <div class="grid grid-cols-2 gap-4">
24
+ <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
2525
<div>
2626
<label class="block text-sm font-medium text-gray-300 mb-1">Type</label>
2727
<select name="type" class="w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm">
2828
<option value="Code_Defect">Code Defect</option>
2929
<option value="Feature_Request">Feature Request</option>
@@ -50,11 +50,11 @@
5050
</div>
5151
5252
{% if custom_fields %}
5353
<div class="border-t border-gray-700 pt-4 mt-4">
5454
<h3 class="text-sm font-semibold text-gray-300 mb-3">Custom Fields</h3>
55
- <div class="grid grid-cols-2 gap-4">
55
+ <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
5656
{% for cf in custom_fields %}
5757
<div{% if cf.field_type == "textarea" %} class="col-span-2"{% endif %}>
5858
<label class="block text-sm font-medium text-gray-300 mb-1">
5959
{{ cf.label }}
6060
{% if cf.is_required %}<span class="text-red-400">*</span>{% endif %}
6161
--- templates/fossil/ticket_form.html
+++ templates/fossil/ticket_form.html
@@ -19,11 +19,11 @@
19 <label class="block text-sm font-medium text-gray-300 mb-1">Title <span class="text-red-400">*</span></label>
20 <input type="text" name="title" required placeholder="Ticket title"
21 class="w-full rounded-md border-gray-700 bg-gray-900 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm">
22 </div>
23
24 <div class="grid grid-cols-2 gap-4">
25 <div>
26 <label class="block text-sm font-medium text-gray-300 mb-1">Type</label>
27 <select name="type" class="w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm">
28 <option value="Code_Defect">Code Defect</option>
29 <option value="Feature_Request">Feature Request</option>
@@ -50,11 +50,11 @@
50 </div>
51
52 {% if custom_fields %}
53 <div class="border-t border-gray-700 pt-4 mt-4">
54 <h3 class="text-sm font-semibold text-gray-300 mb-3">Custom Fields</h3>
55 <div class="grid grid-cols-2 gap-4">
56 {% for cf in custom_fields %}
57 <div{% if cf.field_type == "textarea" %} class="col-span-2"{% endif %}>
58 <label class="block text-sm font-medium text-gray-300 mb-1">
59 {{ cf.label }}
60 {% if cf.is_required %}<span class="text-red-400">*</span>{% endif %}
61
--- templates/fossil/ticket_form.html
+++ templates/fossil/ticket_form.html
@@ -19,11 +19,11 @@
19 <label class="block text-sm font-medium text-gray-300 mb-1">Title <span class="text-red-400">*</span></label>
20 <input type="text" name="title" required placeholder="Ticket title"
21 class="w-full rounded-md border-gray-700 bg-gray-900 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm">
22 </div>
23
24 <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
25 <div>
26 <label class="block text-sm font-medium text-gray-300 mb-1">Type</label>
27 <select name="type" class="w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 shadow-sm focus:border-brand focus:ring-brand sm:text-sm">
28 <option value="Code_Defect">Code Defect</option>
29 <option value="Feature_Request">Feature Request</option>
@@ -50,11 +50,11 @@
50 </div>
51
52 {% if custom_fields %}
53 <div class="border-t border-gray-700 pt-4 mt-4">
54 <h3 class="text-sm font-semibold text-gray-300 mb-3">Custom Fields</h3>
55 <div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
56 {% for cf in custom_fields %}
57 <div{% if cf.field_type == "textarea" %} class="col-span-2"{% endif %}>
58 <label class="block text-sm font-medium text-gray-300 mb-1">
59 {{ cf.label }}
60 {% if cf.is_required %}<span class="text-red-400">*</span>{% endif %}
61
--- templates/fossil/ticket_list.html
+++ templates/fossil/ticket_list.html
@@ -4,11 +4,11 @@
44
{% block content %}
55
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
66
{% include "fossil/_project_nav.html" %}
77
88
<div class="flex flex-wrap items-center justify-between gap-3 mb-4">
9
- <div class="flex items-center gap-2 text-xs text-gray-500">
9
+ <div class="flex flex-wrap items-center gap-2 text-xs text-gray-500">
1010
<span>Status:</span>
1111
<a href="{% url 'fossil:tickets' slug=project.slug %}"
1212
class="rounded-full px-2.5 py-1 {% if not status_filter %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">All</a>
1313
<a href="{% url 'fossil:tickets' slug=project.slug %}?status=Open"
1414
class="rounded-full px-2.5 py-1 {% if status_filter == 'Open' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Open</a>
@@ -15,11 +15,11 @@
1515
<a href="{% url 'fossil:tickets' slug=project.slug %}?status=Fixed"
1616
class="rounded-full px-2.5 py-1 {% if status_filter == 'Fixed' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Fixed</a>
1717
<a href="{% url 'fossil:tickets' slug=project.slug %}?status=Closed"
1818
class="rounded-full px-2.5 py-1 {% if status_filter == 'Closed' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Closed</a>
1919
</div>
20
- <div class="flex items-center gap-3">
20
+ <div class="flex flex-wrap items-center gap-3">
2121
<a href="{% url 'fossil:tickets_csv' slug=project.slug %}" class="text-xs text-gray-500 hover:text-brand-light">Export CSV</a>
2222
{% if perms.projects.change_project %}
2323
<a href="{% url 'fossil:ticket_create' slug=project.slug %}" class="inline-flex items-center rounded-md bg-brand px-3 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-brand-hover">New Ticket</a>
2424
{% endif %}
2525
<span class="search-wrap">
@@ -40,12 +40,12 @@
4040
</div>
4141
</div>
4242
4343
{% include "fossil/partials/ticket_table.html" %}
4444
45
-<div class="mt-4 flex items-center justify-between text-sm">
46
- <div class="flex items-center gap-3">
45
+<div class="mt-4 flex flex-wrap items-center justify-between gap-3 text-sm">
46
+ <div class="flex flex-wrap items-center gap-3">
4747
<span class="text-gray-500">{{ total }} ticket{{ total|pluralize }}</span>
4848
<div class="flex items-center gap-1 text-xs">
4949
<span class="text-gray-600">Show:</span>
5050
{% for size in per_page_options %}
5151
<a href="{% url 'fossil:tickets' slug=project.slug %}?per_page={{ size }}{% if status_filter %}&status={{ status_filter }}{% endif %}"
5252
--- templates/fossil/ticket_list.html
+++ templates/fossil/ticket_list.html
@@ -4,11 +4,11 @@
4 {% block content %}
5 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
6 {% include "fossil/_project_nav.html" %}
7
8 <div class="flex flex-wrap items-center justify-between gap-3 mb-4">
9 <div class="flex items-center gap-2 text-xs text-gray-500">
10 <span>Status:</span>
11 <a href="{% url 'fossil:tickets' slug=project.slug %}"
12 class="rounded-full px-2.5 py-1 {% if not status_filter %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">All</a>
13 <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Open"
14 class="rounded-full px-2.5 py-1 {% if status_filter == 'Open' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Open</a>
@@ -15,11 +15,11 @@
15 <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Fixed"
16 class="rounded-full px-2.5 py-1 {% if status_filter == 'Fixed' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Fixed</a>
17 <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Closed"
18 class="rounded-full px-2.5 py-1 {% if status_filter == 'Closed' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Closed</a>
19 </div>
20 <div class="flex items-center gap-3">
21 <a href="{% url 'fossil:tickets_csv' slug=project.slug %}" class="text-xs text-gray-500 hover:text-brand-light">Export CSV</a>
22 {% if perms.projects.change_project %}
23 <a href="{% url 'fossil:ticket_create' slug=project.slug %}" class="inline-flex items-center rounded-md bg-brand px-3 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-brand-hover">New Ticket</a>
24 {% endif %}
25 <span class="search-wrap">
@@ -40,12 +40,12 @@
40 </div>
41 </div>
42
43 {% include "fossil/partials/ticket_table.html" %}
44
45 <div class="mt-4 flex items-center justify-between text-sm">
46 <div class="flex items-center gap-3">
47 <span class="text-gray-500">{{ total }} ticket{{ total|pluralize }}</span>
48 <div class="flex items-center gap-1 text-xs">
49 <span class="text-gray-600">Show:</span>
50 {% for size in per_page_options %}
51 <a href="{% url 'fossil:tickets' slug=project.slug %}?per_page={{ size }}{% if status_filter %}&status={{ status_filter }}{% endif %}"
52
--- templates/fossil/ticket_list.html
+++ templates/fossil/ticket_list.html
@@ -4,11 +4,11 @@
4 {% block content %}
5 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
6 {% include "fossil/_project_nav.html" %}
7
8 <div class="flex flex-wrap items-center justify-between gap-3 mb-4">
9 <div class="flex flex-wrap items-center gap-2 text-xs text-gray-500">
10 <span>Status:</span>
11 <a href="{% url 'fossil:tickets' slug=project.slug %}"
12 class="rounded-full px-2.5 py-1 {% if not status_filter %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">All</a>
13 <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Open"
14 class="rounded-full px-2.5 py-1 {% if status_filter == 'Open' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Open</a>
@@ -15,11 +15,11 @@
15 <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Fixed"
16 class="rounded-full px-2.5 py-1 {% if status_filter == 'Fixed' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Fixed</a>
17 <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Closed"
18 class="rounded-full px-2.5 py-1 {% if status_filter == 'Closed' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Closed</a>
19 </div>
20 <div class="flex flex-wrap items-center gap-3">
21 <a href="{% url 'fossil:tickets_csv' slug=project.slug %}" class="text-xs text-gray-500 hover:text-brand-light">Export CSV</a>
22 {% if perms.projects.change_project %}
23 <a href="{% url 'fossil:ticket_create' slug=project.slug %}" class="inline-flex items-center rounded-md bg-brand px-3 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-brand-hover">New Ticket</a>
24 {% endif %}
25 <span class="search-wrap">
@@ -40,12 +40,12 @@
40 </div>
41 </div>
42
43 {% include "fossil/partials/ticket_table.html" %}
44
45 <div class="mt-4 flex flex-wrap items-center justify-between gap-3 text-sm">
46 <div class="flex flex-wrap items-center gap-3">
47 <span class="text-gray-500">{{ total }} ticket{{ total|pluralize }}</span>
48 <div class="flex items-center gap-1 text-xs">
49 <span class="text-gray-600">Show:</span>
50 {% for size in per_page_options %}
51 <a href="{% url 'fossil:tickets' slug=project.slug %}?per_page={{ size }}{% if status_filter %}&status={{ status_filter }}{% endif %}"
52
--- templates/fossil/timeline.html
+++ templates/fossil/timeline.html
@@ -4,12 +4,12 @@
44
{% block content %}
55
{% include "fossil/_live_reload.html" %}
66
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
77
{% include "fossil/_project_nav.html" %}
88
9
-<div class="flex items-center justify-between mb-4">
10
- <div class="flex items-center gap-2 text-xs text-gray-500">
9
+<div class="flex flex-wrap items-center justify-between gap-2 mb-4">
10
+ <div class="flex flex-wrap items-center gap-2 text-xs text-gray-500">
1111
<span>Filter:</span>
1212
<a href="{% url 'fossil:timeline' slug=project.slug %}"
1313
class="rounded-full px-2.5 py-1 {% if not event_type %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">All</a>
1414
<a href="{% url 'fossil:timeline' slug=project.slug %}?type=ci"
1515
class="rounded-full px-2.5 py-1 {% if event_type == 'ci' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Checkins</a>
1616
--- templates/fossil/timeline.html
+++ templates/fossil/timeline.html
@@ -4,12 +4,12 @@
4 {% block content %}
5 {% include "fossil/_live_reload.html" %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="flex items-center justify-between mb-4">
10 <div class="flex items-center gap-2 text-xs text-gray-500">
11 <span>Filter:</span>
12 <a href="{% url 'fossil:timeline' slug=project.slug %}"
13 class="rounded-full px-2.5 py-1 {% if not event_type %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">All</a>
14 <a href="{% url 'fossil:timeline' slug=project.slug %}?type=ci"
15 class="rounded-full px-2.5 py-1 {% if event_type == 'ci' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Checkins</a>
16
--- templates/fossil/timeline.html
+++ templates/fossil/timeline.html
@@ -4,12 +4,12 @@
4 {% block content %}
5 {% include "fossil/_live_reload.html" %}
6 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
7 {% include "fossil/_project_nav.html" %}
8
9 <div class="flex flex-wrap items-center justify-between gap-2 mb-4">
10 <div class="flex flex-wrap items-center gap-2 text-xs text-gray-500">
11 <span>Filter:</span>
12 <a href="{% url 'fossil:timeline' slug=project.slug %}"
13 class="rounded-full px-2.5 py-1 {% if not event_type %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">All</a>
14 <a href="{% url 'fossil:timeline' slug=project.slug %}?type=ci"
15 class="rounded-full px-2.5 py-1 {% if event_type == 'ci' %}bg-brand text-white{% else %}bg-gray-800 text-gray-400 hover:text-white border border-gray-700{% endif %}">Checkins</a>
16
--- templates/fossil/unversioned_list.html
+++ templates/fossil/unversioned_list.html
@@ -26,11 +26,11 @@
2626
</div>
2727
</div>
2828
2929
<div id="unversioned-content">
3030
{% if files %}
31
-<div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700">
31
+<div class="overflow-x-auto rounded-lg bg-gray-800 shadow border border-gray-700">
3232
<table class="min-w-full divide-y divide-gray-700">
3333
<thead class="bg-gray-900">
3434
<tr>
3535
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Name</th>
3636
<th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Size</th>
3737
--- templates/fossil/unversioned_list.html
+++ templates/fossil/unversioned_list.html
@@ -26,11 +26,11 @@
26 </div>
27 </div>
28
29 <div id="unversioned-content">
30 {% if files %}
31 <div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700">
32 <table class="min-w-full divide-y divide-gray-700">
33 <thead class="bg-gray-900">
34 <tr>
35 <th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Name</th>
36 <th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Size</th>
37
--- templates/fossil/unversioned_list.html
+++ templates/fossil/unversioned_list.html
@@ -26,11 +26,11 @@
26 </div>
27 </div>
28
29 <div id="unversioned-content">
30 {% if files %}
31 <div class="overflow-x-auto rounded-lg bg-gray-800 shadow border border-gray-700">
32 <table class="min-w-full divide-y divide-gray-700">
33 <thead class="bg-gray-900">
34 <tr>
35 <th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Name</th>
36 <th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Size</th>
37
--- templates/fossil/wiki_list.html
+++ templates/fossil/wiki_list.html
@@ -3,11 +3,11 @@
33
44
{% block content %}
55
<h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
66
{% include "fossil/_project_nav.html" %}
77
8
-<div class="flex items-center justify-between mb-4">
8
+<div class="flex flex-wrap items-center justify-between gap-3 mb-4">
99
<div>
1010
<span class="search-wrap">
1111
<input type="search"
1212
name="search"
1313
value="{{ search }}"
1414
--- templates/fossil/wiki_list.html
+++ templates/fossil/wiki_list.html
@@ -3,11 +3,11 @@
3
4 {% block content %}
5 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
6 {% include "fossil/_project_nav.html" %}
7
8 <div class="flex items-center justify-between mb-4">
9 <div>
10 <span class="search-wrap">
11 <input type="search"
12 name="search"
13 value="{{ search }}"
14
--- templates/fossil/wiki_list.html
+++ templates/fossil/wiki_list.html
@@ -3,11 +3,11 @@
3
4 {% block content %}
5 <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1>
6 {% include "fossil/_project_nav.html" %}
7
8 <div class="flex flex-wrap items-center justify-between gap-3 mb-4">
9 <div>
10 <span class="search-wrap">
11 <input type="search"
12 name="search"
13 value="{{ search }}"
14
--- templates/organization/audit_log.html
+++ templates/organization/audit_log.html
@@ -9,11 +9,11 @@
99
<p class="mt-1 text-sm text-gray-400">History of changes across all tracked models.</p>
1010
</div>
1111
</div>
1212
1313
<!-- Filter by model type -->
14
-<div class="flex gap-2 mb-6">
14
+<div class="flex flex-wrap gap-2 mb-6">
1515
<a href="{% url 'organization:audit_log' %}"
1616
class="rounded-md px-3 py-2 text-sm font-medium {% if not model_filter %}bg-brand text-white{% else %}bg-gray-700 text-gray-300 ring-1 ring-inset ring-gray-600 hover:bg-gray-600{% endif %}">
1717
All
1818
</a>
1919
{% for model_name in available_models %}
@@ -23,11 +23,11 @@
2323
</a>
2424
{% endfor %}
2525
</div>
2626
2727
<!-- Audit entries table -->
28
-<div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
28
+<div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2929
<table class="min-w-full divide-y divide-gray-700">
3030
<thead class="bg-gray-900">
3131
<tr>
3232
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Date</th>
3333
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">User</th>
3434
--- templates/organization/audit_log.html
+++ templates/organization/audit_log.html
@@ -9,11 +9,11 @@
9 <p class="mt-1 text-sm text-gray-400">History of changes across all tracked models.</p>
10 </div>
11 </div>
12
13 <!-- Filter by model type -->
14 <div class="flex gap-2 mb-6">
15 <a href="{% url 'organization:audit_log' %}"
16 class="rounded-md px-3 py-2 text-sm font-medium {% if not model_filter %}bg-brand text-white{% else %}bg-gray-700 text-gray-300 ring-1 ring-inset ring-gray-600 hover:bg-gray-600{% endif %}">
17 All
18 </a>
19 {% for model_name in available_models %}
@@ -23,11 +23,11 @@
23 </a>
24 {% endfor %}
25 </div>
26
27 <!-- Audit entries table -->
28 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
29 <table class="min-w-full divide-y divide-gray-700">
30 <thead class="bg-gray-900">
31 <tr>
32 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Date</th>
33 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">User</th>
34
--- templates/organization/audit_log.html
+++ templates/organization/audit_log.html
@@ -9,11 +9,11 @@
9 <p class="mt-1 text-sm text-gray-400">History of changes across all tracked models.</p>
10 </div>
11 </div>
12
13 <!-- Filter by model type -->
14 <div class="flex flex-wrap gap-2 mb-6">
15 <a href="{% url 'organization:audit_log' %}"
16 class="rounded-md px-3 py-2 text-sm font-medium {% if not model_filter %}bg-brand text-white{% else %}bg-gray-700 text-gray-300 ring-1 ring-inset ring-gray-600 hover:bg-gray-600{% endif %}">
17 All
18 </a>
19 {% for model_name in available_models %}
@@ -23,11 +23,11 @@
23 </a>
24 {% endfor %}
25 </div>
26
27 <!-- Audit entries table -->
28 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
29 <table class="min-w-full divide-y divide-gray-700">
30 <thead class="bg-gray-900">
31 <tr>
32 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Date</th>
33 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">User</th>
34
--- templates/organization/partials/member_table.html
+++ templates/organization/partials/member_table.html
@@ -1,7 +1,7 @@
11
<div id="member-table">
2
- <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2
+ <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
33
<table class="min-w-full divide-y divide-gray-700">
44
<thead class="bg-gray-900">
55
<tr>
66
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Username</th>
77
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Email</th>
88
--- templates/organization/partials/member_table.html
+++ templates/organization/partials/member_table.html
@@ -1,7 +1,7 @@
1 <div id="member-table">
2 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Username</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Email</th>
8
--- templates/organization/partials/member_table.html
+++ templates/organization/partials/member_table.html
@@ -1,7 +1,7 @@
1 <div id="member-table">
2 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Username</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Email</th>
8
--- templates/organization/partials/team_member_table.html
+++ templates/organization/partials/team_member_table.html
@@ -1,7 +1,7 @@
11
<div id="team-member-table">
2
- <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2
+ <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
33
<table class="min-w-full divide-y divide-gray-700">
44
<thead class="bg-gray-900">
55
<tr>
66
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Username</th>
77
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Email</th>
88
--- templates/organization/partials/team_member_table.html
+++ templates/organization/partials/team_member_table.html
@@ -1,7 +1,7 @@
1 <div id="team-member-table">
2 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Username</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Email</th>
8
--- templates/organization/partials/team_member_table.html
+++ templates/organization/partials/team_member_table.html
@@ -1,7 +1,7 @@
1 <div id="team-member-table">
2 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Username</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Email</th>
8
--- templates/organization/partials/team_table.html
+++ templates/organization/partials/team_table.html
@@ -1,7 +1,7 @@
11
<div id="team-table">
2
- <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2
+ <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
33
<table class="min-w-full divide-y divide-gray-700">
44
<thead class="bg-gray-900">
55
<tr>
66
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
77
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Members</th>
88
--- templates/organization/partials/team_table.html
+++ templates/organization/partials/team_table.html
@@ -1,7 +1,7 @@
1 <div id="team-table">
2 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Members</th>
8
--- templates/organization/partials/team_table.html
+++ templates/organization/partials/team_table.html
@@ -1,7 +1,7 @@
1 <div id="team-table">
2 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Members</th>
8
--- templates/pages/partials/page_table.html
+++ templates/pages/partials/page_table.html
@@ -1,7 +1,7 @@
11
<div id="page-table">
2
- <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2
+ <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
33
<table class="min-w-full divide-y divide-gray-700">
44
<thead class="bg-gray-900">
55
<tr>
66
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Title</th>
77
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Status</th>
88
--- templates/pages/partials/page_table.html
+++ templates/pages/partials/page_table.html
@@ -1,7 +1,7 @@
1 <div id="page-table">
2 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Title</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Status</th>
8
--- templates/pages/partials/page_table.html
+++ templates/pages/partials/page_table.html
@@ -1,7 +1,7 @@
1 <div id="page-table">
2 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Title</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Status</th>
8
--- templates/projects/explore.html
+++ templates/projects/explore.html
@@ -25,11 +25,11 @@
2525
<button type="submit"
2626
class="rounded-md bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-100 ring-1 ring-inset ring-gray-600 hover:bg-gray-600">
2727
Search
2828
</button>
2929
</form>
30
- <div class="flex gap-2">
30
+ <div class="flex flex-wrap gap-2">
3131
<a href="{% url 'explore' %}?sort=stars{% if search %}&search={{ search }}{% endif %}"
3232
class="rounded-md px-3 py-2 text-sm font-medium {% if sort == 'stars' %}bg-brand text-white{% else %}bg-gray-700 text-gray-300 ring-1 ring-inset ring-gray-600 hover:bg-gray-600{% endif %}">
3333
Stars
3434
</a>
3535
<a href="{% url 'explore' %}?sort=recent{% if search %}&search={{ search }}{% endif %}"
3636
--- templates/projects/explore.html
+++ templates/projects/explore.html
@@ -25,11 +25,11 @@
25 <button type="submit"
26 class="rounded-md bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-100 ring-1 ring-inset ring-gray-600 hover:bg-gray-600">
27 Search
28 </button>
29 </form>
30 <div class="flex gap-2">
31 <a href="{% url 'explore' %}?sort=stars{% if search %}&search={{ search }}{% endif %}"
32 class="rounded-md px-3 py-2 text-sm font-medium {% if sort == 'stars' %}bg-brand text-white{% else %}bg-gray-700 text-gray-300 ring-1 ring-inset ring-gray-600 hover:bg-gray-600{% endif %}">
33 Stars
34 </a>
35 <a href="{% url 'explore' %}?sort=recent{% if search %}&search={{ search }}{% endif %}"
36
--- templates/projects/explore.html
+++ templates/projects/explore.html
@@ -25,11 +25,11 @@
25 <button type="submit"
26 class="rounded-md bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-100 ring-1 ring-inset ring-gray-600 hover:bg-gray-600">
27 Search
28 </button>
29 </form>
30 <div class="flex flex-wrap gap-2">
31 <a href="{% url 'explore' %}?sort=stars{% if search %}&search={{ search }}{% endif %}"
32 class="rounded-md px-3 py-2 text-sm font-medium {% if sort == 'stars' %}bg-brand text-white{% else %}bg-gray-700 text-gray-300 ring-1 ring-inset ring-gray-600 hover:bg-gray-600{% endif %}">
33 Stars
34 </a>
35 <a href="{% url 'explore' %}?sort=recent{% if search %}&search={{ search }}{% endif %}"
36
--- templates/projects/partials/group_table.html
+++ templates/projects/partials/group_table.html
@@ -1,7 +1,7 @@
11
<div id="group-table">
2
- <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2
+ <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
33
<table class="min-w-full divide-y divide-gray-700">
44
<thead class="bg-gray-900">
55
<tr>
66
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
77
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Description</th>
88
--- templates/projects/partials/group_table.html
+++ templates/projects/partials/group_table.html
@@ -1,7 +1,7 @@
1 <div id="group-table">
2 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Description</th>
8
--- templates/projects/partials/group_table.html
+++ templates/projects/partials/group_table.html
@@ -1,7 +1,7 @@
1 <div id="group-table">
2 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Description</th>
8
--- templates/projects/partials/project_table.html
+++ templates/projects/partials/project_table.html
@@ -1,7 +1,7 @@
11
<div id="project-table">
2
- <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2
+ <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
33
<table class="min-w-full divide-y divide-gray-700">
44
<thead class="bg-gray-900">
55
<tr>
66
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
77
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Visibility</th>
88
--- templates/projects/partials/project_table.html
+++ templates/projects/partials/project_table.html
@@ -1,7 +1,7 @@
1 <div id="project-table">
2 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Visibility</th>
8
--- templates/projects/partials/project_table.html
+++ templates/projects/partials/project_table.html
@@ -1,7 +1,7 @@
1 <div id="project-table">
2 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Visibility</th>
8
--- templates/projects/partials/project_team_table.html
+++ templates/projects/partials/project_team_table.html
@@ -1,7 +1,7 @@
11
<div id="project-team-table">
2
- <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
2
+ <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
33
<table class="min-w-full divide-y divide-gray-700">
44
<thead class="bg-gray-900">
55
<tr>
66
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Team</th>
77
<th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Role</th>
88
--- templates/projects/partials/project_team_table.html
+++ templates/projects/partials/project_team_table.html
@@ -1,7 +1,7 @@
1 <div id="project-team-table">
2 <div class="overflow-hidden rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Team</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Role</th>
8
--- templates/projects/partials/project_team_table.html
+++ templates/projects/partials/project_team_table.html
@@ -1,7 +1,7 @@
1 <div id="project-team-table">
2 <div class="overflow-x-auto rounded-lg border border-gray-700 bg-gray-800 shadow-sm">
3 <table class="min-w-full divide-y divide-gray-700">
4 <thead class="bg-gray-900">
5 <tr>
6 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Team</th>
7 <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Role</th>
8
--- templates/projects/project_detail.html
+++ templates/projects/project_detail.html
@@ -72,11 +72,11 @@
7272
<div class="w-2.5 h-2.5 rounded-full bg-brand"></div>
7373
</div>
7474
<div class="flex-1 min-w-0">
7575
<a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=commit.uuid %}"
7676
class="text-sm text-gray-200 hover:text-brand-light">{{ commit.comment|truncatechars:80 }}</a>
77
- <div class="mt-0.5 flex items-center gap-3 text-xs text-gray-500">
77
+ <div class="mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-gray-500">
7878
<span>{{ commit.user|display_user }}</span>
7979
<a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=commit.uuid %}"
8080
class="font-mono text-brand-light hover:text-brand">{{ commit.uuid|truncatechars:10 }}</a>
8181
<span>{{ commit.timestamp|timesince }} ago</span>
8282
</div>
8383
--- templates/projects/project_detail.html
+++ templates/projects/project_detail.html
@@ -72,11 +72,11 @@
72 <div class="w-2.5 h-2.5 rounded-full bg-brand"></div>
73 </div>
74 <div class="flex-1 min-w-0">
75 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=commit.uuid %}"
76 class="text-sm text-gray-200 hover:text-brand-light">{{ commit.comment|truncatechars:80 }}</a>
77 <div class="mt-0.5 flex items-center gap-3 text-xs text-gray-500">
78 <span>{{ commit.user|display_user }}</span>
79 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=commit.uuid %}"
80 class="font-mono text-brand-light hover:text-brand">{{ commit.uuid|truncatechars:10 }}</a>
81 <span>{{ commit.timestamp|timesince }} ago</span>
82 </div>
83
--- templates/projects/project_detail.html
+++ templates/projects/project_detail.html
@@ -72,11 +72,11 @@
72 <div class="w-2.5 h-2.5 rounded-full bg-brand"></div>
73 </div>
74 <div class="flex-1 min-w-0">
75 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=commit.uuid %}"
76 class="text-sm text-gray-200 hover:text-brand-light">{{ commit.comment|truncatechars:80 }}</a>
77 <div class="mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-gray-500">
78 <span>{{ commit.user|display_user }}</span>
79 <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=commit.uuid %}"
80 class="font-mono text-brand-light hover:text-brand">{{ commit.uuid|truncatechars:10 }}</a>
81 <span>{{ commit.timestamp|timesince }} ago</span>
82 </div>
83
--- templates/projects/project_list.html
+++ templates/projects/project_list.html
@@ -1,14 +1,14 @@
11
{% extends "base.html" %}
22
{% block title %}Projects — Fossilrepo{% endblock %}
33
44
{% block content %}
5
-<div class="md:flex md:items-center md:justify-between mb-6">
5
+<div class="flex flex-wrap items-center justify-between gap-4 mb-6">
66
<h1 class="text-2xl font-bold text-gray-100">Projects</h1>
77
{% if perms.projects.add_project %}
88
<a href="{% url 'projects:create' %}"
9
- class="mt-4 md:mt-0 inline-flex items-center rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-brand-hover">
9
+ class="inline-flex items-center rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-brand-hover">
1010
New Project
1111
</a>
1212
{% endif %}
1313
</div>
1414
1515
--- templates/projects/project_list.html
+++ templates/projects/project_list.html
@@ -1,14 +1,14 @@
1 {% extends "base.html" %}
2 {% block title %}Projects — Fossilrepo{% endblock %}
3
4 {% block content %}
5 <div class="md:flex md:items-center md:justify-between mb-6">
6 <h1 class="text-2xl font-bold text-gray-100">Projects</h1>
7 {% if perms.projects.add_project %}
8 <a href="{% url 'projects:create' %}"
9 class="mt-4 md:mt-0 inline-flex items-center rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-brand-hover">
10 New Project
11 </a>
12 {% endif %}
13 </div>
14
15
--- templates/projects/project_list.html
+++ templates/projects/project_list.html
@@ -1,14 +1,14 @@
1 {% extends "base.html" %}
2 {% block title %}Projects — Fossilrepo{% endblock %}
3
4 {% block content %}
5 <div class="flex flex-wrap items-center justify-between gap-4 mb-6">
6 <h1 class="text-2xl font-bold text-gray-100">Projects</h1>
7 {% if perms.projects.add_project %}
8 <a href="{% url 'projects:create' %}"
9 class="inline-flex items-center rounded-md bg-brand px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-brand-hover">
10 New Project
11 </a>
12 {% endif %}
13 </div>
14
15
--- tests/__pycache__/test_agent_coordination.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_agent_coordination.cpython-314-pytest-9.0.2.pyc
cannot compute difference between binary files
11
--- tests/__pycache__/test_agent_coordination.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_agent_coordination.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- tests/__pycache__/test_agent_coordination.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_agent_coordination.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- tests/__pycache__/test_bundle_cli.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_bundle_cli.cpython-314-pytest-9.0.2.pyc
cannot compute difference between binary files
11
--- tests/__pycache__/test_bundle_cli.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_bundle_cli.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- tests/__pycache__/test_bundle_cli.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_bundle_cli.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- tests/__pycache__/test_releases.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_releases.cpython-314-pytest-9.0.2.pyc
cannot compute difference between binary files
11
--- tests/__pycache__/test_releases.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_releases.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- tests/__pycache__/test_releases.cpython-314-pytest-9.0.2.pyc
+++ tests/__pycache__/test_releases.cpython-314-pytest-9.0.2.pyc
0 annot compute difference between binary files
1
--- tests/test_agent_coordination.py
+++ tests/test_agent_coordination.py
@@ -693,21 +693,21 @@
693693
694694
695695
@pytest.mark.django_db
696696
class TestCodeReviewComment:
697697
def test_add_comment(self, admin_client, sample_project, fossil_repo_obj, admin_user):
698
- """Adding a comment to a review returns 201."""
698
+ """Adding a comment to a review returns 201. Author is derived from auth, not body."""
699699
review = CodeReview.objects.create(repository=fossil_repo_obj, title="Fix", diff="d", created_by=admin_user)
700700
701701
response = admin_client.post(
702702
_api_url(sample_project.slug, f"api/reviews/{review.pk}/comment"),
703703
data=json.dumps(
704704
{
705705
"body": "Consider using a guard clause here",
706706
"file_path": "src/auth.py",
707707
"line_number": 42,
708
- "author": "human-reviewer",
708
+ "author": "human-reviewer", # ignored — author comes from auth context
709709
}
710710
),
711711
content_type="application/json",
712712
)
713713
@@ -714,11 +714,11 @@
714714
assert response.status_code == 201
715715
data = response.json()
716716
assert data["body"] == "Consider using a guard clause here"
717717
assert data["file_path"] == "src/auth.py"
718718
assert data["line_number"] == 42
719
- assert data["author"] == "human-reviewer"
719
+ assert data["author"] == "admin" # session user's username, not caller-supplied
720720
721721
# Verify DB
722722
assert ReviewComment.objects.filter(review=review).count() == 1
723723
724724
def test_add_comment_infers_author_from_user(self, admin_client, sample_project, fossil_repo_obj, admin_user):
725725
--- tests/test_agent_coordination.py
+++ tests/test_agent_coordination.py
@@ -693,21 +693,21 @@
693
694
695 @pytest.mark.django_db
696 class TestCodeReviewComment:
697 def test_add_comment(self, admin_client, sample_project, fossil_repo_obj, admin_user):
698 """Adding a comment to a review returns 201."""
699 review = CodeReview.objects.create(repository=fossil_repo_obj, title="Fix", diff="d", created_by=admin_user)
700
701 response = admin_client.post(
702 _api_url(sample_project.slug, f"api/reviews/{review.pk}/comment"),
703 data=json.dumps(
704 {
705 "body": "Consider using a guard clause here",
706 "file_path": "src/auth.py",
707 "line_number": 42,
708 "author": "human-reviewer",
709 }
710 ),
711 content_type="application/json",
712 )
713
@@ -714,11 +714,11 @@
714 assert response.status_code == 201
715 data = response.json()
716 assert data["body"] == "Consider using a guard clause here"
717 assert data["file_path"] == "src/auth.py"
718 assert data["line_number"] == 42
719 assert data["author"] == "human-reviewer"
720
721 # Verify DB
722 assert ReviewComment.objects.filter(review=review).count() == 1
723
724 def test_add_comment_infers_author_from_user(self, admin_client, sample_project, fossil_repo_obj, admin_user):
725
--- tests/test_agent_coordination.py
+++ tests/test_agent_coordination.py
@@ -693,21 +693,21 @@
693
694
695 @pytest.mark.django_db
696 class TestCodeReviewComment:
697 def test_add_comment(self, admin_client, sample_project, fossil_repo_obj, admin_user):
698 """Adding a comment to a review returns 201. Author is derived from auth, not body."""
699 review = CodeReview.objects.create(repository=fossil_repo_obj, title="Fix", diff="d", created_by=admin_user)
700
701 response = admin_client.post(
702 _api_url(sample_project.slug, f"api/reviews/{review.pk}/comment"),
703 data=json.dumps(
704 {
705 "body": "Consider using a guard clause here",
706 "file_path": "src/auth.py",
707 "line_number": 42,
708 "author": "human-reviewer", # ignored — author comes from auth context
709 }
710 ),
711 content_type="application/json",
712 )
713
@@ -714,11 +714,11 @@
714 assert response.status_code == 201
715 data = response.json()
716 assert data["body"] == "Consider using a guard clause here"
717 assert data["file_path"] == "src/auth.py"
718 assert data["line_number"] == 42
719 assert data["author"] == "admin" # session user's username, not caller-supplied
720
721 # Verify DB
722 assert ReviewComment.objects.filter(review=review).count() == 1
723
724 def test_add_comment_infers_author_from_user(self, admin_client, sample_project, fossil_repo_obj, admin_user):
725
--- tests/test_bundle_cli.py
+++ tests/test_bundle_cli.py
@@ -21,11 +21,14 @@
2121
assert result.exit_code == 0
2222
assert "No repository found" in result.output
2323
2424
def test_export_repo_not_on_disk(self, runner, sample_project):
2525
"""Export when the .fossil file does not exist on disk."""
26
- result = runner.invoke(cli, ["bundle", "export", sample_project.slug, "/tmp/out.bundle"])
26
+ from fossil.models import FossilRepository
27
+
28
+ with patch.object(type(FossilRepository.objects.get(project=sample_project)), "exists_on_disk", new_callable=lambda: property(lambda self: False)):
29
+ result = runner.invoke(cli, ["bundle", "export", sample_project.slug, "/tmp/out.bundle"])
2730
assert result.exit_code == 0
2831
assert "not found on disk" in result.output
2932
3033
def test_export_fossil_not_available(self, runner, sample_project):
3134
"""Export when fossil binary is not found."""
3235
--- tests/test_bundle_cli.py
+++ tests/test_bundle_cli.py
@@ -21,11 +21,14 @@
21 assert result.exit_code == 0
22 assert "No repository found" in result.output
23
24 def test_export_repo_not_on_disk(self, runner, sample_project):
25 """Export when the .fossil file does not exist on disk."""
26 result = runner.invoke(cli, ["bundle", "export", sample_project.slug, "/tmp/out.bundle"])
 
 
 
27 assert result.exit_code == 0
28 assert "not found on disk" in result.output
29
30 def test_export_fossil_not_available(self, runner, sample_project):
31 """Export when fossil binary is not found."""
32
--- tests/test_bundle_cli.py
+++ tests/test_bundle_cli.py
@@ -21,11 +21,14 @@
21 assert result.exit_code == 0
22 assert "No repository found" in result.output
23
24 def test_export_repo_not_on_disk(self, runner, sample_project):
25 """Export when the .fossil file does not exist on disk."""
26 from fossil.models import FossilRepository
27
28 with patch.object(type(FossilRepository.objects.get(project=sample_project)), "exists_on_disk", new_callable=lambda: property(lambda self: False)):
29 result = runner.invoke(cli, ["bundle", "export", sample_project.slug, "/tmp/out.bundle"])
30 assert result.exit_code == 0
31 assert "not found on disk" in result.output
32
33 def test_export_fossil_not_available(self, runner, sample_project):
34 """Export when fossil binary is not found."""
35
--- tests/test_releases.py
+++ tests/test_releases.py
@@ -365,7 +365,7 @@
365365
class TestDraftSourceArchiveAccess:
366366
def test_draft_source_archive_denied_for_non_writer(self, no_perm_client, sample_project, draft_release):
367367
"""Non-writers cannot download source archives for draft releases."""
368368
sample_project.visibility = "public"
369369
sample_project.save()
370
- response = no_perm_client.get(f"/projects/{sample_project.slug}/fossil/releases/{draft_release.tag_name}/source/tar.gz")
370
+ response = no_perm_client.get(f"/projects/{sample_project.slug}/fossil/releases/{draft_release.tag_name}/source.tar.gz")
371371
assert response.status_code == 403
372372
--- tests/test_releases.py
+++ tests/test_releases.py
@@ -365,7 +365,7 @@
365 class TestDraftSourceArchiveAccess:
366 def test_draft_source_archive_denied_for_non_writer(self, no_perm_client, sample_project, draft_release):
367 """Non-writers cannot download source archives for draft releases."""
368 sample_project.visibility = "public"
369 sample_project.save()
370 response = no_perm_client.get(f"/projects/{sample_project.slug}/fossil/releases/{draft_release.tag_name}/source/tar.gz")
371 assert response.status_code == 403
372
--- tests/test_releases.py
+++ tests/test_releases.py
@@ -365,7 +365,7 @@
365 class TestDraftSourceArchiveAccess:
366 def test_draft_source_archive_denied_for_non_writer(self, no_perm_client, sample_project, draft_release):
367 """Non-writers cannot download source archives for draft releases."""
368 sample_project.visibility = "public"
369 sample_project.save()
370 response = no_perm_client.get(f"/projects/{sample_project.slug}/fossil/releases/{draft_release.tag_name}/source.tar.gz")
371 assert response.status_code == 403
372

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button