|
c588255…
|
ragelink
|
1 |
{% extends "base.html" %} |
|
c588255…
|
ragelink
|
2 |
{% block title %}Profile — Fossilrepo{% endblock %} |
|
c588255…
|
ragelink
|
3 |
|
|
c588255…
|
ragelink
|
4 |
{% block content %} |
|
c588255…
|
ragelink
|
5 |
<!-- Profile Header --> |
|
0e40dc2…
|
ragelink
|
6 |
<div class="sm:flex sm:items-center gap-5 mb-8"> |
|
0e40dc2…
|
ragelink
|
7 |
<div class="flex items-center gap-4 sm:gap-5 flex-1 min-w-0"> |
|
0e40dc2…
|
ragelink
|
8 |
<div class="flex-shrink-0 h-16 w-16 rounded-full bg-brand flex items-center justify-center text-white text-2xl font-bold"> |
|
0e40dc2…
|
ragelink
|
9 |
{{ user.username|make_list|first|upper }} |
|
0e40dc2…
|
ragelink
|
10 |
</div> |
|
0e40dc2…
|
ragelink
|
11 |
<div class="min-w-0"> |
|
0e40dc2…
|
ragelink
|
12 |
<h1 class="text-2xl font-bold text-gray-100 truncate"> |
|
0e40dc2…
|
ragelink
|
13 |
{% if user.get_full_name %}{{ user.get_full_name }}{% else %}{{ user.username }}{% endif %} |
|
0e40dc2…
|
ragelink
|
14 |
</h1> |
|
0e40dc2…
|
ragelink
|
15 |
<div class="flex items-center gap-3 mt-1 text-sm text-gray-400"> |
|
0e40dc2…
|
ragelink
|
16 |
{% if user_profile.handle %} |
|
0e40dc2…
|
ragelink
|
17 |
<span>@{{ user_profile.handle }}</span> |
|
0e40dc2…
|
ragelink
|
18 |
{% endif %} |
|
0e40dc2…
|
ragelink
|
19 |
<span>{{ user.email }}</span> |
|
0e40dc2…
|
ragelink
|
20 |
</div> |
|
0e40dc2…
|
ragelink
|
21 |
</div> |
|
0e40dc2…
|
ragelink
|
22 |
</div> |
|
313537c…
|
ragelink
|
23 |
<div class="flex flex-wrap items-center gap-2 mt-4 sm:mt-0"> |
|
afe42d0…
|
ragelink
|
24 |
<a href="{% url 'accounts:profile_edit' %}" |
|
2f13242…
|
ragelink
|
25 |
class="rounded-md bg-gray-700 px-4 py-2 text-sm font-semibold text-gray-200 hover:bg-gray-600 border border-gray-600 transition-colors"> |
|
afe42d0…
|
ragelink
|
26 |
Edit Profile |
|
afe42d0…
|
ragelink
|
27 |
</a> |
|
afe42d0…
|
ragelink
|
28 |
<a href="{% url 'organization:user_password' username=user.username %}" |
|
2f13242…
|
ragelink
|
29 |
class="rounded-md bg-gray-800 px-4 py-2 text-sm font-medium text-gray-400 hover:text-gray-200 hover:bg-gray-700 ring-1 ring-gray-700 transition-colors"> |
|
afe42d0…
|
ragelink
|
30 |
Change Password |
|
afe42d0…
|
ragelink
|
31 |
</a> |
|
afe42d0…
|
ragelink
|
32 |
</div> |
|
c588255…
|
ragelink
|
33 |
</div> |
|
c588255…
|
ragelink
|
34 |
|
|
c588255…
|
ragelink
|
35 |
<!-- Profile Info Card --> |
|
2f13242…
|
ragelink
|
36 |
<div class="rounded-lg bg-gray-800 border border-gray-700 p-6 mb-6 shadow-sm"> |
|
c588255…
|
ragelink
|
37 |
<h2 class="text-lg font-semibold text-gray-200 mb-4">Profile Info</h2> |
|
c588255…
|
ragelink
|
38 |
<dl class="grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-3 text-sm"> |
|
c588255…
|
ragelink
|
39 |
<div> |
|
c588255…
|
ragelink
|
40 |
<dt class="text-gray-500">Full Name</dt> |
|
c588255…
|
ragelink
|
41 |
<dd class="text-gray-200 mt-0.5">{{ user.get_full_name|default:"Not set" }}</dd> |
|
c588255…
|
ragelink
|
42 |
</div> |
|
c588255…
|
ragelink
|
43 |
<div> |
|
c588255…
|
ragelink
|
44 |
<dt class="text-gray-500">Handle</dt> |
|
c588255…
|
ragelink
|
45 |
<dd class="text-gray-200 mt-0.5">{% if user_profile.handle %}@{{ user_profile.handle }}{% else %}Not set{% endif %}</dd> |
|
c588255…
|
ragelink
|
46 |
</div> |
|
c588255…
|
ragelink
|
47 |
<div> |
|
c588255…
|
ragelink
|
48 |
<dt class="text-gray-500">Email</dt> |
|
c588255…
|
ragelink
|
49 |
<dd class="text-gray-200 mt-0.5">{{ user.email|default:"Not set" }}</dd> |
|
c588255…
|
ragelink
|
50 |
</div> |
|
c588255…
|
ragelink
|
51 |
<div> |
|
c588255…
|
ragelink
|
52 |
<dt class="text-gray-500">Location</dt> |
|
c588255…
|
ragelink
|
53 |
<dd class="text-gray-200 mt-0.5">{{ user_profile.location|default:"Not set" }}</dd> |
|
c588255…
|
ragelink
|
54 |
</div> |
|
c588255…
|
ragelink
|
55 |
<div> |
|
c588255…
|
ragelink
|
56 |
<dt class="text-gray-500">Website</dt> |
|
c588255…
|
ragelink
|
57 |
<dd class="text-gray-200 mt-0.5"> |
|
c588255…
|
ragelink
|
58 |
{% if user_profile.website %} |
|
c588255…
|
ragelink
|
59 |
<a href="{{ user_profile.website }}" class="text-brand-light hover:text-brand" target="_blank" rel="noopener">{{ user_profile.website }}</a> |
|
c588255…
|
ragelink
|
60 |
{% else %}Not set{% endif %} |
|
c588255…
|
ragelink
|
61 |
</dd> |
|
c588255…
|
ragelink
|
62 |
</div> |
|
c588255…
|
ragelink
|
63 |
<div class="sm:col-span-2"> |
|
c588255…
|
ragelink
|
64 |
<dt class="text-gray-500">Bio</dt> |
|
c588255…
|
ragelink
|
65 |
<dd class="text-gray-200 mt-0.5">{{ user_profile.bio|default:"Not set"|linebreaksbr }}</dd> |
|
c588255…
|
ragelink
|
66 |
</div> |
|
c588255…
|
ragelink
|
67 |
</dl> |
|
c588255…
|
ragelink
|
68 |
</div> |
|
c588255…
|
ragelink
|
69 |
|
|
c588255…
|
ragelink
|
70 |
<!-- SSH Keys Card --> |
|
2f13242…
|
ragelink
|
71 |
<div class="rounded-lg bg-gray-800 border border-gray-700 mb-6 shadow-sm"> |
|
c588255…
|
ragelink
|
72 |
<div class="p-4 border-b border-gray-700 flex items-center justify-between"> |
|
c588255…
|
ragelink
|
73 |
<h2 class="text-lg font-semibold text-gray-200">SSH Keys</h2> |
|
c588255…
|
ragelink
|
74 |
<a href="{% url 'accounts:ssh_keys' %}" class="text-sm text-brand-light hover:text-brand">Manage Keys</a> |
|
c588255…
|
ragelink
|
75 |
</div> |
|
c588255…
|
ragelink
|
76 |
{% if ssh_keys %} |
|
c588255…
|
ragelink
|
77 |
<div class="divide-y divide-gray-700"> |
|
c588255…
|
ragelink
|
78 |
{% for key in ssh_keys %} |
|
313537c…
|
ragelink
|
79 |
<div class="p-4 flex flex-wrap items-center justify-between gap-3"> |
|
313537c…
|
ragelink
|
80 |
<div class="min-w-0"> |
|
c588255…
|
ragelink
|
81 |
<div class="text-sm font-medium text-gray-200">{{ key.title }}</div> |
|
313537c…
|
ragelink
|
82 |
<div class="text-xs text-gray-500 font-mono mt-1 truncate">{{ key.fingerprint }}</div> |
|
c588255…
|
ragelink
|
83 |
<div class="text-xs text-gray-500 mt-1"> |
|
c588255…
|
ragelink
|
84 |
{{ key.key_type|upper }} · Added {{ key.created_at|timesince }} ago |
|
c588255…
|
ragelink
|
85 |
{% if key.last_used_at %}· Last used {{ key.last_used_at|timesince }} ago{% endif %} |
|
c588255…
|
ragelink
|
86 |
</div> |
|
c588255…
|
ragelink
|
87 |
</div> |
|
c588255…
|
ragelink
|
88 |
</div> |
|
c588255…
|
ragelink
|
89 |
{% endfor %} |
|
c588255…
|
ragelink
|
90 |
</div> |
|
c588255…
|
ragelink
|
91 |
{% else %} |
|
c588255…
|
ragelink
|
92 |
<div class="p-6 text-center text-sm text-gray-500"> |
|
c588255…
|
ragelink
|
93 |
No SSH keys added yet. <a href="{% url 'accounts:ssh_keys' %}" class="text-brand-light hover:text-brand">Add one</a> to clone and push over SSH. |
|
c588255…
|
ragelink
|
94 |
</div> |
|
c588255…
|
ragelink
|
95 |
{% endif %} |
|
c588255…
|
ragelink
|
96 |
</div> |
|
c588255…
|
ragelink
|
97 |
|
|
c588255…
|
ragelink
|
98 |
<!-- Notification Preferences Card --> |
|
2f13242…
|
ragelink
|
99 |
<div class="rounded-lg bg-gray-800 border border-gray-700 mb-6 shadow-sm"> |
|
c588255…
|
ragelink
|
100 |
<div class="p-4 border-b border-gray-700 flex items-center justify-between"> |
|
c588255…
|
ragelink
|
101 |
<h2 class="text-lg font-semibold text-gray-200">Notification Preferences</h2> |
|
c588255…
|
ragelink
|
102 |
<a href="{% url 'accounts:notification_prefs' %}" class="text-sm text-brand-light hover:text-brand">Edit Preferences</a> |
|
c588255…
|
ragelink
|
103 |
</div> |
|
c588255…
|
ragelink
|
104 |
<div class="p-4"> |
|
c588255…
|
ragelink
|
105 |
<dl class="grid grid-cols-1 sm:grid-cols-2 gap-x-6 gap-y-3 text-sm"> |
|
c588255…
|
ragelink
|
106 |
<div> |
|
c588255…
|
ragelink
|
107 |
<dt class="text-gray-500">Delivery Mode</dt> |
|
c588255…
|
ragelink
|
108 |
<dd class="text-gray-200 mt-0.5 capitalize">{{ notif_prefs.delivery_mode }}</dd> |
|
c588255…
|
ragelink
|
109 |
</div> |
|
c588255…
|
ragelink
|
110 |
<div> |
|
c588255…
|
ragelink
|
111 |
<dt class="text-gray-500">Events</dt> |
|
c588255…
|
ragelink
|
112 |
<dd class="text-gray-200 mt-0.5"> |
|
c588255…
|
ragelink
|
113 |
{% if notif_prefs.notify_checkins %}Checkins{% endif %} |
|
c588255…
|
ragelink
|
114 |
{% if notif_prefs.notify_tickets %}{% if notif_prefs.notify_checkins %}, {% endif %}Tickets{% endif %} |
|
c588255…
|
ragelink
|
115 |
{% if notif_prefs.notify_wiki %}{% if notif_prefs.notify_checkins or notif_prefs.notify_tickets %}, {% endif %}Wiki{% endif %} |
|
c588255…
|
ragelink
|
116 |
{% if notif_prefs.notify_releases %}{% if notif_prefs.notify_checkins or notif_prefs.notify_tickets or notif_prefs.notify_wiki %}, {% endif %}Releases{% endif %} |
|
c588255…
|
ragelink
|
117 |
{% if notif_prefs.notify_forum %}{% if notif_prefs.notify_checkins or notif_prefs.notify_tickets or notif_prefs.notify_wiki or notif_prefs.notify_releases %}, {% endif %}Forum{% endif %} |
|
c588255…
|
ragelink
|
118 |
{% if not notif_prefs.notify_checkins and not notif_prefs.notify_tickets and not notif_prefs.notify_wiki and not notif_prefs.notify_releases and not notif_prefs.notify_forum %}None{% endif %} |
|
c588255…
|
ragelink
|
119 |
</dd> |
|
c588255…
|
ragelink
|
120 |
</div> |
|
c588255…
|
ragelink
|
121 |
</dl> |
|
c588255…
|
ragelink
|
122 |
</div> |
|
c588255…
|
ragelink
|
123 |
</div> |
|
c588255…
|
ragelink
|
124 |
|
|
c588255…
|
ragelink
|
125 |
<!-- Personal Access Tokens Card --> |
|
2f13242…
|
ragelink
|
126 |
<div class="rounded-lg bg-gray-800 border border-gray-700 mb-6 shadow-sm"> |
|
c588255…
|
ragelink
|
127 |
<div class="p-4 border-b border-gray-700 flex items-center justify-between"> |
|
c588255…
|
ragelink
|
128 |
<h2 class="text-lg font-semibold text-gray-200">Personal Access Tokens</h2> |
|
c588255…
|
ragelink
|
129 |
<a href="{% url 'accounts:profile_token_create' %}" |
|
2f13242…
|
ragelink
|
130 |
class="rounded-md bg-brand px-3 py-1.5 text-sm font-semibold text-white hover:bg-brand-hover focus:outline-none focus:ring-2 focus:ring-brand focus:ring-offset-2 focus:ring-offset-gray-950 transition-colors"> |
|
c588255…
|
ragelink
|
131 |
Generate Token |
|
c588255…
|
ragelink
|
132 |
</a> |
|
c588255…
|
ragelink
|
133 |
</div> |
|
c588255…
|
ragelink
|
134 |
{% if tokens %} |
|
c588255…
|
ragelink
|
135 |
<div class="divide-y divide-gray-700"> |
|
c588255…
|
ragelink
|
136 |
{% for token in tokens %} |
|
313537c…
|
ragelink
|
137 |
<div class="p-4 flex flex-wrap items-center justify-between gap-3"> |
|
313537c…
|
ragelink
|
138 |
<div class="min-w-0"> |
|
c588255…
|
ragelink
|
139 |
<div class="text-sm font-medium text-gray-200">{{ token.name }}</div> |
|
313537c…
|
ragelink
|
140 |
<div class="text-xs text-gray-500 font-mono mt-1 truncate">{{ token.token_prefix }}...</div> |
|
313537c…
|
ragelink
|
141 |
<div class="text-xs text-gray-500 mt-1 break-words"> |
|
c588255…
|
ragelink
|
142 |
Scopes: {{ token.scopes }} · Created {{ token.created_at|timesince }} ago |
|
c588255…
|
ragelink
|
143 |
{% if token.last_used_at %}· Last used {{ token.last_used_at|timesince }} ago{% endif %} |
|
c588255…
|
ragelink
|
144 |
{% if token.expires_at %}· Expires {{ token.expires_at|date:"M j, Y" }}{% endif %} |
|
c588255…
|
ragelink
|
145 |
</div> |
|
c588255…
|
ragelink
|
146 |
</div> |
|
c588255…
|
ragelink
|
147 |
<form hx-post="{% url 'accounts:profile_token_revoke' guid=token.token_prefix %}" |
|
c588255…
|
ragelink
|
148 |
hx-confirm="Revoke token '{{ token.name }}'? This cannot be undone."> |
|
c588255…
|
ragelink
|
149 |
{% csrf_token %} |
|
c588255…
|
ragelink
|
150 |
<button type="submit" class="text-sm text-red-400 hover:text-red-300">Revoke</button> |
|
c588255…
|
ragelink
|
151 |
</form> |
|
c588255…
|
ragelink
|
152 |
</div> |
|
c588255…
|
ragelink
|
153 |
{% endfor %} |
|
c588255…
|
ragelink
|
154 |
</div> |
|
c588255…
|
ragelink
|
155 |
{% else %} |
|
c588255…
|
ragelink
|
156 |
<div class="p-6 text-center text-sm text-gray-500"> |
|
c588255…
|
ragelink
|
157 |
No personal access tokens. Generate one to authenticate with the API or CLI. |
|
c588255…
|
ragelink
|
158 |
</div> |
|
c588255…
|
ragelink
|
159 |
{% endif %} |
|
c588255…
|
ragelink
|
160 |
</div> |
|
c588255…
|
ragelink
|
161 |
{% endblock %} |