]> granicus.if.org Git - cgit/commitdiff
ui-repolist: Allow sections to be collapsible jk/collapsible-sections
authorAndy Doan <andy.doan@linaro.org>
Tue, 13 Sep 2016 03:54:08 +0000 (22:54 -0500)
committerJohn Keeping <john@keeping.me.uk>
Sat, 1 Oct 2016 10:51:07 +0000 (11:51 +0100)
The index page can be difficult to navigate for really large git
servers. This change allows a configuration like:

 section-collapse=people
 section-collapse=tests

And an index page would only display the "people" and "tests" section
headers entries (not their repos) with a hyperlink that can be used to
drill down into each section.

Additionally the boolean logic around displaying sections in
ui-repolist.c was simplified to eliminate an impossible condition.

Signed-off-by: Andy Doan <andy.doan@linaro.org>
Reviewed-by: John Keeping <john@keeping.me.uk>
Signed-off-by: John Keeping <john@keeping.me.uk>
cgit.c
cgit.h
cgitrc.5.txt
scan-tree.c
shared.c
ui-repolist.c

diff --git a/cgit.c b/cgit.c
index 2f29aa6d33082cd105d34f2bc195db493e3c90d3..3266a9896b411a8615b009b9baf7855333bd510e 100644 (file)
--- a/cgit.c
+++ b/cgit.c
@@ -77,7 +77,7 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va
                item = string_list_append(&repo->submodules, xstrdup(name + 12));
                item->util = xstrdup(value);
        } else if (!strcmp(name, "section"))
-               repo->section = xstrdup(value);
+               repo->section = get_or_create_section(value);
        else if (!strcmp(name, "readme") && value != NULL) {
                if (repo->readme.items == ctx.cfg.readme.items)
                        memset(&repo->readme, 0, sizeof(repo->readme));
@@ -107,7 +107,7 @@ static void repo_config(struct cgit_repo *repo, const char *name, const char *va
 static void config_cb(const char *name, const char *value)
 {
        if (!strcmp(name, "section") || !strcmp(name, "repo.group"))
-               ctx.cfg.section = xstrdup(value);
+               ctx.cfg.section = get_or_create_section(value);
        else if (!strcmp(name, "repo.url"))
                ctx.repo = cgit_add_repo(value);
        else if (ctx.repo && !strcmp(name, "repo.path"))
@@ -242,6 +242,8 @@ static void config_cb(const char *name, const char *value)
                ctx.cfg.section_from_path = atoi(value);
        else if (!strcmp(name, "repository-sort"))
                ctx.cfg.repository_sort = xstrdup(value);
+       else if (!strcmp(name, "section-collapse"))
+               get_or_create_section(value)->collapse = 1;
        else if (!strcmp(name, "section-sort"))
                ctx.cfg.section_sort = atoi(value);
        else if (!strcmp(name, "source-filter"))
@@ -385,7 +387,7 @@ static void prepare_context(void)
        ctx.cfg.root_desc = "a fast webinterface for the git dscm";
        ctx.cfg.scan_hidden_path = 0;
        ctx.cfg.script_name = CGIT_SCRIPT_NAME;
-       ctx.cfg.section = "";
+       ctx.cfg.section = NULL;
        ctx.cfg.repository_sort = "name";
        ctx.cfg.section_sort = 1;
        ctx.cfg.summary_branches = 10;
@@ -794,7 +796,7 @@ static void print_repo(FILE *f, struct cgit_repo *repo)
        if (repo->module_link)
                fprintf(f, "repo.module-link=%s\n", repo->module_link);
        if (repo->section)
-               fprintf(f, "repo.section=%s\n", repo->section);
+               fprintf(f, "repo.section=%s\n", repo->section->name);
        if (repo->homepage)
                fprintf(f, "repo.homepage=%s\n", repo->homepage);
        if (repo->clone_url)
@@ -1026,6 +1028,23 @@ static int calc_ttl(void)
        return ctx.cfg.cache_repo_ttl;
 }
 
+struct cgit_section* get_or_create_section(const char *section)
+{
+       struct cgit_section *ptr = ctx.sections;
+       while(ptr) {
+               if (!strcmp(section, ptr->name))
+                       return ptr;
+               ptr = ptr->next;
+       }
+       /* Not found insert into head of list */
+       ptr = xmalloc(sizeof(*ptr));
+       ptr->name = xstrdup(section);
+       ptr->collapse = 0;
+       ptr->next = ctx.sections;
+       ctx.sections = ptr;
+       return ptr;
+}
+
 int cmd_main(int argc, const char **argv)
 {
        const char *path;
diff --git a/cgit.h b/cgit.h
index df4231290ba2642b804b3c0e16dc121c9ee9bbc3..5d81fe8fe0645b617da943e29c09f12a3b26e703 100644 (file)
--- a/cgit.h
+++ b/cgit.h
@@ -75,6 +75,12 @@ struct cgit_exec_filter {
        int pid;
 };
 
+struct cgit_section {
+       unsigned int collapse : 1;
+       char *name;
+       struct cgit_section *next;
+};
+
 struct cgit_repo {
        char *url;
        char *name;
@@ -85,7 +91,7 @@ struct cgit_repo {
        char *defbranch;
        char *module_link;
        struct string_list readme;
-       char *section;
+       struct cgit_section *section;
        char *clone_url;
        char *logo;
        char *logo_link;
@@ -208,7 +214,7 @@ struct cgit_config {
        char *root_desc;
        char *root_readme;
        char *script_name;
-       char *section;
+       struct cgit_section *section;
        char *repository_sort;
        char *virtual_root;     /* Always ends with '/'. */
        char *strict_export;
@@ -305,6 +311,7 @@ struct cgit_context {
        struct cgit_config cfg;
        struct cgit_repo *repo;
        struct cgit_page page;
+       struct cgit_section *sections;
 };
 
 typedef int (*write_archive_fn_t)(const char *, const char *);
@@ -322,6 +329,8 @@ extern struct cgit_repolist cgit_repolist;
 extern struct cgit_context ctx;
 extern const struct cgit_snapshot_format cgit_snapshot_formats[];
 
+extern struct cgit_section* get_or_create_section(const char *section);
+
 extern char *cgit_default_repo_desc;
 extern struct cgit_repo *cgit_add_repo(const char *url);
 extern struct cgit_repo *cgit_get_repoinfo(const char *url);
index 9fcf445bef2df3cb226d2dffea85438e16ead17f..27626578d9478d2a468bb4f95fd488345d18bd39 100644 (file)
@@ -404,6 +404,11 @@ section::
        after this option will inherit the current section name. Default value:
        none.
 
+section-collapse::
+       Name of a section to "collapse" and not display on the index page.
+       Multiple config entries can be specified and each one will be
+       collapsed.
+
 section-sort::
        Flag which, when set to "1", will sort the sections on the repository
        listing by name. Set this flag to "0" if the order in the cgitrc file should
index 1cb4e5d320d7bd98354cde16948795e46a35baf1..fa21fc49febb39e2f62bae9760fbd953fb82808f 100644 (file)
@@ -164,10 +164,10 @@ static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn)
                }
                if (slash && !n) {
                        *slash = '\0';
-                       repo->section = xstrdup(rel.buf);
+                       repo->section = get_or_create_section(rel.buf);
                        *slash = '/';
-                       if (starts_with(repo->name, repo->section)) {
-                               repo->name += strlen(repo->section);
+                       if (starts_with(repo->name, repo->section->name)) {
+                               repo->name += strlen(repo->section->name);
                                if (*repo->name == '/')
                                        repo->name++;
                        }
index 571fbba6cb67ba6d623e544348d58380e168d614..e4627e14270da11664a18dd48e613a167ffffff7 100644 (file)
--- a/shared.c
+++ b/shared.c
@@ -443,13 +443,16 @@ typedef struct {
 
 void cgit_prepare_repo_env(struct cgit_repo * repo)
 {
+       char *section = NULL;
+       if (repo->section)
+               section = repo->section->name;
        cgit_env_var env_vars[] = {
                { .name = "CGIT_REPO_URL", .value = repo->url },
                { .name = "CGIT_REPO_NAME", .value = repo->name },
                { .name = "CGIT_REPO_PATH", .value = repo->path },
                { .name = "CGIT_REPO_OWNER", .value = repo->owner },
                { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch },
-               { .name = "CGIT_REPO_SECTION", .value = repo->section },
+               { .name = "CGIT_REPO_SECTION", .value = section },
                { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url }
        };
        int env_var_count = ARRAY_SIZE(env_vars);
index 3f967a8d63ba3db60bd1336f4847e234b88c9e61..e9676b8b4d6b7a66bcb5a4f8bfabb7282ebf7a62 100644 (file)
@@ -188,10 +188,16 @@ static int sort_section(const void *a, const void *b)
 {
        const struct cgit_repo *r1 = a;
        const struct cgit_repo *r2 = b;
+       const char *s1 = "";
+       const char *s2 = "";
        int result;
        time_t t;
 
-       result = cmp(r1->section, r2->section);
+       if (r1->section)
+               s1 = r1->section->name;
+       if (r2->section)
+               s2 = r2->section->name;
+       result = cmp(s1, s2);
        if (!result) {
                if (!strcmp(ctx.cfg.repository_sort, "age")) {
                        // get_repo_modtime caches the value in r->mtime, so we don't
@@ -273,8 +279,8 @@ static int sort_repolist(char *field)
 void cgit_print_repolist(void)
 {
        int i, columns = 3, hits = 0, header = 0;
-       char *last_section = NULL;
-       char *section;
+       struct cgit_section *last_section = NULL;
+       struct cgit_section *section;
        int sorted = 0;
 
        if (!any_repos_visible()) {
@@ -294,12 +300,10 @@ void cgit_print_repolist(void)
 
        if (ctx.cfg.index_header)
                html_include(ctx.cfg.index_header);
-
        if (ctx.qry.sort)
                sorted = sort_repolist(ctx.qry.sort);
        else if (ctx.cfg.section_sort)
                sort_repolist("section");
-
        html("<table summary='repository list' class='list nowrap'>");
        for (i = 0; i < cgit_repolist.count; i++) {
                ctx.repo = &cgit_repolist.repos[i];
@@ -313,23 +317,22 @@ void cgit_print_repolist(void)
                if (!header++)
                        print_header();
                section = ctx.repo->section;
-               if (section && !strcmp(section, ""))
+               if (section && !strcmp(section->name, ""))
                        section = NULL;
-               if (!sorted &&
-                   ((last_section == NULL && section != NULL) ||
-                   (last_section != NULL && section == NULL) ||
-                   (last_section != NULL && section != NULL &&
-                    strcmp(section, last_section)))) {
+               if (!sorted && section && last_section != section ) {
                        htmlf("<tr class='nohover'><td colspan='%d' class='reposection'>",
                              columns);
                        html("<a href='");
-                       html_attr(section);
+                       html_attr(section->name);
                        html("'>");
-                       html_txt(section);
+                       html_txt(section->name);
                        html("</a>");
                        html("</td></tr>");
-                       last_section = section;
                }
+               last_section = section;
+               if (section && section->collapse && !strstr(ctx.qry.url, section->name))
+                       continue;
+
                htmlf("<tr><td class='%s'>",
                      !sorted && section ? "sublevel-repo" : "toplevel-repo");
                cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL);