appview: repo/index: add ref selector dropdown
nix: builds for repoguard and keyfetch
Anirudh Oppiliappan 2 weeks ago 7 files (+307, -172)
MODIFIED
appview/pages/pages.go
MODIFIED
appview/pages/pages.go
@@ -237,6 +237,8 @@ type RepoIndexParams struct {LoggedInUser *auth.UserRepoInfo RepoInfoActive string+ Branches []types.Branch+ Tags []*types.TagReferencetypes.RepoIndexResponse}
@@ -1,48 +1,96 @@-{{define "repoContent"}}+{{ define "repoContent" }}+ <main>+ {{- if .IsEmpty }}+ this repo is empty+ {{ else }}+ <div class="flex gap-4">+ <div id="file-tree" class="w-1/2">+ {{ $containerstyle := "py-1" }}+ {{ $linkstyle := "no-underline hover:underline" }}-<main>- {{- if .IsEmpty }}- this repo is empty- {{ else }}- <div class="flex gap-4">- <div id="file-tree" class="w-1/2">- {{ $containerstyle := "py-1" }}- {{ $linkstyle := "no-underline hover:underline" }}- {{ range .Files }}- {{ if not .IsFile }}- <div class="{{ $containerstyle }}">- <a href="/{{ $.RepoInfo.FullName }}/tree/{{ $.Ref }}/{{ .Name }}" class="{{ $linkstyle }}">- <div class="flex items-center gap-2">- <i class="w-3 h-3 fill-current" data-lucide="folder"></i>{{ .Name }}/- </div>- </a>- </div>- {{ end }}- {{ end }}+ <div class="flex justify-end">+ <select+ hx-get="/{{ .RepoInfo.FullName }}/tree/"+ hx-on::config-request = "event.detail.path += this.value"+ hx-trigger="change"+ hx-target="#repo-content"+ hx-select="#repo-content"+ hx-push-url="true"+ class="p-1 border border-gray-500 bg-white"+ >+ <optgroup label="branches" class="font-semibold">+ {{ range .Branches }}+ <option+ value="{{ .Reference.Name }}"+ class="py-1"+ >+ {{ .Reference.Name }}+ </option>+ {{ end }}+ </optgroup>+ <optgroup label="tags" class="font-semibold">+ {{ range .Tags }}+ <option+ value="{{ .Reference.Name }}"+ class="py-1"+ >+ {{ .Reference.Name }}+ </option>+ {{ end }}+ </optgroup>+ </select>+ </div>- {{ range .Files }}- {{ if .IsFile }}- <div class="{{ $containerstyle }}">- <a href="/{{ $.RepoInfo.FullName }}/blob/{{ $.Ref }}/{{ .Name }}" class="{{ $linkstyle }}">- <div class="flex items-center gap-2">- <i class="w-3 h-3" data-lucide="file"></i>{{ .Name }}- </div>- </a>- </div>- {{ end }}- {{ end }}- </div>- <div id="commit-log" class="flex-1">- {{ range .Commits }}- <div class=- "relative+ <section id="repo-content">+ {{ range .Files }}+ {{ if not .IsFile }}+ <div class="{{ $containerstyle }}">+ <a+ href="/{{ $.RepoInfo.FullName }}/tree/{{ $.Ref }}/{{ .Name }}"+ class="{{ $linkstyle }}"+ >+ <div class="flex items-center gap-2">+ <i+ class="w-3 h-3 fill-current"+ data-lucide="folder"+ ></i+ >{{ .Name }}/+ </div>+ </a>+ </div>+ {{ end }}+ {{ end }}++ {{ range .Files }}+ {{ if .IsFile }}+ <div class="{{ $containerstyle }}">+ <a+ href="/{{ $.RepoInfo.FullName }}/blob/{{ $.Ref }}/{{ .Name }}"+ class="{{ $linkstyle }}"+ >+ <div class="flex items-center gap-2">+ <i+ class="w-3 h-3"+ data-lucide="file"+ ></i+ >{{ .Name }}+ </div>+ </a>+ </div>+ {{ end }}+ {{ end }}+ </div>+ <div id="commit-log" class="flex-1">+ {{ range .Commits }}+ <div+ class="relativepx-4py-4border-lborder-black- before:content-['']- before:absolute+ before:content-['']+ before:absolutebefore:w-1before:h-1before:bg-black@@ -64,35 +112,44 @@ {{ end }}</div></div>- <div class="text-xs text-gray-500">- <span class="font-mono">- <a href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash.String }}" class="text-gray-500 no-underline hover:underline">{{ slice .Hash.String 0 8 }}</a>- </span>- · - <span>- <a href="mailto:{{ .Author.Email }}" class="text-gray-500 no-underline hover:underline">{{ .Author.Name }}</a>- </span>- · - <span>{{ timeFmt .Author.When }}</span>- </div>+ <div class="text-xs text-gray-500">+ <span class="font-mono">+ <a+ href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash.String }}"+ class="text-gray-500 no-underline hover:underline"+ >{{ slice .Hash.String 0 8 }}</a+ >+ </span>+ · + <span>+ <a+ href="mailto:{{ .Author.Email }}"+ class="text-gray-500 no-underline hover:underline"+ >{{ .Author.Name }}</a+ >+ </span>+ · + <span>{{ timeFmt .Author.When }}</span>+ </div>+ </div>+ {{ end }}+ </div>+ </div>+ </section>+ {{- if .Readme }}+ <article class="readme">+ {{- .Readme -}}+ </article>+ {{- end -}}+ {{- end -}}- </div>- {{ end }}- </div>- </div>- {{- if .Readme }}- <article class="readme">- {{- .Readme -}}- </article>- {{- end -}}- {{- end -}}- <div class="clone-url">- <strong>clone</strong>- <pre>+ <div class="clone-url">+ <strong>clone</strong>+ <pre>git clone https://tangled.sh/{{ .RepoInfo.OwnerWithAt }}/{{ .RepoInfo.Name }}- </pre>- </div>-</main>-{{end}}-+ </pre+ >+ </div>+ </main>+{{ end }}
MODIFIED
appview/state/repo.go
MODIFIED
appview/state/repo.go
@@ -18,13 +18,20 @@ "github.com/sotangled/tangled/types")func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) {+ ref := chi.URLParam(r, "ref")f, err := fullyResolvedRepo(r)if err != nil {log.Println("failed to fully resolve repo", err)return}+ var reqUrl string+ if ref != "" {+ reqUrl = fmt.Sprintf("http://%s/%s/%s/tree/%s", f.Knot, f.OwnerDid(), f.RepoName, ref)+ } else {+ reqUrl = fmt.Sprintf("http://%s/%s/%s", f.Knot, f.OwnerDid(), f.RepoName)+ }- resp, err := http.Get(fmt.Sprintf("http://%s/%s/%s", f.Knot, f.OwnerDid(), f.RepoName))+ resp, err := http.Get(reqUrl)if err != nil {s.pages.Error503(w)log.Println("failed to reach knotserver", err)@@ -45,6 +52,46 @@ log.Fatalf("Error unmarshalling response body: %v", err)return}+ branchesResp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/branches", f.Knot, f.OwnerDid(), f.RepoName))+ if err != nil {+ log.Println("failed to reach knotserver for branches", err)+ return+ }+ defer branchesResp.Body.Close()++ tagsResp, err := http.Get(fmt.Sprintf("http://%s/%s/%s/tags", f.Knot, f.OwnerDid(), f.RepoName))+ if err != nil {+ log.Println("failed to reach knotserver for tags", err)+ return+ }+ defer tagsResp.Body.Close()++ branchesBody, err := io.ReadAll(branchesResp.Body)+ if err != nil {+ log.Println("failed to read branches response", err)+ return+ }++ tagsBody, err := io.ReadAll(tagsResp.Body)+ if err != nil {+ log.Println("failed to read tags response", err)+ return+ }++ var branchesResult types.RepoBranchesResponse+ err = json.Unmarshal(branchesBody, &branchesResult)+ if err != nil {+ log.Println("failed to parse branches response", err)+ return+ }++ var tagsResult types.RepoTagsResponse+ err = json.Unmarshal(tagsBody, &tagsResult)+ if err != nil {+ log.Println("failed to parse tags response", err)+ return+ }+log.Println(resp.Status, result)user := s.auth.GetUser(r)@@ -57,6 +104,8 @@ Name: f.RepoName,SettingsAllowed: settingsAllowed(s, user, f),},RepoIndexResponse: result,+ Branches: branchesResult.Branches,+ Tags: tagsResult.Tags,})return
MODIFIED
appview/state/state.go
MODIFIED
appview/state/state.go
@@ -685,6 +685,7 @@ r.With(ResolveRepoKnot(s)).Route("/{repo}", func(r chi.Router) {r.Get("/", s.RepoIndex)r.Get("/log/{ref}", s.RepoLog)r.Route("/tree/{ref}", func(r chi.Router) {+ r.Get("/", s.RepoIndex)r.Get("/*", s.RepoTree)})r.Get("/commit/{ref}", s.RepoCommit)
MODIFIED
flake.nix
MODIFIED
flake.nix
@@ -12,8 +12,8 @@ url = "https://unpkg.com/htmx.org@2.0.4/dist/htmx.min.js";flake = false;};lucide-src = {- url = "https://unpkg.com/lucide@latest";- flake = false;+ url = "https://unpkg.com/lucide@latest";+ flake = false;};gitignore = {url = "github:hercules-ci/gitignore.nix";@@ -21,102 +21,127 @@ inputs.nixpkgs.follows = "nixpkgs";};};- outputs = {- self,- nixpkgs,- indigo,- htmx-src,- lucide-src,- gitignore,- }: let- supportedSystems = ["x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin"];- forAllSystems = nixpkgs.lib.genAttrs supportedSystems;- nixpkgsFor = forAllSystems (system:- import nixpkgs {- inherit system;- overlays = [self.overlays.default];- });- inherit (gitignore.lib) gitignoreSource;- in {- overlays.default = final: prev: {- indigo-lexgen = with final;- final.buildGoModule {- pname = "indigo-lexgen";- version = "0.1.0";- src = indigo;- subPackages = ["cmd/lexgen"];- vendorHash = "sha256-pGc29fgJFq8LP7n/pY1cv6ExZl88PAeFqIbFEhB3xXs=";- doCheck = false;- };+ outputs =+ { self+ , nixpkgs+ , indigo+ , htmx-src+ , lucide-src+ , gitignore+ ,+ }:+ let+ supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];+ forAllSystems = nixpkgs.lib.genAttrs supportedSystems;+ nixpkgsFor = forAllSystems (system:+ import nixpkgs {+ inherit system;+ overlays = [ self.overlays.default ];+ });+ inherit (gitignore.lib) gitignoreSource;+ in+ {+ overlays.default = final: prev: {+ indigo-lexgen = with final;+ final.buildGoModule {+ pname = "indigo-lexgen";+ version = "0.1.0";+ src = indigo;+ subPackages = [ "cmd/lexgen" ];+ vendorHash = "sha256-pGc29fgJFq8LP7n/pY1cv6ExZl88PAeFqIbFEhB3xXs=";+ doCheck = false;+ };- appview = with final;- final.pkgsStatic.buildGoModule {- pname = "appview";- version = "0.1.0";- src = gitignoreSource ./.;- postConfigureHook = ''- cp -f ${htmx-src} appview/pages/static/htmx.min.js- cp -f ${lucide-src} appview/pages/static/lucide.min.js- ${pkgs.tailwindcss}/bin/tailwindcss -i input.css -o appview/pages/static/tw.css- '';- subPackages = ["cmd/appview"];- vendorHash = "sha256-t7lWrCyFWCI7zjUcC6XNWzCrUPSCFnFu9gTmRTsYrz0=";- env.CGO_ENABLED = 1;- stdenv = pkgsStatic.stdenv;- };- knotserver = with final;+ appview = with final;+ final.pkgsStatic.buildGoModule {+ pname = "appview";+ version = "0.1.0";+ src = gitignoreSource ./.;+ postConfigureHook = ''+ cp -f ${htmx-src} appview/pages/static/htmx.min.js+ cp -f ${lucide-src} appview/pages/static/lucide.min.js+ ${pkgs.tailwindcss}/bin/tailwindcss -i input.css -o appview/pages/static/tw.css+ '';+ subPackages = [ "cmd/appview" ];+ vendorHash = "sha256-t7lWrCyFWCI7zjUcC6XNWzCrUPSCFnFu9gTmRTsYrz0=";+ env.CGO_ENABLED = 1;+ stdenv = pkgsStatic.stdenv;+ };+ knotserver = with final;+ final.pkgsStatic.buildGoModule {+ pname = "knotserver";+ version = "0.1.0";+ src = gitignoreSource ./.;+ subPackages = [ "cmd/knotserver" ];+ vendorHash = "sha256-t7lWrCyFWCI7zjUcC6XNWzCrUPSCFnFu9gTmRTsYrz0=";+ env.CGO_ENABLED = 1;+ };+ repoguard = with final;+ final.pkgsStatic.buildGoModule {+ pname = "repoguard";+ version = "0.1.0";+ src = gitignoreSource ./.;+ subPackages = [ "cmd/repoguard" ];+ vendorHash = "sha256-t7lWrCyFWCI7zjUcC6XNWzCrUPSCFnFu9gTmRTsYrz0=";+ env.CGO_ENABLED = 0;+ };+ keyfetch = with final;final.pkgsStatic.buildGoModule {- pname = "knotserver";- version = "0.1.0";- src = gitignoreSource ./.;- subPackages = ["cmd/knotserver"];- vendorHash = "sha256-t7lWrCyFWCI7zjUcC6XNWzCrUPSCFnFu9gTmRTsYrz0=";- env.CGO_ENABLED = 1;- };+ pname = "keyfetch";+ version = "0.1.0";+ src = gitignoreSource ./.;+ subPackages = [ "cmd/keyfetch" ];+ vendorHash = "sha256-t7lWrCyFWCI7zjUcC6XNWzCrUPSCFnFu9gTmRTsYrz0=";+ env.CGO_ENABLED = 0;+ };+ };+ packages = forAllSystems (system: {+ inherit (nixpkgsFor."${system}") indigo-lexgen appview knotserver repoguard keyfetch;+ });+ defaultPackage = forAllSystems (system: nixpkgsFor.${system}.appview);+ formatter = forAllSystems (system: nixpkgsFor."${system}".alejandra);+ devShells = forAllSystems (system:+ let+ pkgs = nixpkgsFor.${system};+ staticShell = pkgs.mkShell.override {+ stdenv = pkgs.pkgsStatic.stdenv;+ };+ in+ {+ default = staticShell {+ nativeBuildInputs = [+ pkgs.go+ pkgs.air+ pkgs.gopls+ pkgs.httpie+ pkgs.indigo-lexgen+ pkgs.litecli+ pkgs.websocat+ pkgs.tailwindcss+ ];+ };+ });+ apps = forAllSystems (system:+ let+ pkgs = nixpkgsFor."${system}";+ air-watcher = name:+ pkgs.writeShellScriptBin "run"+ ''+ ${pkgs.air}/bin/air -c /dev/null \+ -build.cmd "${pkgs.tailwindcss}/bin/tailwindcss -i input.css -o ./appview/pages/static/tw.css && ${pkgs.go}/bin/go build -o ./out/${name}.out ./cmd/${name}/main.go" \+ -build.bin "./out/${name}.out" \+ -build.include_ext "go,html,css"+ '';+ in+ {+ watch-appview = {+ type = "app";+ program = ''${air-watcher "appview"}/bin/run'';+ };+ watch-knotserver = {+ type = "app";+ program = ''${air-watcher "knotserver"}/bin/run'';+ };+ });};- packages = forAllSystems (system: {- inherit (nixpkgsFor."${system}") indigo-lexgen appview knotserver;- });- defaultPackage = forAllSystems (system: nixpkgsFor.${system}.appview);- formatter = forAllSystems (system: nixpkgsFor."${system}".alejandra);- devShells = forAllSystems (system: let- pkgs = nixpkgsFor.${system};- staticShell = pkgs.mkShell.override {- stdenv = pkgs.pkgsStatic.stdenv;- };- in {- default = staticShell {- nativeBuildInputs = [- pkgs.go- pkgs.air- pkgs.gopls- pkgs.httpie- pkgs.indigo-lexgen- pkgs.litecli- pkgs.websocat- pkgs.tailwindcss- ];- };- });- apps = forAllSystems (system: let- pkgs = nixpkgsFor."${system}";- air-watcher = name:- pkgs.writeShellScriptBin "run"- ''- ${pkgs.air}/bin/air -c /dev/null \- -build.cmd "${pkgs.tailwindcss}/bin/tailwindcss -i input.css -o ./appview/pages/static/tw.css && ${pkgs.go}/bin/go build -o ./out/${name}.out ./cmd/${name}/main.go" \- -build.bin "./out/${name}.out" \- -build.include_ext "go,html,css"- '';- in {- watch-appview = {- type = "app";- program = ''${air-watcher "appview"}/bin/run'';- };- watch-knotserver = {- type = "app";- program = ''${air-watcher "knotserver"}/bin/run'';- };- });- };}
MODIFIED
knotserver/routes.go
MODIFIED
knotserver/routes.go
@@ -342,11 +342,12 @@rtags := []*types.TagReference{}for _, tag := range tags {tr := types.TagReference{- Ref: types.Reference{- Name: tag.Name(),- Hash: tag.Hash().String(),- },Tag: tag.TagObject(),+ }++ tr.Reference = types.Reference{+ Name: tag.Name(),+ Hash: tag.Hash().String(),}if tag.Message() != "" {
MODIFIED
types/repo.go
MODIFIED
types/repo.go
@@ -39,9 +39,9 @@ Files []NiceTree `json:"files,omitempty"`}type TagReference struct {- Ref Reference `json:"ref,omitempty"`- Tag *object.Tag `json:"tag,omitempty"`- Message string `json:"message,omitempty"`+ Reference `json:"ref,omitempty"`+ Tag *object.Tag `json:"tag,omitempty"`+ Message string `json:"message,omitempty"`}type Reference struct {