mirror of
https://git.zx2c4.com/cgit
synced 2024-11-26 02:18:42 +00:00
ui-repolist: Allow sections to be collapsible
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>
This commit is contained in:
parent
84b158abe0
commit
1a66e7f3c1
27
cgit.c
27
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;
|
||||
|
13
cgit.h
13
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);
|
||||
|
@ -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
|
||||
|
@ -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++;
|
||||
}
|
||||
|
5
shared.c
5
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);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user