forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

Compare changes

Choose any two refs to compare.

Changed files
+58 -57
appview
notify
pages
templates
repo
issues
settings
spindles
user
state
+42 -50
appview/notify/merged_notifier.go
··· 2 3 import ( 4 "context" 5 6 "tangled.org/core/appview/models" 7 ) ··· 16 17 var _ Notifier = &mergedNotifier{} 18 19 - func (m *mergedNotifier) NewRepo(ctx context.Context, repo *models.Repo) { 20 - for _, notifier := range m.notifiers { 21 - notifier.NewRepo(ctx, repo) 22 } 23 } 24 25 func (m *mergedNotifier) NewStar(ctx context.Context, star *models.Star) { 26 - for _, notifier := range m.notifiers { 27 - notifier.NewStar(ctx, star) 28 - } 29 } 30 func (m *mergedNotifier) DeleteStar(ctx context.Context, star *models.Star) { 31 - for _, notifier := range m.notifiers { 32 - notifier.DeleteStar(ctx, star) 33 - } 34 } 35 36 func (m *mergedNotifier) NewIssue(ctx context.Context, issue *models.Issue) { 37 - for _, notifier := range m.notifiers { 38 - notifier.NewIssue(ctx, issue) 39 - } 40 } 41 func (m *mergedNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) { 42 - for _, notifier := range m.notifiers { 43 - notifier.NewIssueComment(ctx, comment) 44 - } 45 } 46 47 func (m *mergedNotifier) NewIssueClosed(ctx context.Context, issue *models.Issue) { 48 - for _, notifier := range m.notifiers { 49 - notifier.NewIssueClosed(ctx, issue) 50 - } 51 } 52 53 func (m *mergedNotifier) NewFollow(ctx context.Context, follow *models.Follow) { 54 - for _, notifier := range m.notifiers { 55 - notifier.NewFollow(ctx, follow) 56 - } 57 } 58 func (m *mergedNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) { 59 - for _, notifier := range m.notifiers { 60 - notifier.DeleteFollow(ctx, follow) 61 - } 62 } 63 64 func (m *mergedNotifier) NewPull(ctx context.Context, pull *models.Pull) { 65 - for _, notifier := range m.notifiers { 66 - notifier.NewPull(ctx, pull) 67 - } 68 } 69 func (m *mergedNotifier) NewPullComment(ctx context.Context, comment *models.PullComment) { 70 - for _, notifier := range m.notifiers { 71 - notifier.NewPullComment(ctx, comment) 72 - } 73 } 74 75 func (m *mergedNotifier) NewPullMerged(ctx context.Context, pull *models.Pull) { 76 - for _, notifier := range m.notifiers { 77 - notifier.NewPullMerged(ctx, pull) 78 - } 79 } 80 81 func (m *mergedNotifier) NewPullClosed(ctx context.Context, pull *models.Pull) { 82 - for _, notifier := range m.notifiers { 83 - notifier.NewPullClosed(ctx, pull) 84 - } 85 } 86 87 func (m *mergedNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) { 88 - for _, notifier := range m.notifiers { 89 - notifier.UpdateProfile(ctx, profile) 90 - } 91 } 92 93 - func (m *mergedNotifier) NewString(ctx context.Context, string *models.String) { 94 - for _, notifier := range m.notifiers { 95 - notifier.NewString(ctx, string) 96 - } 97 } 98 99 - func (m *mergedNotifier) EditString(ctx context.Context, string *models.String) { 100 - for _, notifier := range m.notifiers { 101 - notifier.EditString(ctx, string) 102 - } 103 } 104 105 func (m *mergedNotifier) DeleteString(ctx context.Context, did, rkey string) { 106 - for _, notifier := range m.notifiers { 107 - notifier.DeleteString(ctx, did, rkey) 108 - } 109 }
··· 2 3 import ( 4 "context" 5 + "reflect" 6 + "sync" 7 8 "tangled.org/core/appview/models" 9 ) ··· 18 19 var _ Notifier = &mergedNotifier{} 20 21 + // fanout calls the same method on all notifiers concurrently 22 + func (m *mergedNotifier) fanout(method string, args ...any) { 23 + var wg sync.WaitGroup 24 + for _, n := range m.notifiers { 25 + wg.Add(1) 26 + go func(notifier Notifier) { 27 + defer wg.Done() 28 + v := reflect.ValueOf(notifier).MethodByName(method) 29 + in := make([]reflect.Value, len(args)) 30 + for i, arg := range args { 31 + in[i] = reflect.ValueOf(arg) 32 + } 33 + v.Call(in) 34 + }(n) 35 } 36 + wg.Wait() 37 + } 38 + 39 + func (m *mergedNotifier) NewRepo(ctx context.Context, repo *models.Repo) { 40 + m.fanout("NewRepo", ctx, repo) 41 } 42 43 func (m *mergedNotifier) NewStar(ctx context.Context, star *models.Star) { 44 + m.fanout("NewStar", ctx, star) 45 } 46 + 47 func (m *mergedNotifier) DeleteStar(ctx context.Context, star *models.Star) { 48 + m.fanout("DeleteStar", ctx, star) 49 } 50 51 func (m *mergedNotifier) NewIssue(ctx context.Context, issue *models.Issue) { 52 + m.fanout("NewIssue", ctx, issue) 53 } 54 + 55 func (m *mergedNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) { 56 + m.fanout("NewIssueComment", ctx, comment) 57 } 58 59 func (m *mergedNotifier) NewIssueClosed(ctx context.Context, issue *models.Issue) { 60 + m.fanout("NewIssueClosed", ctx, issue) 61 } 62 63 func (m *mergedNotifier) NewFollow(ctx context.Context, follow *models.Follow) { 64 + m.fanout("NewFollow", ctx, follow) 65 } 66 + 67 func (m *mergedNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) { 68 + m.fanout("DeleteFollow", ctx, follow) 69 } 70 71 func (m *mergedNotifier) NewPull(ctx context.Context, pull *models.Pull) { 72 + m.fanout("NewPull", ctx, pull) 73 } 74 + 75 func (m *mergedNotifier) NewPullComment(ctx context.Context, comment *models.PullComment) { 76 + m.fanout("NewPullComment", ctx, comment) 77 } 78 79 func (m *mergedNotifier) NewPullMerged(ctx context.Context, pull *models.Pull) { 80 + m.fanout("NewPullMerged", ctx, pull) 81 } 82 83 func (m *mergedNotifier) NewPullClosed(ctx context.Context, pull *models.Pull) { 84 + m.fanout("NewPullClosed", ctx, pull) 85 } 86 87 func (m *mergedNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) { 88 + m.fanout("UpdateProfile", ctx, profile) 89 } 90 91 + func (m *mergedNotifier) NewString(ctx context.Context, s *models.String) { 92 + m.fanout("NewString", ctx, s) 93 } 94 95 + func (m *mergedNotifier) EditString(ctx context.Context, s *models.String) { 96 + m.fanout("EditString", ctx, s) 97 } 98 99 func (m *mergedNotifier) DeleteString(ctx context.Context, did, rkey string) { 100 + m.fanout("DeleteString", ctx, did, rkey) 101 }
+3 -2
appview/pages/funcmap.go
··· 297 }, 298 299 "normalizeForHtmlId": func(s string) string { 300 - // TODO: extend this to handle other cases? 301 - return strings.ReplaceAll(s, ":", "_") 302 }, 303 "sshFingerprint": func(pubKey string) string { 304 fp, err := crypto.SSHFingerprint(pubKey)
··· 297 }, 298 299 "normalizeForHtmlId": func(s string) string { 300 + normalized := strings.ReplaceAll(s, ":", "_") 301 + normalized = strings.ReplaceAll(normalized, ".", "_") 302 + return normalized 303 }, 304 "sshFingerprint": func(pubKey string) string { 305 fp, err := crypto.SSHFingerprint(pubKey)
+2 -2
appview/pages/templates/repo/issues/fragments/issueCommentHeader.html
··· 34 35 {{ define "editIssueComment" }} 36 <a 37 - class="text-gray-500 dark:text-gray-400 flex gap-1 items-center group" 38 hx-get="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment/{{ .Comment.Id }}/edit" 39 hx-swap="outerHTML" 40 hx-target="#comment-body-{{.Comment.Id}}"> ··· 44 45 {{ define "deleteIssueComment" }} 46 <a 47 - class="text-gray-500 dark:text-gray-400 flex gap-1 items-center group" 48 hx-delete="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment/{{ .Comment.Id }}/" 49 hx-confirm="Are you sure you want to delete your comment?" 50 hx-swap="outerHTML"
··· 34 35 {{ define "editIssueComment" }} 36 <a 37 + class="text-gray-500 dark:text-gray-400 flex gap-1 items-center group cursor-pointer" 38 hx-get="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment/{{ .Comment.Id }}/edit" 39 hx-swap="outerHTML" 40 hx-target="#comment-body-{{.Comment.Id}}"> ··· 44 45 {{ define "deleteIssueComment" }} 46 <a 47 + class="text-gray-500 dark:text-gray-400 flex gap-1 items-center group cursor-pointer" 48 hx-delete="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/comment/{{ .Comment.Id }}/" 49 hx-confirm="Are you sure you want to delete your comment?" 50 hx-swap="outerHTML"
+2 -2
appview/pages/templates/repo/issues/issue.html
··· 84 85 {{ define "editIssue" }} 86 <a 87 - class="text-gray-500 dark:text-gray-400 flex gap-1 items-center group" 88 hx-get="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/edit" 89 hx-swap="innerHTML" 90 hx-target="#issue-{{.Issue.IssueId}}"> ··· 94 95 {{ define "deleteIssue" }} 96 <a 97 - class="text-gray-500 dark:text-gray-400 flex gap-1 items-center group" 98 hx-delete="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/" 99 hx-confirm="Are you sure you want to delete your issue?" 100 hx-swap="none">
··· 84 85 {{ define "editIssue" }} 86 <a 87 + class="text-gray-500 dark:text-gray-400 flex gap-1 items-center group cursor-pointer" 88 hx-get="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/edit" 89 hx-swap="innerHTML" 90 hx-target="#issue-{{.Issue.IssueId}}"> ··· 94 95 {{ define "deleteIssue" }} 96 <a 97 + class="text-gray-500 dark:text-gray-400 flex gap-1 items-center group cursor-pointer" 98 hx-delete="/{{ .RepoInfo.FullName }}/issues/{{ .Issue.IssueId }}/" 99 hx-confirm="Are you sure you want to delete your issue?" 100 hx-swap="none">
+2
appview/pages/templates/repo/settings/access.html
··· 83 </label> 84 <p class="text-sm text-gray-500 dark:text-gray-400">Collaborators can push to this repository.</p> 85 <input 86 type="text" 87 id="add-collaborator" 88 name="collaborator"
··· 83 </label> 84 <p class="text-sm text-gray-500 dark:text-gray-400">Collaborators can push to this repository.</p> 85 <input 86 + autocapitalize="none" 87 + autocorrect="off" 88 type="text" 89 id="add-collaborator" 90 name="collaborator"
+2
appview/pages/templates/spindles/fragments/addMemberModal.html
··· 30 </label> 31 <p class="text-sm text-gray-500 dark:text-gray-400">Members can register repositories and run workflows on this spindle.</p> 32 <input 33 type="text" 34 id="member-did-{{ .Id }}" 35 name="member"
··· 30 </label> 31 <p class="text-sm text-gray-500 dark:text-gray-400">Members can register repositories and run workflows on this spindle.</p> 32 <input 33 + autocapitalize="none" 34 + autocorrect="off" 35 type="text" 36 id="member-did-{{ .Id }}" 37 name="member"
+1 -1
appview/pages/templates/user/fragments/followCard.html
··· 3 <div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 rounded-sm"> 4 <div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex items-center gap-4"> 5 <div class="flex-shrink-0 max-h-full w-24 h-24"> 6 - <img class="object-cover rounded-full p-2" src="{{ fullAvatar $userIdent }}" /> 7 </div> 8 9 <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-2 w-full">
··· 3 <div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 rounded-sm"> 4 <div class="py-4 px-6 drop-shadow-sm rounded bg-white dark:bg-gray-800 flex items-center gap-4"> 5 <div class="flex-shrink-0 max-h-full w-24 h-24"> 6 + <img class="object-cover rounded-full p-2" src="{{ fullAvatar $userIdent }}" alt="{{ $userIdent }}" /> 7 </div> 8 9 <div class="flex flex-col md:flex-row md:items-center md:justify-between gap-2 w-full">
+3
appview/pages/templates/user/login.html
··· 29 <div class="flex flex-col"> 30 <label for="handle">handle</label> 31 <input 32 type="text" 33 id="handle" 34 name="handle"
··· 29 <div class="flex flex-col"> 30 <label for="handle">handle</label> 31 <input 32 + autocapitalize="none" 33 + autocorrect="off" 34 + autocomplete="username" 35 type="text" 36 id="handle" 37 name="handle"
+1
appview/state/follow.go
··· 26 subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject) 27 if err != nil { 28 log.Println("failed to follow, invalid did") 29 } 30 31 if currentUser.Did == subjectIdent.DID.String() {
··· 26 subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject) 27 if err != nil { 28 log.Println("failed to follow, invalid did") 29 + return 30 } 31 32 if currentUser.Did == subjectIdent.DID.String() {