FossilRepo
Fix fossil http proxy: remove GATEWAY_INTERFACE that broke CGI mode, add Basic Auth for push/pull
Commit
313537cc4cf40a7ae09927af30fa28e2d5963d002ac6046304d183844ef0fee5
Parent
c2dd86c08bde705…
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 | ||
| 1 | 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 |
| --- __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 @@ | ||
| 3 | 3 | |
| 4 | 4 | from organization.models import Organization, OrganizationMember, Team |
| 5 | 5 | from pages.models import Page |
| 6 | 6 | from projects.models import Project, ProjectTeam |
| 7 | 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 | + | |
| 8 | 27 | |
| 9 | 28 | @pytest.fixture |
| 10 | 29 | def admin_user(db): |
| 11 | 30 | user = User.objects.create_superuser(username="admin", email="[email protected]", password="testpass123") |
| 12 | 31 | return user |
| 13 | 32 |
| --- 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 | ||
| 1 | 1 |
| --- 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 | ||
| 1 | 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__/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 | ||
| 1 | 1 |
| --- 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 @@ | ||
| 409 | 409 | "CONTENT_TYPE": content_type, |
| 410 | 410 | "CONTENT_LENGTH": str(len(request_body)), |
| 411 | 411 | "PATH_INFO": "/xfer", |
| 412 | 412 | "SCRIPT_NAME": "", |
| 413 | 413 | "HTTP_HOST": "localhost", |
| 414 | - "GATEWAY_INTERFACE": "CGI/1.1", | |
| 415 | 414 | "SERVER_PROTOCOL": "HTTP/1.1", |
| 416 | 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) | |
| 417 | 419 | |
| 418 | 420 | cmd = [self.binary, "http", str(repo_path)] |
| 419 | 421 | if localauth: |
| 420 | 422 | cmd.append("--localauth") |
| 421 | 423 | |
| 422 | 424 |
| --- 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 @@ | ||
| 304 | 304 | |
| 305 | 305 | def test_full_path(self, sample_project): |
| 306 | 306 | repo = FossilRepository.objects.get(project=sample_project) |
| 307 | 307 | assert repo.full_path.name == repo.filename |
| 308 | 308 | |
| 309 | - def test_exists_on_disk_false(self, sample_project): | |
| 309 | + def test_exists_on_disk(self, sample_project): | |
| 310 | 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 | |
| 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 | |
| 313 | 319 | |
| 314 | 320 | |
| 315 | 321 | # --- View tests --- |
| 316 | 322 | |
| 317 | 323 | |
| 318 | 324 |
| --- 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 |
+8
-8
| --- templates/accounts/profile.html | ||
| +++ templates/accounts/profile.html | ||
| @@ -18,11 +18,11 @@ | ||
| 18 | 18 | {% endif %} |
| 19 | 19 | <span>{{ user.email }}</span> |
| 20 | 20 | </div> |
| 21 | 21 | </div> |
| 22 | 22 | </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"> | |
| 24 | 24 | <a href="{% url 'accounts:profile_edit' %}" |
| 25 | 25 | class="rounded-md bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-200 hover:bg-gray-600"> |
| 26 | 26 | Edit Profile |
| 27 | 27 | </a> |
| 28 | 28 | <a href="{% url 'organization:user_password' username=user.username %}" |
| @@ -74,14 +74,14 @@ | ||
| 74 | 74 | <a href="{% url 'accounts:ssh_keys' %}" class="text-sm text-brand-light hover:text-brand">Manage Keys</a> |
| 75 | 75 | </div> |
| 76 | 76 | {% if ssh_keys %} |
| 77 | 77 | <div class="divide-y divide-gray-700"> |
| 78 | 78 | {% 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"> | |
| 81 | 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> | |
| 82 | + <div class="text-xs text-gray-500 font-mono mt-1 truncate">{{ key.fingerprint }}</div> | |
| 83 | 83 | <div class="text-xs text-gray-500 mt-1"> |
| 84 | 84 | {{ key.key_type|upper }} · Added {{ key.created_at|timesince }} ago |
| 85 | 85 | {% if key.last_used_at %}· Last used {{ key.last_used_at|timesince }} ago{% endif %} |
| 86 | 86 | </div> |
| 87 | 87 | </div> |
| @@ -132,15 +132,15 @@ | ||
| 132 | 132 | </a> |
| 133 | 133 | </div> |
| 134 | 134 | {% if tokens %} |
| 135 | 135 | <div class="divide-y divide-gray-700"> |
| 136 | 136 | {% 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"> | |
| 139 | 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"> | |
| 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 | 142 | Scopes: {{ token.scopes }} · Created {{ token.created_at|timesince }} ago |
| 143 | 143 | {% if token.last_used_at %}· Last used {{ token.last_used_at|timesince }} ago{% endif %} |
| 144 | 144 | {% if token.expires_at %}· Expires {{ token.expires_at|date:"M j, Y" }}{% endif %} |
| 145 | 145 | </div> |
| 146 | 146 | </div> |
| 147 | 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 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 }} · Added {{ key.created_at|timesince }} ago |
| 85 | {% if key.last_used_at %}· 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 }} · Created {{ token.created_at|timesince }} ago |
| 143 | {% if token.last_used_at %}· Last used {{ token.last_used_at|timesince }} ago{% endif %} |
| 144 | {% if token.expires_at %}· 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 }} · Added {{ key.created_at|timesince }} ago |
| 85 | {% if key.last_used_at %}· 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 }} · Created {{ token.created_at|timesince }} ago |
| 143 | {% if token.last_used_at %}· Last used {{ token.last_used_at|timesince }} ago{% endif %} |
| 144 | {% if token.expires_at %}· Expires {{ token.expires_at|date:"M j, Y" }}{% endif %} |
| 145 | </div> |
| 146 | </div> |
| 147 |
+3
| --- templates/base.html | ||
| +++ templates/base.html | ||
| @@ -45,10 +45,13 @@ | ||
| 45 | 45 | focus:border-brand focus:ring-brand sm:text-sm; |
| 46 | 46 | } |
| 47 | 47 | } |
| 48 | 48 | </style> |
| 49 | 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; } | |
| 50 | 53 | /* Focus visible outlines for keyboard navigation */ |
| 51 | 54 | a:focus-visible, button:focus-visible, [role="button"]:focus-visible { |
| 52 | 55 | outline: 2px solid #DC394C; |
| 53 | 56 | outline-offset: 2px; |
| 54 | 57 | border-radius: 4px; |
| 55 | 58 |
| --- 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 |
+1
-1
| --- templates/dashboard.html | ||
| +++ templates/dashboard.html | ||
| @@ -75,11 +75,11 @@ | ||
| 75 | 75 | <div class="w-2.5 h-2.5 rounded-full bg-brand"></div> |
| 76 | 76 | </div> |
| 77 | 77 | <div class="flex-1 min-w-0"> |
| 78 | 78 | <a href="{% url 'fossil:checkin_detail' slug=item.project.slug checkin_uuid=item.entry.uuid %}" |
| 79 | 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"> | |
| 80 | + <div class="mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-gray-500"> | |
| 81 | 81 | <a href="{% url 'projects:detail' slug=item.project.slug %}" class="text-brand-light hover:text-brand">{{ item.project.name }}</a> |
| 82 | 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 | 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 | 84 | <span>{{ item.entry.timestamp|timesince }} ago</span> |
| 85 | 85 | </div> |
| 86 | 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 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 |
+13
-13
| --- 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"> | |
| 2 | 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 %}"> | |
| 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 | 4 | Overview |
| 5 | 5 | </a> |
| 6 | 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 %}"> | |
| 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 | 8 | Code |
| 9 | 9 | </a> |
| 10 | 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 %}"> | |
| 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 | 12 | Branches |
| 13 | 13 | </a> |
| 14 | 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 %}"> | |
| 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 | 16 | Timeline |
| 17 | 17 | </a> |
| 18 | 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 %}"> | |
| 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 | 20 | Tickets |
| 21 | 21 | </a> |
| 22 | 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 %}"> | |
| 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 | 24 | Wiki |
| 25 | 25 | </a> |
| 26 | 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 %}"> | |
| 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 | 28 | Forum |
| 29 | 29 | </a> |
| 30 | 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 %}"> | |
| 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 | 32 | Releases |
| 33 | 33 | </a> |
| 34 | 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 %}"> | |
| 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 | 36 | Files |
| 37 | 37 | </a> |
| 38 | 38 | {% if perms.projects.change_project %} |
| 39 | 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 %}"> | |
| 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 | 41 | {% if fossil_repo.remote_url %}Sync{% else %}Setup Sync{% endif %} |
| 42 | 42 | </a> |
| 43 | 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 %}"> | |
| 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 | 45 | Settings |
| 46 | 46 | </a> |
| 47 | 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 %}"> | |
| 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 | 49 | Explorer |
| 50 | 50 | </a> |
| 51 | 51 | {% endif %} |
| 52 | 52 | </nav> |
| 53 | 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"> |
| 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 @@ | ||
| 25 | 25 | </span> |
| 26 | 26 | </div> |
| 27 | 27 | </div> |
| 28 | 28 | |
| 29 | 29 | <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"> | |
| 31 | 31 | <table class="min-w-full divide-y divide-gray-700"> |
| 32 | 32 | <thead class="bg-gray-900"> |
| 33 | 33 | <tr> |
| 34 | 34 | <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Branch</th> |
| 35 | 35 | <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Last Checkin</th> |
| 36 | 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"> |
| 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 @@ | ||
| 18 | 18 | .diff-gutter a { color: inherit; text-decoration: none; display: block; } |
| 19 | 19 | .line-row:target { background: rgba(220, 57, 76, 0.15) !important; } |
| 20 | 20 | .line-row:target .diff-gutter { color: #DC394C; font-weight: 600; } |
| 21 | 21 | .line-row { scroll-margin-top: 40vh; } |
| 22 | 22 | /* 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; } } | |
| 24 | 25 | .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; } } | |
| 26 | 28 | .split-diff-side .diff-table td:last-child { width: 100%; } |
| 27 | 29 | .split-line-add { background: rgba(34, 197, 94, 0.1); } |
| 28 | 30 | .split-line-add td:last-child { color: #86efac; } |
| 29 | 31 | .split-line-del { background: rgba(239, 68, 68, 0.1); } |
| 30 | 32 | .split-line-del td:last-child { color: #fca5a5; } |
| @@ -57,11 +59,11 @@ | ||
| 57 | 59 | <div class="space-y-4"> |
| 58 | 60 | <!-- Commit header --> |
| 59 | 61 | <div class="rounded-lg bg-gray-800 border border-gray-700"> |
| 60 | 62 | <div class="px-6 py-5"> |
| 61 | 63 | <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"> | |
| 63 | 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> |
| 64 | 66 | <span class="text-gray-500">{{ checkin.timestamp|date:"Y-m-d H:i" }}</span> |
| 65 | 67 | {% if checkin.branch %} |
| 66 | 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"> |
| 67 | 69 | {{ checkin.branch }} |
| @@ -76,11 +78,11 @@ | ||
| 76 | 78 | <div class="px-6 py-3 border-t border-gray-700 bg-gray-800/50"> |
| 77 | 79 | <div class="flex items-center gap-2 mb-2"> |
| 78 | 80 | <span class="text-xs font-medium text-gray-400">CI Status</span> |
| 79 | 81 | <img src="{% url 'fossil:status_badge' slug=project.slug checkin_uuid=checkin.uuid %}" alt="CI Status" class="h-5"> |
| 80 | 82 | </div> |
| 81 | - <div class="flex flex-wrap gap-2"> | |
| 83 | + <div class="flex flex-wrap gap-x-2 gap-y-1.5"> | |
| 82 | 84 | {% for check in status_checks %} |
| 83 | 85 | <a {% if check.target_url and check.target_url|slice:":4" == "http" %}href="{{ check.target_url }}" target="_blank" rel="noopener"{% endif %} |
| 84 | 86 | class="inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs |
| 85 | 87 | {% if check.state == 'success' %}border-green-800 bg-green-900/30 text-green-300 |
| 86 | 88 | {% elif check.state == 'failure' %}border-red-800 bg-red-900/30 text-red-300 |
| @@ -104,11 +106,11 @@ | ||
| 104 | 106 | </a> |
| 105 | 107 | {% endfor %} |
| 106 | 108 | </div> |
| 107 | 109 | </div> |
| 108 | 110 | {% 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"> | |
| 110 | 112 | <div class="flex items-center gap-2"> |
| 111 | 113 | <span class="text-gray-500">Commit</span> |
| 112 | 114 | <code class="font-mono text-gray-300 break-all">{{ checkin.uuid }}</code> |
| 113 | 115 | </div> |
| 114 | 116 | {% if checkin.parent_uuid %} |
| @@ -135,13 +137,13 @@ | ||
| 135 | 137 | <span class="text-red-400">-{{ fd.deletions }}</span> |
| 136 | 138 | {% endif %} |
| 137 | 139 | {% endfor %} |
| 138 | 140 | {% endwith %} |
| 139 | 141 | </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"> | |
| 141 | 143 | {% 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"> | |
| 143 | 145 | {% if fd.change_type == "added" %} |
| 144 | 146 | <span class="text-green-400">+</span> |
| 145 | 147 | {% elif fd.change_type == "deleted" %} |
| 146 | 148 | <span class="text-red-400">-</span> |
| 147 | 149 | {% else %} |
| 148 | 150 |
| --- 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 @@ | ||
| 33 | 33 | {% endif %} |
| 34 | 34 | </div> |
| 35 | 35 | |
| 36 | 36 | <!-- Latest commit info --> |
| 37 | 37 | {% 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"> | |
| 39 | 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 | 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 | 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 | 42 | <span>{{ latest_commit.timestamp|date:"Y-m-d H:i" }}</span> |
| 43 | 43 | </div> |
| 44 | 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 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 |
+3
-3
| --- templates/fossil/code_file.html | ||
| +++ templates/fossil/code_file.html | ||
| @@ -43,12 +43,12 @@ | ||
| 43 | 43 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 44 | 44 | {% include "fossil/_project_nav.html" %} |
| 45 | 45 | |
| 46 | 46 | <div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700"> |
| 47 | 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"> | |
| 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 | 50 | <a href="{% url 'fossil:code' slug=project.slug %}" class="text-brand-light hover:text-brand">{{ project.slug }}</a> |
| 51 | 51 | {% for crumb in file_breadcrumbs %} |
| 52 | 52 | <span class="text-gray-600">/</span> |
| 53 | 53 | {% if forloop.last %} |
| 54 | 54 | <span class="text-gray-200">{{ crumb.name }}</span> |
| @@ -55,11 +55,11 @@ | ||
| 55 | 55 | {% else %} |
| 56 | 56 | <a href="{% url 'fossil:code_dir' slug=project.slug dirpath=crumb.path %}" class="text-brand-light hover:text-brand">{{ crumb.name }}</a> |
| 57 | 57 | {% endif %} |
| 58 | 58 | {% endfor %} |
| 59 | 59 | </div> |
| 60 | - <div class="flex items-center gap-3"> | |
| 60 | + <div class="flex flex-wrap items-center gap-2"> | |
| 61 | 61 | {% if can_render %} |
| 62 | 62 | <div class="flex items-center gap-1 text-xs"> |
| 63 | 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 | 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 | 65 | </div> |
| 66 | 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-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 |
+6
-4
| --- templates/fossil/compare.html | ||
| +++ templates/fossil/compare.html | ||
| @@ -13,13 +13,15 @@ | ||
| 13 | 13 | .diff-line-hunk { background: rgba(96, 165, 250, 0.08); } |
| 14 | 14 | .diff-line-hunk td { color: #93c5fd; } |
| 15 | 15 | .diff-line-header td { color: #6b7280; } |
| 16 | 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 | 17 | /* 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; } } | |
| 19 | 20 | .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; } } | |
| 21 | 23 | .split-diff-side .diff-table td:last-child { width: 100%; } |
| 22 | 24 | .split-line-add { background: rgba(34, 197, 94, 0.1); } |
| 23 | 25 | .split-line-add td:last-child { color: #86efac; } |
| 24 | 26 | .split-line-del { background: rgba(239, 68, 68, 0.1); } |
| 25 | 27 | .split-line-del td:last-child { color: #fca5a5; } |
| @@ -35,11 +37,11 @@ | ||
| 35 | 37 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 36 | 38 | {% include "fossil/_project_nav.html" %} |
| 37 | 39 | |
| 38 | 40 | <div class="mb-6"> |
| 39 | 41 | <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"> | |
| 41 | 43 | <div class="flex-1"> |
| 42 | 44 | <label class="block text-xs text-gray-500 mb-1">From (older)</label> |
| 43 | 45 | <input type="text" name="from" value="{{ from_uuid }}" placeholder="Checkin hash..." |
| 44 | 46 | aria-label="From checkin hash" |
| 45 | 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 @@ | ||
| 53 | 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> |
| 54 | 56 | </form> |
| 55 | 57 | </div> |
| 56 | 58 | |
| 57 | 59 | {% 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"> | |
| 59 | 61 | <div class="rounded-lg bg-gray-800 border border-gray-700 p-4"> |
| 60 | 62 | <div class="text-xs text-gray-500 mb-1">From</div> |
| 61 | 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> |
| 62 | 64 | <div class="mt-1 text-xs text-gray-500">{{ from_detail.user|display_user }} · {{ from_detail.timestamp|date:"Y-m-d H:i" }}</div> |
| 63 | 65 | </div> |
| 64 | 66 |
| --- 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 }} · {{ 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 }} · {{ from_detail.timestamp|date:"Y-m-d H:i" }}</div> |
| 65 | </div> |
| 66 |
+2
-2
| --- templates/fossil/forum_list.html | ||
| +++ templates/fossil/forum_list.html | ||
| @@ -4,13 +4,13 @@ | ||
| 4 | 4 | |
| 5 | 5 | {% block content %} |
| 6 | 6 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 7 | 7 | {% include "fossil/_project_nav.html" %} |
| 8 | 8 | |
| 9 | -<div class="flex items-center justify-between mb-6"> | |
| 9 | +<div class="flex flex-wrap items-center justify-between gap-3 mb-6"> | |
| 10 | 10 | <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"> | |
| 12 | 12 | <span class="search-wrap"> |
| 13 | 13 | <input type="search" |
| 14 | 14 | name="search" |
| 15 | 15 | value="{{ search }}" |
| 16 | 16 | placeholder="Search forum..." |
| 17 | 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 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"> | |
| 2 | 2 | {% if tree %} |
| 3 | 3 | <table class="min-w-full"> |
| 4 | 4 | <tbody class="divide-y divide-gray-700"> |
| 5 | 5 | {% for entry in tree %} |
| 6 | 6 | <tr class="hover:bg-gray-700/30"> |
| 7 | 7 |
| --- 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 @@ | ||
| 1 | 1 | <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"> | |
| 3 | 3 | <table class="min-w-full divide-y divide-gray-700"> |
| 4 | 4 | <thead class="bg-gray-900"> |
| 5 | 5 | <tr> |
| 6 | 6 | <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Title</th> |
| 7 | 7 | <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400 w-24">Status</th> |
| 8 | 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-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 @@ | ||
| 27 | 27 | top: 20%; border-radius: 4px 4px 0 0; |
| 28 | 28 | border-top: 2px solid; border-left: 2px solid; border-right: 2px solid; |
| 29 | 29 | border-bottom: none; height: 30%; opacity: 0.5; |
| 30 | 30 | } |
| 31 | 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; } | |
| 32 | + .tl-row { display: flex; min-height: 28px; align-items: center; flex-wrap: wrap; } | |
| 33 | 33 | .tl-row:hover { background: rgba(255,255,255,0.02); } |
| 34 | 34 | .tl-time { width: 42px; flex-shrink: 0; text-align: right; font-size: 0.75rem; color: #6b7280; font-variant-numeric: tabular-nums; } |
| 35 | 35 | .tl-msg { flex: 1; min-width: 0; font-size: 0.8125rem; color: #e5e5e5; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } |
| 36 | 36 | .tl-msg a { color: #e5e5e5; text-decoration: none; } |
| 37 | 37 | .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 | + } | |
| 39 | 44 | .tl-hash { font-family: ui-monospace, monospace; font-size: 0.7rem; color: #DC394C; text-decoration: none; } |
| 40 | 45 | .tl-hash:hover { color: #e8677a; text-decoration: underline; } |
| 41 | 46 | .tl-user { font-size: 0.7rem; color: #9ca3af; text-decoration: none; } |
| 42 | 47 | .tl-user:hover { color: #e8677a; } |
| 43 | 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; } |
| 44 | 49 |
| --- 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 @@ | ||
| 4 | 4 | |
| 5 | 5 | {% block content %} |
| 6 | 6 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 7 | 7 | {% include "fossil/_project_nav.html" %} |
| 8 | 8 | |
| 9 | -<div class="flex items-center justify-between mb-6"> | |
| 9 | +<div class="flex flex-wrap items-center justify-between gap-3 mb-6"> | |
| 10 | 10 | <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"> | |
| 12 | 12 | <span class="search-wrap"> |
| 13 | 13 | <input type="search" |
| 14 | 14 | name="search" |
| 15 | 15 | value="{{ search }}" |
| 16 | 16 | placeholder="Search releases..." |
| 17 | 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 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 @@ | ||
| 105 | 105 | </div> |
| 106 | 106 | |
| 107 | 107 | <!-- Actions --> |
| 108 | 108 | <div class="rounded-lg bg-gray-800 border border-gray-700 p-5"> |
| 109 | 109 | <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"> | |
| 111 | 111 | <form method="post"> |
| 112 | 112 | {% csrf_token %} |
| 113 | 113 | <input type="hidden" name="action" value="sync_metadata"> |
| 114 | 114 | <button type="submit" |
| 115 | 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 | 176 | |
| 177 | 177 | <!-- Danger Zone --> |
| 178 | 178 | <div class="rounded-lg border-2 border-red-900/50 p-5"> |
| 179 | 179 | <h2 class="text-lg font-semibold text-red-400 mb-2">Danger Zone</h2> |
| 180 | 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"> | |
| 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 | 182 | <div> |
| 183 | 183 | <p class="text-sm font-medium text-gray-200">Delete this repository</p> |
| 184 | 184 | <p class="text-xs text-gray-500">Permanently removes the .fossil file and all associated data.</p> |
| 185 | 185 | </div> |
| 186 | 186 | <button disabled |
| 187 | 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-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 |
+1
-1
| --- templates/fossil/search.html | ||
| +++ templates/fossil/search.html | ||
| @@ -5,11 +5,11 @@ | ||
| 5 | 5 | {% block content %} |
| 6 | 6 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 7 | 7 | {% include "fossil/_project_nav.html" %} |
| 8 | 8 | |
| 9 | 9 | <form method="get" class="mb-6"> |
| 10 | - <div class="flex gap-2"> | |
| 10 | + <div class="flex flex-col sm:flex-row gap-2"> | |
| 11 | 11 | <input type="text" name="q" value="{{ query }}" placeholder="Search checkins, tickets, wiki..." |
| 12 | 12 | aria-label="Search repository" |
| 13 | 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 | 14 | autofocus> |
| 15 | 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 | 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 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 |
+1
-1
| --- templates/fossil/tag_list.html | ||
| +++ templates/fossil/tag_list.html | ||
| @@ -25,11 +25,11 @@ | ||
| 25 | 25 | </span> |
| 26 | 26 | </div> |
| 27 | 27 | </div> |
| 28 | 28 | |
| 29 | 29 | <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"> | |
| 31 | 31 | <table class="min-w-full divide-y divide-gray-700"> |
| 32 | 32 | <thead class="bg-gray-900"> |
| 33 | 33 | <tr> |
| 34 | 34 | <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Tag</th> |
| 35 | 35 | <th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-400">Checkin</th> |
| 36 | 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-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 @@ | ||
| 5 | 5 | {% block content %} |
| 6 | 6 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 7 | 7 | {% include "fossil/_project_nav.html" %} |
| 8 | 8 | |
| 9 | 9 | <div class="mb-4"> |
| 10 | - <a href="{% url 'fossil:tickets' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">← Back to tickets</a> | |
| 10 | + <a href="{% url 'fossil:tickets' slug=project.slug %}" class="text-sm text-brand-light hover:text-brand">← Back to Tickets</a> | |
| 11 | 11 | </div> |
| 12 | 12 | |
| 13 | 13 | <div class="overflow-hidden rounded-lg bg-gray-800 shadow border border-gray-700"> |
| 14 | 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> | |
| 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 | 18 | </div> |
| 19 | 19 | <div class="flex items-center gap-2 flex-shrink-0"> |
| 20 | 20 | {% if perms.projects.change_project %} |
| 21 | 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 | 22 | {% endif %} |
| @@ -35,11 +35,11 @@ | ||
| 35 | 35 | </p> |
| 36 | 36 | </div> |
| 37 | 37 | |
| 38 | 38 | <!-- Metadata grid --> |
| 39 | 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"> | |
| 40 | + <dl class="grid grid-cols-1 gap-x-6 gap-y-3 sm:grid-cols-2 lg:grid-cols-4"> | |
| 41 | 41 | <div> |
| 42 | 42 | <dt class="text-xs font-medium text-gray-500 uppercase">Type</dt> |
| 43 | 43 | <dd class="mt-0.5 text-sm text-gray-200">{{ ticket.type|default:"—" }}</dd> |
| 44 | 44 | </div> |
| 45 | 45 | <div> |
| 46 | 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">← 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">← 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 @@ | ||
| 19 | 19 | <label class="block text-sm font-medium text-gray-300 mb-1">Title <span class="text-red-400">*</span></label> |
| 20 | 20 | <input type="text" name="title" required placeholder="Ticket title" |
| 21 | 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 | 22 | </div> |
| 23 | 23 | |
| 24 | - <div class="grid grid-cols-2 gap-4"> | |
| 24 | + <div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> | |
| 25 | 25 | <div> |
| 26 | 26 | <label class="block text-sm font-medium text-gray-300 mb-1">Type</label> |
| 27 | 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 | 28 | <option value="Code_Defect">Code Defect</option> |
| 29 | 29 | <option value="Feature_Request">Feature Request</option> |
| @@ -50,11 +50,11 @@ | ||
| 50 | 50 | </div> |
| 51 | 51 | |
| 52 | 52 | {% if custom_fields %} |
| 53 | 53 | <div class="border-t border-gray-700 pt-4 mt-4"> |
| 54 | 54 | <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"> | |
| 56 | 56 | {% for cf in custom_fields %} |
| 57 | 57 | <div{% if cf.field_type == "textarea" %} class="col-span-2"{% endif %}> |
| 58 | 58 | <label class="block text-sm font-medium text-gray-300 mb-1"> |
| 59 | 59 | {{ cf.label }} |
| 60 | 60 | {% if cf.is_required %}<span class="text-red-400">*</span>{% endif %} |
| 61 | 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-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 @@ | ||
| 4 | 4 | {% block content %} |
| 5 | 5 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 6 | 6 | {% include "fossil/_project_nav.html" %} |
| 7 | 7 | |
| 8 | 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"> | |
| 9 | + <div class="flex flex-wrap items-center gap-2 text-xs text-gray-500"> | |
| 10 | 10 | <span>Status:</span> |
| 11 | 11 | <a href="{% url 'fossil:tickets' slug=project.slug %}" |
| 12 | 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 | 13 | <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Open" |
| 14 | 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 | 15 | <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Fixed" |
| 16 | 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 | 17 | <a href="{% url 'fossil:tickets' slug=project.slug %}?status=Closed" |
| 18 | 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 | 19 | </div> |
| 20 | - <div class="flex items-center gap-3"> | |
| 20 | + <div class="flex flex-wrap items-center gap-3"> | |
| 21 | 21 | <a href="{% url 'fossil:tickets_csv' slug=project.slug %}" class="text-xs text-gray-500 hover:text-brand-light">Export CSV</a> |
| 22 | 22 | {% if perms.projects.change_project %} |
| 23 | 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 | 24 | {% endif %} |
| 25 | 25 | <span class="search-wrap"> |
| @@ -40,12 +40,12 @@ | ||
| 40 | 40 | </div> |
| 41 | 41 | </div> |
| 42 | 42 | |
| 43 | 43 | {% include "fossil/partials/ticket_table.html" %} |
| 44 | 44 | |
| 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"> | |
| 47 | 47 | <span class="text-gray-500">{{ total }} ticket{{ total|pluralize }}</span> |
| 48 | 48 | <div class="flex items-center gap-1 text-xs"> |
| 49 | 49 | <span class="text-gray-600">Show:</span> |
| 50 | 50 | {% for size in per_page_options %} |
| 51 | 51 | <a href="{% url 'fossil:tickets' slug=project.slug %}?per_page={{ size }}{% if status_filter %}&status={{ status_filter }}{% endif %}" |
| 52 | 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 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 |
+2
-2
| --- templates/fossil/timeline.html | ||
| +++ templates/fossil/timeline.html | ||
| @@ -4,12 +4,12 @@ | ||
| 4 | 4 | {% block content %} |
| 5 | 5 | {% include "fossil/_live_reload.html" %} |
| 6 | 6 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 7 | 7 | {% include "fossil/_project_nav.html" %} |
| 8 | 8 | |
| 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"> | |
| 11 | 11 | <span>Filter:</span> |
| 12 | 12 | <a href="{% url 'fossil:timeline' slug=project.slug %}" |
| 13 | 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 | 14 | <a href="{% url 'fossil:timeline' slug=project.slug %}?type=ci" |
| 15 | 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 | 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 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 @@ | ||
| 26 | 26 | </div> |
| 27 | 27 | </div> |
| 28 | 28 | |
| 29 | 29 | <div id="unversioned-content"> |
| 30 | 30 | {% 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"> | |
| 32 | 32 | <table class="min-w-full divide-y divide-gray-700"> |
| 33 | 33 | <thead class="bg-gray-900"> |
| 34 | 34 | <tr> |
| 35 | 35 | <th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Name</th> |
| 36 | 36 | <th class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Size</th> |
| 37 | 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-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 |
+1
-1
| --- templates/fossil/wiki_list.html | ||
| +++ templates/fossil/wiki_list.html | ||
| @@ -3,11 +3,11 @@ | ||
| 3 | 3 | |
| 4 | 4 | {% block content %} |
| 5 | 5 | <h1 class="text-2xl font-bold text-gray-100 mb-2">{{ project.name }}</h1> |
| 6 | 6 | {% include "fossil/_project_nav.html" %} |
| 7 | 7 | |
| 8 | -<div class="flex items-center justify-between mb-4"> | |
| 8 | +<div class="flex flex-wrap items-center justify-between gap-3 mb-4"> | |
| 9 | 9 | <div> |
| 10 | 10 | <span class="search-wrap"> |
| 11 | 11 | <input type="search" |
| 12 | 12 | name="search" |
| 13 | 13 | value="{{ search }}" |
| 14 | 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 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 @@ | ||
| 9 | 9 | <p class="mt-1 text-sm text-gray-400">History of changes across all tracked models.</p> |
| 10 | 10 | </div> |
| 11 | 11 | </div> |
| 12 | 12 | |
| 13 | 13 | <!-- Filter by model type --> |
| 14 | -<div class="flex gap-2 mb-6"> | |
| 14 | +<div class="flex flex-wrap gap-2 mb-6"> | |
| 15 | 15 | <a href="{% url 'organization:audit_log' %}" |
| 16 | 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 | 17 | All |
| 18 | 18 | </a> |
| 19 | 19 | {% for model_name in available_models %} |
| @@ -23,11 +23,11 @@ | ||
| 23 | 23 | </a> |
| 24 | 24 | {% endfor %} |
| 25 | 25 | </div> |
| 26 | 26 | |
| 27 | 27 | <!-- 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"> | |
| 29 | 29 | <table class="min-w-full divide-y divide-gray-700"> |
| 30 | 30 | <thead class="bg-gray-900"> |
| 31 | 31 | <tr> |
| 32 | 32 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Date</th> |
| 33 | 33 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">User</th> |
| 34 | 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 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 @@ | ||
| 1 | 1 | <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"> | |
| 3 | 3 | <table class="min-w-full divide-y divide-gray-700"> |
| 4 | 4 | <thead class="bg-gray-900"> |
| 5 | 5 | <tr> |
| 6 | 6 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Username</th> |
| 7 | 7 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Email</th> |
| 8 | 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-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 @@ | ||
| 1 | 1 | <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"> | |
| 3 | 3 | <table class="min-w-full divide-y divide-gray-700"> |
| 4 | 4 | <thead class="bg-gray-900"> |
| 5 | 5 | <tr> |
| 6 | 6 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Username</th> |
| 7 | 7 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Email</th> |
| 8 | 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-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 @@ | ||
| 1 | 1 | <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"> | |
| 3 | 3 | <table class="min-w-full divide-y divide-gray-700"> |
| 4 | 4 | <thead class="bg-gray-900"> |
| 5 | 5 | <tr> |
| 6 | 6 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th> |
| 7 | 7 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Members</th> |
| 8 | 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-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 @@ | ||
| 1 | 1 | <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"> | |
| 3 | 3 | <table class="min-w-full divide-y divide-gray-700"> |
| 4 | 4 | <thead class="bg-gray-900"> |
| 5 | 5 | <tr> |
| 6 | 6 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Title</th> |
| 7 | 7 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Status</th> |
| 8 | 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-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 |
+1
-1
| --- templates/projects/explore.html | ||
| +++ templates/projects/explore.html | ||
| @@ -25,11 +25,11 @@ | ||
| 25 | 25 | <button type="submit" |
| 26 | 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 | 27 | Search |
| 28 | 28 | </button> |
| 29 | 29 | </form> |
| 30 | - <div class="flex gap-2"> | |
| 30 | + <div class="flex flex-wrap gap-2"> | |
| 31 | 31 | <a href="{% url 'explore' %}?sort=stars{% if search %}&search={{ search }}{% endif %}" |
| 32 | 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 | 33 | Stars |
| 34 | 34 | </a> |
| 35 | 35 | <a href="{% url 'explore' %}?sort=recent{% if search %}&search={{ search }}{% endif %}" |
| 36 | 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 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 @@ | ||
| 1 | 1 | <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"> | |
| 3 | 3 | <table class="min-w-full divide-y divide-gray-700"> |
| 4 | 4 | <thead class="bg-gray-900"> |
| 5 | 5 | <tr> |
| 6 | 6 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th> |
| 7 | 7 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Description</th> |
| 8 | 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-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 @@ | ||
| 1 | 1 | <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"> | |
| 3 | 3 | <table class="min-w-full divide-y divide-gray-700"> |
| 4 | 4 | <thead class="bg-gray-900"> |
| 5 | 5 | <tr> |
| 6 | 6 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Name</th> |
| 7 | 7 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Visibility</th> |
| 8 | 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-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 @@ | ||
| 1 | 1 | <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"> | |
| 3 | 3 | <table class="min-w-full divide-y divide-gray-700"> |
| 4 | 4 | <thead class="bg-gray-900"> |
| 5 | 5 | <tr> |
| 6 | 6 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Team</th> |
| 7 | 7 | <th class="px-6 py-3 text-left text-xs font-medium uppercase text-gray-400">Role</th> |
| 8 | 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-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 @@ | ||
| 72 | 72 | <div class="w-2.5 h-2.5 rounded-full bg-brand"></div> |
| 73 | 73 | </div> |
| 74 | 74 | <div class="flex-1 min-w-0"> |
| 75 | 75 | <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=commit.uuid %}" |
| 76 | 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"> | |
| 77 | + <div class="mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-gray-500"> | |
| 78 | 78 | <span>{{ commit.user|display_user }}</span> |
| 79 | 79 | <a href="{% url 'fossil:checkin_detail' slug=project.slug checkin_uuid=commit.uuid %}" |
| 80 | 80 | class="font-mono text-brand-light hover:text-brand">{{ commit.uuid|truncatechars:10 }}</a> |
| 81 | 81 | <span>{{ commit.timestamp|timesince }} ago</span> |
| 82 | 82 | </div> |
| 83 | 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 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 @@ | ||
| 1 | 1 | {% extends "base.html" %} |
| 2 | 2 | {% block title %}Projects — Fossilrepo{% endblock %} |
| 3 | 3 | |
| 4 | 4 | {% 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"> | |
| 6 | 6 | <h1 class="text-2xl font-bold text-gray-100">Projects</h1> |
| 7 | 7 | {% if perms.projects.add_project %} |
| 8 | 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"> | |
| 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 | 10 | New Project |
| 11 | 11 | </a> |
| 12 | 12 | {% endif %} |
| 13 | 13 | </div> |
| 14 | 14 | |
| 15 | 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="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 | ||
| 1 | 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_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 | ||
| 1 | 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_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 | ||
| 1 | 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/__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 |
+3
-3
| --- tests/test_agent_coordination.py | ||
| +++ tests/test_agent_coordination.py | ||
| @@ -693,21 +693,21 @@ | ||
| 693 | 693 | |
| 694 | 694 | |
| 695 | 695 | @pytest.mark.django_db |
| 696 | 696 | class TestCodeReviewComment: |
| 697 | 697 | 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.""" | |
| 699 | 699 | review = CodeReview.objects.create(repository=fossil_repo_obj, title="Fix", diff="d", created_by=admin_user) |
| 700 | 700 | |
| 701 | 701 | response = admin_client.post( |
| 702 | 702 | _api_url(sample_project.slug, f"api/reviews/{review.pk}/comment"), |
| 703 | 703 | data=json.dumps( |
| 704 | 704 | { |
| 705 | 705 | "body": "Consider using a guard clause here", |
| 706 | 706 | "file_path": "src/auth.py", |
| 707 | 707 | "line_number": 42, |
| 708 | - "author": "human-reviewer", | |
| 708 | + "author": "human-reviewer", # ignored — author comes from auth context | |
| 709 | 709 | } |
| 710 | 710 | ), |
| 711 | 711 | content_type="application/json", |
| 712 | 712 | ) |
| 713 | 713 | |
| @@ -714,11 +714,11 @@ | ||
| 714 | 714 | assert response.status_code == 201 |
| 715 | 715 | data = response.json() |
| 716 | 716 | assert data["body"] == "Consider using a guard clause here" |
| 717 | 717 | assert data["file_path"] == "src/auth.py" |
| 718 | 718 | assert data["line_number"] == 42 |
| 719 | - assert data["author"] == "human-reviewer" | |
| 719 | + assert data["author"] == "admin" # session user's username, not caller-supplied | |
| 720 | 720 | |
| 721 | 721 | # Verify DB |
| 722 | 722 | assert ReviewComment.objects.filter(review=review).count() == 1 |
| 723 | 723 | |
| 724 | 724 | def test_add_comment_infers_author_from_user(self, admin_client, sample_project, fossil_repo_obj, admin_user): |
| 725 | 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.""" |
| 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 |
+4
-1
| --- tests/test_bundle_cli.py | ||
| +++ tests/test_bundle_cli.py | ||
| @@ -21,11 +21,14 @@ | ||
| 21 | 21 | assert result.exit_code == 0 |
| 22 | 22 | assert "No repository found" in result.output |
| 23 | 23 | |
| 24 | 24 | def test_export_repo_not_on_disk(self, runner, sample_project): |
| 25 | 25 | """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"]) | |
| 27 | 30 | assert result.exit_code == 0 |
| 28 | 31 | assert "not found on disk" in result.output |
| 29 | 32 | |
| 30 | 33 | def test_export_fossil_not_available(self, runner, sample_project): |
| 31 | 34 | """Export when fossil binary is not found.""" |
| 32 | 35 |
| --- 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 |
+1
-1
| --- tests/test_releases.py | ||
| +++ tests/test_releases.py | ||
| @@ -365,7 +365,7 @@ | ||
| 365 | 365 | class TestDraftSourceArchiveAccess: |
| 366 | 366 | def test_draft_source_archive_denied_for_non_writer(self, no_perm_client, sample_project, draft_release): |
| 367 | 367 | """Non-writers cannot download source archives for draft releases.""" |
| 368 | 368 | sample_project.visibility = "public" |
| 369 | 369 | 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") | |
| 371 | 371 | assert response.status_code == 403 |
| 372 | 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 |
| --- 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 |