#2052 advanced select ops for system notices
This commit is contained in:
parent
e82ee40e9e
commit
f41360d864
13 changed files with 186 additions and 54 deletions
|
@ -5,7 +5,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
|
|||
|
||||
![](public/img/gogs-large-resize.png)
|
||||
|
||||
##### Current version: 0.7.30 Beta
|
||||
##### Current version: 0.7.31 Beta
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
|
|
|
@ -280,7 +280,7 @@ func runWeb(ctx *cli.Context) {
|
|||
|
||||
m.Group("/notices", func() {
|
||||
m.Get("", admin.Notices)
|
||||
m.Get("/:id:int/delete", admin.DeleteNotice)
|
||||
m.Post("/delete", admin.DeleteNotices)
|
||||
m.Get("/empty", admin.EmptyNotices)
|
||||
})
|
||||
}, adminReq)
|
||||
|
|
|
@ -32,7 +32,7 @@ USER_PAGING_NUM = 50
|
|||
; Number of repos that are showed in one page
|
||||
REPO_PAGING_NUM = 50
|
||||
; Number of notices that are showed in one page
|
||||
NOTICE_PAGING_NUM = 50
|
||||
NOTICE_PAGING_NUM = 25
|
||||
; Number of organization that are showed in one page
|
||||
ORG_PAGING_NUM = 50
|
||||
|
||||
|
|
|
@ -991,12 +991,18 @@ monitor.start = Start Time
|
|||
monitor.execute_time = Execution Time
|
||||
|
||||
notices.system_notice_list = System Notices
|
||||
notices.empty_all = Remove All Notices
|
||||
notices.view_detail_header = View Notice Detail
|
||||
notices.actions = Actions
|
||||
notices.select_all = Select All
|
||||
notices.deselect_all = Deselect All
|
||||
notices.inverse_selection = Inverse Selection
|
||||
notices.delete_selected = Delete Selected
|
||||
notices.delete_all = Delete All Notices
|
||||
notices.type = Type
|
||||
notices.type_1 = Repository
|
||||
notices.desc = Description
|
||||
notices.op = Op.
|
||||
notices.delete_success = System notice has been deleted successfully.
|
||||
notices.delete_success = System notices have been deleted successfully.
|
||||
|
||||
[action]
|
||||
create_repo = created repository <a href="%s">%s</a>
|
||||
|
|
2
gogs.go
2
gogs.go
|
@ -17,7 +17,7 @@ import (
|
|||
"github.com/gogits/gogs/modules/setting"
|
||||
)
|
||||
|
||||
const APP_VER = "0.7.30.1204 Beta"
|
||||
const APP_VER = "0.7.31.1205 Beta"
|
||||
|
||||
func init() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"github.com/gogits/gogs/modules/base"
|
||||
)
|
||||
|
||||
type NoticeType int
|
||||
|
@ -18,7 +21,7 @@ const (
|
|||
|
||||
// Notice represents a system notice for admin.
|
||||
type Notice struct {
|
||||
Id int64
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Type NoticeType
|
||||
Description string `xorm:"TEXT"`
|
||||
Created time.Time `xorm:"CREATED"`
|
||||
|
@ -71,3 +74,12 @@ func DeleteNotices(start, end int64) error {
|
|||
_, err := sess.Delete(new(Notice))
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteNoticesByIDs deletes notices by given IDs.
|
||||
func DeleteNoticesByIDs(ids []int64) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
_, err := x.Where("id IN (" + strings.Join(base.Int64sToStrings(ids), ",") + ")").Delete(new(Notice))
|
||||
return err
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2999,12 +2999,18 @@ footer .container .links > *:first-child {
|
|||
padding: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.admin .table.segment:not(.striped) {
|
||||
padding-top: 5px;
|
||||
}
|
||||
.admin .table.segment:not(.striped) thead th:last-child {
|
||||
padding-right: 5px !important;
|
||||
}
|
||||
.admin .table.segment th {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.admin .table.segment th:first-of-type,
|
||||
.admin .table.segment td:first-of-type {
|
||||
.admin .table.segment:not(.select) th:first-of-type,
|
||||
.admin .table.segment:not(.select) td:first-of-type {
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
.admin .ui.header,
|
||||
|
|
|
@ -319,23 +319,23 @@ function initRepository() {
|
|||
$('#edit-title').click(editTitleToggle);
|
||||
$('#cancel-edit-title').click(editTitleToggle);
|
||||
$('#save-edit-title').click(editTitleToggle).
|
||||
click(function () {
|
||||
if ($edit_input.val().length == 0 ||
|
||||
$edit_input.val() == $issue_title.text()) {
|
||||
$edit_input.val($issue_title.text());
|
||||
return false;
|
||||
}
|
||||
|
||||
$.post($(this).data('update-url'), {
|
||||
"_csrf": csrf,
|
||||
"title": $edit_input.val()
|
||||
},
|
||||
function (data) {
|
||||
$edit_input.val(data.title);
|
||||
$issue_title.text(data.title);
|
||||
});
|
||||
click(function () {
|
||||
if ($edit_input.val().length == 0 ||
|
||||
$edit_input.val() == $issue_title.text()) {
|
||||
$edit_input.val($issue_title.text());
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
$.post($(this).data('update-url'), {
|
||||
"_csrf": csrf,
|
||||
"title": $edit_input.val()
|
||||
},
|
||||
function (data) {
|
||||
$edit_input.val(data.title);
|
||||
$issue_title.text(data.title);
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// Edit issue or comment content
|
||||
$('.edit-content').click(function () {
|
||||
|
@ -607,6 +607,50 @@ function initAdmin() {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Notice
|
||||
if ($('.admin.notice')) {
|
||||
var $detail_modal = $('#detail-modal');
|
||||
|
||||
// Attach view detail modals
|
||||
$('.view-detail').click(function () {
|
||||
$detail_modal.find('.content p').text($(this).data('content'));
|
||||
$detail_modal.modal('show');
|
||||
return false;
|
||||
});
|
||||
|
||||
// Select actions
|
||||
var $checkboxes = $('.select.table .ui.checkbox');
|
||||
$('.select.action').click(function () {
|
||||
switch ($(this).data('action')) {
|
||||
case 'select-all':
|
||||
$checkboxes.checkbox('check');
|
||||
break;
|
||||
case 'deselect-all':
|
||||
$checkboxes.checkbox('uncheck');
|
||||
break;
|
||||
case 'inverse':
|
||||
$checkboxes.checkbox('toggle');
|
||||
break;
|
||||
}
|
||||
});
|
||||
$('#delete-selection').click(function () {
|
||||
var $this = $(this);
|
||||
$this.addClass("loading disabled");
|
||||
var ids = [];
|
||||
$checkboxes.each(function () {
|
||||
if ($(this).checkbox('is checked')) {
|
||||
ids.push($(this).data('id'));
|
||||
}
|
||||
});
|
||||
$.post($this.data('link'), {
|
||||
"_csrf": csrf,
|
||||
"ids": ids
|
||||
}).done(function () {
|
||||
window.location.href = $this.data('redirect');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function buttonsClickOnEnter() {
|
||||
|
@ -734,9 +778,9 @@ $(document).ready(function () {
|
|||
// Show exact time
|
||||
$('.time-since').each(function () {
|
||||
$(this).addClass('poping up').
|
||||
attr('data-content', $(this).attr('title')).
|
||||
attr('data-variation', 'inverted tiny').
|
||||
attr('title', '');
|
||||
attr('data-content', $(this).attr('title')).
|
||||
attr('data-variation', 'inverted tiny').
|
||||
attr('title', '');
|
||||
});
|
||||
|
||||
// Semantic UI modules.
|
||||
|
@ -750,6 +794,9 @@ $(document).ready(function () {
|
|||
$('.slide.up.dropdown').dropdown({
|
||||
transition: 'slide up'
|
||||
});
|
||||
$('.upward.dropdown').dropdown({
|
||||
direction: 'upward'
|
||||
});
|
||||
$('.ui.accordion').accordion();
|
||||
$('.ui.checkbox').checkbox();
|
||||
$('.ui.progress').progress({
|
||||
|
|
|
@ -5,13 +5,27 @@
|
|||
.table.segment {
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
|
||||
&:not(.striped) {
|
||||
padding-top: 5px;
|
||||
|
||||
thead {
|
||||
th:last-child {
|
||||
padding-right: 5px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
th, td {
|
||||
&:first-of-type {
|
||||
padding-left: 15px !important;
|
||||
|
||||
&:not(.select) {
|
||||
th, td {
|
||||
&:first-of-type {
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/Unknwon/paginater"
|
||||
|
||||
"github.com/gogits/gogs/models"
|
||||
|
@ -41,15 +42,23 @@ func Notices(ctx *middleware.Context) {
|
|||
ctx.HTML(200, NOTICES)
|
||||
}
|
||||
|
||||
func DeleteNotice(ctx *middleware.Context) {
|
||||
id := ctx.ParamsInt64(":id")
|
||||
if err := models.DeleteNotice(id); err != nil {
|
||||
ctx.Handle(500, "DeleteNotice", err)
|
||||
return
|
||||
func DeleteNotices(ctx *middleware.Context) {
|
||||
strs := ctx.QueryStrings("ids[]")
|
||||
ids := make([]int64, 0, len(strs))
|
||||
for i := range strs {
|
||||
id := com.StrTo(strs[i]).MustInt64()
|
||||
if id > 0 {
|
||||
ids = append(ids, id)
|
||||
}
|
||||
}
|
||||
|
||||
if err := models.DeleteNoticesByIDs(ids); err != nil {
|
||||
ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error())
|
||||
ctx.Status(500)
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("admin.notices.delete_success"))
|
||||
ctx.Status(200)
|
||||
}
|
||||
log.Trace("System notice deleted by admin (%s): %d", ctx.User.Name, id)
|
||||
ctx.Flash.Success(ctx.Tr("admin.notices.delete_success"))
|
||||
ctx.Redirect(setting.AppSubUrl + "/admin/notices")
|
||||
}
|
||||
|
||||
func EmptyNotices(ctx *middleware.Context) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.7.30.1204 Beta
|
||||
0.7.31.1205 Beta
|
|
@ -1,5 +1,5 @@
|
|||
{{template "base/head" .}}
|
||||
<div class="admin user">
|
||||
<div class="admin notice">
|
||||
<div class="ui container">
|
||||
<div class="ui grid">
|
||||
{{template "admin/navbar" .}}
|
||||
|
@ -7,32 +7,62 @@
|
|||
{{template "base/alert" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.notices.system_notice_list"}} ({{.i18n.Tr "admin.total" .Total}})
|
||||
<div class="ui right">
|
||||
<a class="ui red tiny button" href="{{AppSubUrl}}/admin/notices/empty">{{.i18n.Tr "admin.notices.empty_all"}}</a>
|
||||
</div>
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<table class="ui very basic striped table">
|
||||
<table class="ui very basic select selectable table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>ID</th>
|
||||
<th>{{.i18n.Tr "admin.notices.type"}}</th>
|
||||
<th>{{.i18n.Tr "admin.notices.desc"}}</th>
|
||||
<th>{{.i18n.Tr "admin.users.created"}}</th>
|
||||
<th width="100px">{{.i18n.Tr "admin.users.created"}}</th>
|
||||
<th>{{.i18n.Tr "admin.notices.op"}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Notices}}
|
||||
<tr>
|
||||
<td>{{.Id}}</td>
|
||||
<td class="collapsing">
|
||||
<div class="ui fitted checkbox" data-id="{{.ID}}">
|
||||
<input type="checkbox"> <label></label>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{.ID}}</td>
|
||||
<td>{{$.i18n.Tr .TrStr}}</td>
|
||||
<td><span>{{.Description}}</span></td>
|
||||
<td>{{.Created}}</td>
|
||||
<td><a href="{{AppSubUrl}}/admin/notices/{{.Id}}/delete"><i class="fa fa-trash-o text-red"></i></a></td>
|
||||
<td>{{SubStr .Description 0 120}}...</td>
|
||||
<td><span class="poping up" data-content="{{.Created}}" data-variation="inverted tiny">{{DateFmtShort .Created}}</span></td>
|
||||
<td><a href="#"><i class="browser icon view-detail" data-content="{{.Description}}"></i></a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
<tfoot class="full-width">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th colspan="5">
|
||||
<div class="ui right">
|
||||
<a class="ui red small button" href="{{AppSubUrl}}/admin/notices/empty">{{.i18n.Tr "admin.notices.delete_all"}}</a>
|
||||
</div>
|
||||
<div class="ui floating upward dropdown small button">
|
||||
<span class="text">{{.i18n.Tr "admin.notices.actions"}}</span>
|
||||
<div class="menu">
|
||||
<div class="item select action" data-action="select-all">
|
||||
{{.i18n.Tr "admin.notices.select_all"}}
|
||||
</div>
|
||||
<div class="item select action" data-action="deselect-all">
|
||||
{{.i18n.Tr "admin.notices.deselect_all"}}
|
||||
</div>
|
||||
<div class="item select action" data-action="inverse">
|
||||
{{.i18n.Tr "admin.notices.inverse_selection"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui small teal button" id="delete-selection" data-link="{{.Link}}/delete" data-redirect="{{.Link}}?page={{.Page.Current}}">
|
||||
{{.i18n.Tr "admin.notices.delete_selected"}}
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
@ -63,4 +93,12 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui modal" id="detail-modal">
|
||||
<i class="close icon"></i>
|
||||
<div class="header">{{$.i18n.Tr "admin.notices.view_detail_header"}}</div>
|
||||
<div class="content">
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
|
|
Loading…
Add table
Reference in a new issue