Эх сурвалжийг харах

#2052 advanced select ops for system notices

Unknwon 9 жил өмнө
parent
commit
f41360d864

+ 1 - 1
README.md

@@ -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>

+ 1 - 1
cmd/web.go

@@ -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)

+ 1 - 1
conf/app.ini

@@ -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
 

+ 8 - 2
conf/locale/locale_en-US.ini

@@ -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>

+ 1 - 1
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())

+ 13 - 1
models/admin.go

@@ -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
+}

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
modules/bindata/bindata.go


+ 8 - 2
public/css/gogs.css

@@ -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,

+ 66 - 19
public/js/gogs.js

@@ -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({

+ 17 - 3
public/less/_admin.less

@@ -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;
+				}
 			}
 		}
 	}

+ 17 - 8
routers/admin/notice.go

@@ -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
templates/.VERSION

@@ -1 +1 @@
-0.7.30.1204 Beta
+0.7.31.1205 Beta

+ 48 - 10
templates/admin/notice.tmpl

@@ -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" .}}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно