Applying migration changes (#2752)
* Applying migration changes * Fixing linter erros * Restoring userID * Updated user id length * Update server/app/category_boards.go * Skiped creating categories for boards belonging to DMs * Handled private group messages as well * fix sql error for insert_at * fix timestamp parsing Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com> Co-authored-by: Doug Lauder <wiggin77@warpmail.net>
This commit is contained in:
parent
89cc947a21
commit
bc37e97ae9
39 changed files with 300 additions and 281 deletions
|
@ -39,7 +39,7 @@ import wsClient, {
|
|||
ACTION_UPDATE_BLOCK,
|
||||
ACTION_UPDATE_CLIENT_CONFIG,
|
||||
ACTION_UPDATE_SUBSCRIPTION,
|
||||
ACTION_UPDATE_CATEGORY, ACTION_UPDATE_BLOCK_CATEGORY, ACTION_UPDATE_BOARD,
|
||||
ACTION_UPDATE_CATEGORY, ACTION_UPDATE_BOARD_CATEGORY, ACTION_UPDATE_BOARD,
|
||||
} from './../../../webapp/src/wsclient'
|
||||
|
||||
import manifest from './manifest'
|
||||
|
@ -273,7 +273,7 @@ export default class Plugin {
|
|||
// register websocket handlers
|
||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_BOARD}`, (e: any) => wsClient.updateHandler(e.data))
|
||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_CATEGORY}`, (e: any) => wsClient.updateHandler(e.data))
|
||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_BLOCK_CATEGORY}`, (e: any) => wsClient.updateHandler(e.data))
|
||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_BOARD_CATEGORY}`, (e: any) => wsClient.updateHandler(e.data))
|
||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_CLIENT_CONFIG}`, (e: any) => wsClient.updateClientConfigHandler(e.data))
|
||||
this.registry?.registerWebSocketEventHandler(`custom_${manifest.id}_${ACTION_UPDATE_SUBSCRIPTION}`, (e: any) => wsClient.updateSubscriptionHandler(e.data))
|
||||
this.registry?.registerWebSocketEventHandler('plugin_statuses_changed', (e: any) => wsClient.pluginStatusesChangedHandler(e.data))
|
||||
|
|
|
@ -135,8 +135,8 @@ func (a *API) RegisterRoutes(r *mux.Router) {
|
|||
apiv2.HandleFunc("/teams/{teamID}/categories/{categoryID}", a.sessionRequired(a.handleDeleteCategory)).Methods(http.MethodDelete)
|
||||
|
||||
// Category Block APIs
|
||||
apiv2.HandleFunc("/teams/{teamID}/categories", a.sessionRequired(a.handleGetUserCategoryBlocks)).Methods(http.MethodGet)
|
||||
apiv2.HandleFunc("/teams/{teamID}/categories/{categoryID}/blocks/{blockID}", a.sessionRequired(a.handleUpdateCategoryBlock)).Methods(http.MethodPost)
|
||||
apiv2.HandleFunc("/teams/{teamID}/categories", a.sessionRequired(a.handleGetUserCategoryBoards)).Methods(http.MethodGet)
|
||||
apiv2.HandleFunc("/teams/{teamID}/categories/{categoryID}/boards/{boardID}", a.sessionRequired(a.handleUpdateCategoryBoard)).Methods(http.MethodPost)
|
||||
|
||||
// Get Files API
|
||||
apiv2.HandleFunc("/files/teams/{teamID}/{boardID}/{filename}", a.attachSession(a.handleServeFile, false)).Methods("GET")
|
||||
|
@ -539,7 +539,7 @@ func (a *API) handleDeleteCategory(w http.ResponseWriter, r *http.Request) {
|
|||
auditRec.Success()
|
||||
}
|
||||
|
||||
func (a *API) handleGetUserCategoryBlocks(w http.ResponseWriter, r *http.Request) {
|
||||
func (a *API) handleGetUserCategoryBoards(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session := ctx.Value(sessionContextKey).(*model.Session)
|
||||
userID := session.UserID
|
||||
|
@ -550,7 +550,7 @@ func (a *API) handleGetUserCategoryBlocks(w http.ResponseWriter, r *http.Request
|
|||
auditRec := a.makeAuditRecord(r, "getUserCategoryBlocks", audit.Fail)
|
||||
defer a.audit.LogRecord(audit.LevelModify, auditRec)
|
||||
|
||||
categoryBlocks, err := a.app.GetUserCategoryBlocks(userID, teamID)
|
||||
categoryBlocks, err := a.app.GetUserCategoryBoards(userID, teamID)
|
||||
if err != nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
|
||||
return
|
||||
|
@ -566,13 +566,13 @@ func (a *API) handleGetUserCategoryBlocks(w http.ResponseWriter, r *http.Request
|
|||
auditRec.Success()
|
||||
}
|
||||
|
||||
func (a *API) handleUpdateCategoryBlock(w http.ResponseWriter, r *http.Request) {
|
||||
auditRec := a.makeAuditRecord(r, "updateCategoryBlock", audit.Fail)
|
||||
func (a *API) handleUpdateCategoryBoard(w http.ResponseWriter, r *http.Request) {
|
||||
auditRec := a.makeAuditRecord(r, "updateCategoryBoard", audit.Fail)
|
||||
defer a.audit.LogRecord(audit.LevelModify, auditRec)
|
||||
|
||||
vars := mux.Vars(r)
|
||||
categoryID := vars["categoryID"]
|
||||
blockID := vars["blockID"]
|
||||
boardID := vars["boardID"]
|
||||
teamID := vars["teamID"]
|
||||
|
||||
ctx := r.Context()
|
||||
|
@ -580,7 +580,7 @@ func (a *API) handleUpdateCategoryBlock(w http.ResponseWriter, r *http.Request)
|
|||
userID := session.UserID
|
||||
|
||||
// TODO: Check the category and the team matches
|
||||
err := a.app.AddUpdateUserCategoryBlock(teamID, userID, categoryID, blockID)
|
||||
err := a.app.AddUpdateUserCategoryBoard(teamID, userID, categoryID, boardID)
|
||||
if err != nil {
|
||||
a.errorResponse(w, r.URL.Path, http.StatusInternalServerError, "", err)
|
||||
return
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package app
|
||||
|
||||
import "github.com/mattermost/focalboard/server/model"
|
||||
|
||||
func (a *App) GetUserCategoryBlocks(userID, teamID string) ([]model.CategoryBlocks, error) {
|
||||
return a.store.GetUserCategoryBlocks(userID, teamID)
|
||||
}
|
||||
|
||||
func (a *App) AddUpdateUserCategoryBlock(teamID, userID, categoryID, blockID string) error {
|
||||
err := a.store.AddUpdateCategoryBlock(userID, categoryID, blockID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
a.wsAdapter.BroadcastCategoryBlockChange(
|
||||
teamID,
|
||||
userID,
|
||||
model.BlockCategoryWebsocketData{
|
||||
BlockID: blockID,
|
||||
CategoryID: categoryID,
|
||||
})
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
27
server/app/category_boards.go
Normal file
27
server/app/category_boards.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package app
|
||||
|
||||
import "github.com/mattermost/focalboard/server/model"
|
||||
|
||||
func (a *App) GetUserCategoryBoards(userID, teamID string) ([]model.CategoryBoards, error) {
|
||||
return a.store.GetUserCategoryBoards(userID, teamID)
|
||||
}
|
||||
|
||||
func (a *App) AddUpdateUserCategoryBoard(teamID, userID, categoryID, boardID string) error {
|
||||
err := a.store.AddUpdateCategoryBoard(userID, categoryID, boardID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.blockChangeNotifier.Enqueue(func() error {
|
||||
a.wsAdapter.BroadcastCategoryBoardChange(
|
||||
teamID,
|
||||
userID,
|
||||
model.BoardCategoryWebsocketData{
|
||||
BoardID: boardID,
|
||||
CategoryID: categoryID,
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1948,7 +1948,7 @@ func TestPermissionsDeleteCategory(t *testing.T) {
|
|||
runTestCases(t, ttCases, testData, clients)
|
||||
}
|
||||
|
||||
func TestPermissionsUpdateCategoryBlock(t *testing.T) {
|
||||
func TestPermissionsUpdateCategoryBoard(t *testing.T) {
|
||||
th := SetupTestHelperPluginMode(t)
|
||||
defer th.TearDown()
|
||||
testData := setupData(t, th)
|
||||
|
@ -1980,13 +1980,13 @@ func TestPermissionsUpdateCategoryBlock(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
ttCases := []TestCase{
|
||||
{"/teams/test-team/categories/any/blocks/any", methodPost, "", userAnon, http.StatusUnauthorized, 0},
|
||||
{"/teams/test-team/categories/" + categoryNoTeamMember.ID + "/blocks/" + testData.publicBoard.ID, methodPost, "", userNoTeamMember, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryTeamMember.ID + "/blocks/" + testData.publicBoard.ID, methodPost, "", userTeamMember, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryViewer.ID + "/blocks/" + testData.publicBoard.ID, methodPost, "", userViewer, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryCommenter.ID + "/blocks/" + testData.publicBoard.ID, methodPost, "", userCommenter, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryEditor.ID + "/blocks/" + testData.publicBoard.ID, methodPost, "", userEditor, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryAdmin.ID + "/blocks/" + testData.publicBoard.ID, methodPost, "", userAdmin, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/any/boards/any", methodPost, "", userAnon, http.StatusUnauthorized, 0},
|
||||
{"/teams/test-team/categories/" + categoryNoTeamMember.ID + "/boards/" + testData.publicBoard.ID, methodPost, "", userNoTeamMember, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryTeamMember.ID + "/boards/" + testData.publicBoard.ID, methodPost, "", userTeamMember, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryViewer.ID + "/boards/" + testData.publicBoard.ID, methodPost, "", userViewer, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryCommenter.ID + "/boards/" + testData.publicBoard.ID, methodPost, "", userCommenter, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryEditor.ID + "/boards/" + testData.publicBoard.ID, methodPost, "", userEditor, http.StatusOK, 0},
|
||||
{"/teams/test-team/categories/" + categoryAdmin.ID + "/boards/" + testData.publicBoard.ID, methodPost, "", userAdmin, http.StatusOK, 0},
|
||||
}
|
||||
runTestCases(t, ttCases, testData, clients)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package model
|
|||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BoardType string
|
||||
|
@ -359,5 +360,5 @@ type BoardMemberHistoryEntry struct {
|
|||
|
||||
// The insertion time
|
||||
// required: true
|
||||
InsertAt int64 `json:"insertAt"`
|
||||
InsertAt time.Time `json:"insertAt"`
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package model
|
||||
|
||||
type CategoryBlocks struct {
|
||||
Category
|
||||
BlockIDs []string `json:"blockIDs"`
|
||||
}
|
||||
|
||||
type BlockCategoryWebsocketData struct {
|
||||
BlockID string `json:"blockID"`
|
||||
CategoryID string `json:"categoryID"`
|
||||
}
|
11
server/model/category_boards.go
Normal file
11
server/model/category_boards.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package model
|
||||
|
||||
type CategoryBoards struct {
|
||||
Category
|
||||
BoardIDs []string `json:"boardIDs"`
|
||||
}
|
||||
|
||||
type BoardCategoryWebsocketData struct {
|
||||
BoardID string `json:"boardID"`
|
||||
CategoryID string `json:"categoryID"`
|
||||
}
|
|
@ -36,18 +36,18 @@ func (m *MockStore) EXPECT() *MockStoreMockRecorder {
|
|||
return m.recorder
|
||||
}
|
||||
|
||||
// AddUpdateCategoryBlock mocks base method.
|
||||
func (m *MockStore) AddUpdateCategoryBlock(arg0, arg1, arg2 string) error {
|
||||
// AddUpdateCategoryBoard mocks base method.
|
||||
func (m *MockStore) AddUpdateCategoryBoard(arg0, arg1, arg2 string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddUpdateCategoryBlock", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "AddUpdateCategoryBoard", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddUpdateCategoryBlock indicates an expected call of AddUpdateCategoryBlock.
|
||||
func (mr *MockStoreMockRecorder) AddUpdateCategoryBlock(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
// AddUpdateCategoryBoard indicates an expected call of AddUpdateCategoryBoard.
|
||||
func (mr *MockStoreMockRecorder) AddUpdateCategoryBoard(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddUpdateCategoryBlock", reflect.TypeOf((*MockStore)(nil).AddUpdateCategoryBlock), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddUpdateCategoryBoard", reflect.TypeOf((*MockStore)(nil).AddUpdateCategoryBoard), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// CleanUpSessions mocks base method.
|
||||
|
@ -925,19 +925,19 @@ func (mr *MockStoreMockRecorder) GetUserByUsername(arg0 interface{}) *gomock.Cal
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByUsername", reflect.TypeOf((*MockStore)(nil).GetUserByUsername), arg0)
|
||||
}
|
||||
|
||||
// GetUserCategoryBlocks mocks base method.
|
||||
func (m *MockStore) GetUserCategoryBlocks(arg0, arg1 string) ([]model.CategoryBlocks, error) {
|
||||
// GetUserCategoryBoards mocks base method.
|
||||
func (m *MockStore) GetUserCategoryBoards(arg0, arg1 string) ([]model.CategoryBoards, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetUserCategoryBlocks", arg0, arg1)
|
||||
ret0, _ := ret[0].([]model.CategoryBlocks)
|
||||
ret := m.ctrl.Call(m, "GetUserCategoryBoards", arg0, arg1)
|
||||
ret0, _ := ret[0].([]model.CategoryBoards)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetUserCategoryBlocks indicates an expected call of GetUserCategoryBlocks.
|
||||
func (mr *MockStoreMockRecorder) GetUserCategoryBlocks(arg0, arg1 interface{}) *gomock.Call {
|
||||
// GetUserCategoryBoards indicates an expected call of GetUserCategoryBoards.
|
||||
func (mr *MockStoreMockRecorder) GetUserCategoryBoards(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserCategoryBlocks", reflect.TypeOf((*MockStore)(nil).GetUserCategoryBlocks), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserCategoryBoards", reflect.TypeOf((*MockStore)(nil).GetUserCategoryBoards), arg0, arg1)
|
||||
}
|
||||
|
||||
// GetUsersByTeam mocks base method.
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mattermost/focalboard/server/utils"
|
||||
|
||||
|
@ -181,17 +182,29 @@ func (s *SQLStore) boardMemberHistoryEntriesFromRows(rows *sql.Rows) ([]*model.B
|
|||
|
||||
for rows.Next() {
|
||||
var boardMemberHistoryEntry model.BoardMemberHistoryEntry
|
||||
var insertAt sql.NullString
|
||||
|
||||
err := rows.Scan(
|
||||
&boardMemberHistoryEntry.BoardID,
|
||||
&boardMemberHistoryEntry.UserID,
|
||||
&boardMemberHistoryEntry.Action,
|
||||
&boardMemberHistoryEntry.InsertAt,
|
||||
&insertAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse the insert_at timestamp which is different based on database type.
|
||||
dateTemplate := "2006-01-02T15:04:05Z0700"
|
||||
if s.dbType == model.MysqlDBType {
|
||||
dateTemplate = "2006-01-02 15:04:05.000000"
|
||||
}
|
||||
ts, err := time.Parse(dateTemplate, insertAt.String)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse datetime '%s' for board_members_history scan: %w", insertAt.String, err)
|
||||
}
|
||||
boardMemberHistoryEntry.InsertAt = ts
|
||||
|
||||
boardMemberHistoryEntries = append(boardMemberHistoryEntries, &boardMemberHistoryEntry)
|
||||
}
|
||||
|
||||
|
@ -300,7 +313,7 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri
|
|||
|
||||
existingBoard, err := s.getBoard(db, board.ID)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("insertBoard error occurred while fetching existing board %s: %w", board.ID, err)
|
||||
}
|
||||
|
||||
insertQuery := s.getQueryBuilder(db).Insert("").
|
||||
|
@ -348,7 +361,7 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri
|
|||
|
||||
if _, err := query.Exec(); err != nil {
|
||||
s.logger.Error(`InsertBoard error occurred while updating existing board`, mlog.String("boardID", board.ID), mlog.Err(err))
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("insertBoard error occurred while updating existing board %s: %w", board.ID, err)
|
||||
}
|
||||
} else {
|
||||
insertQueryValues["created_by"] = userID
|
||||
|
@ -357,7 +370,7 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri
|
|||
|
||||
query := insertQuery.SetMap(insertQueryValues).Into(s.tablePrefix + "boards")
|
||||
if _, err := query.Exec(); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("insertBoard error occurred while inserting board %s: %w", board.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,7 +378,7 @@ func (s *SQLStore) insertBoard(db sq.BaseRunner, board *model.Board, userID stri
|
|||
query := insertQuery.SetMap(insertQueryValues).Into(s.tablePrefix + "boards_history")
|
||||
if _, err := query.Exec(); err != nil {
|
||||
s.logger.Error("failed to insert board history", mlog.String("board_id", board.ID), mlog.Err(err))
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to insert board %s history: %w", board.ID, err)
|
||||
}
|
||||
|
||||
return s.getBoard(db, board.ID)
|
||||
|
@ -462,7 +475,7 @@ func (s *SQLStore) insertBoardWithAdmin(db sq.BaseRunner, board *model.Board, us
|
|||
|
||||
nbm, err := s.saveMember(db, bm)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, fmt.Errorf("cannot save member %s while inserting board %s: %w", bm.UserID, bm.BoardID, err)
|
||||
}
|
||||
|
||||
return newBoard, nbm, nil
|
||||
|
@ -507,8 +520,8 @@ func (s *SQLStore) saveMember(db sq.BaseRunner, bm *model.BoardMember) (*model.B
|
|||
if oldMember == nil {
|
||||
addToMembersHistory := s.getQueryBuilder(db).
|
||||
Insert(s.tablePrefix+"board_members_history").
|
||||
Columns("board_id", "user_id", "action", "insert_at").
|
||||
Values(bm.BoardID, bm.UserID, "created", model.GetMillis())
|
||||
Columns("board_id", "user_id", "action").
|
||||
Values(bm.BoardID, bm.UserID, "created")
|
||||
|
||||
if _, err := addToMembersHistory.Exec(); err != nil {
|
||||
return nil, err
|
||||
|
@ -537,8 +550,8 @@ func (s *SQLStore) deleteMember(db sq.BaseRunner, boardID, userID string) error
|
|||
if rowsAffected > 0 {
|
||||
addToMembersHistory := s.getQueryBuilder(db).
|
||||
Insert(s.tablePrefix+"board_members_history").
|
||||
Columns("board_id", "user_id", "action", "insert_at").
|
||||
Values(boardID, userID, "deleted", model.GetMillis())
|
||||
Columns("board_id", "user_id", "action").
|
||||
Values(boardID, userID, "deleted")
|
||||
|
||||
if _, err := addToMembersHistory.Exec(); err != nil {
|
||||
return err
|
||||
|
|
|
@ -15,34 +15,34 @@ var (
|
|||
errDuplicateCategoryEntries = errors.New("duplicate entries found for user-board-category mapping")
|
||||
)
|
||||
|
||||
func (s *SQLStore) getUserCategoryBlocks(db sq.BaseRunner, userID, teamID string) ([]model.CategoryBlocks, error) {
|
||||
func (s *SQLStore) getUserCategoryBoards(db sq.BaseRunner, userID, teamID string) ([]model.CategoryBoards, error) {
|
||||
categories, err := s.getUserCategories(db, userID, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userCategoryBlocks := []model.CategoryBlocks{}
|
||||
userCategoryBoards := []model.CategoryBoards{}
|
||||
for _, category := range categories {
|
||||
blockIDs, err := s.getCategoryBlockAttributes(db, category.ID)
|
||||
boardIDs, err := s.getCategoryBoardAttributes(db, category.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userCategoryBlock := model.CategoryBlocks{
|
||||
userCategoryBoard := model.CategoryBoards{
|
||||
Category: category,
|
||||
BlockIDs: blockIDs,
|
||||
BoardIDs: boardIDs,
|
||||
}
|
||||
|
||||
userCategoryBlocks = append(userCategoryBlocks, userCategoryBlock)
|
||||
userCategoryBoards = append(userCategoryBoards, userCategoryBoard)
|
||||
}
|
||||
|
||||
return userCategoryBlocks, nil
|
||||
return userCategoryBoards, nil
|
||||
}
|
||||
|
||||
func (s *SQLStore) getCategoryBlockAttributes(db sq.BaseRunner, categoryID string) ([]string, error) {
|
||||
func (s *SQLStore) getCategoryBoardAttributes(db sq.BaseRunner, categoryID string) ([]string, error) {
|
||||
query := s.getQueryBuilder(db).
|
||||
Select("block_id").
|
||||
From(s.tablePrefix + "category_blocks").
|
||||
Select("board_id").
|
||||
From(s.tablePrefix + "category_boards").
|
||||
Where(sq.Eq{
|
||||
"category_id": categoryID,
|
||||
"delete_at": 0,
|
||||
|
@ -50,19 +50,19 @@ func (s *SQLStore) getCategoryBlockAttributes(db sq.BaseRunner, categoryID strin
|
|||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
s.logger.Error("getCategoryBlocks error fetching categoryblocks", mlog.String("categoryID", categoryID), mlog.Err(err))
|
||||
s.logger.Error("getCategoryBoards error fetching categoryblocks", mlog.String("categoryID", categoryID), mlog.Err(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.categoryBlocksFromRows(rows)
|
||||
return s.categoryBoardsFromRows(rows)
|
||||
}
|
||||
|
||||
func (s *SQLStore) addUpdateCategoryBlock(db sq.BaseRunner, userID, categoryID, blockID string) error {
|
||||
func (s *SQLStore) addUpdateCategoryBoard(db sq.BaseRunner, userID, categoryID, boardID string) error {
|
||||
if categoryID == "0" {
|
||||
return s.deleteUserCategoryBlock(db, userID, blockID)
|
||||
return s.deleteUserCategoryBoard(db, userID, boardID)
|
||||
}
|
||||
|
||||
rowsAffected, err := s.updateUserCategoryBlock(db, userID, blockID, categoryID)
|
||||
rowsAffected, err := s.updateUserCategoryBoard(db, userID, boardID, categoryID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -73,28 +73,28 @@ func (s *SQLStore) addUpdateCategoryBlock(db sq.BaseRunner, userID, categoryID,
|
|||
|
||||
if rowsAffected == 0 {
|
||||
// user-block mapping didn't already exist. So we'll create a new entry
|
||||
return s.addUserCategoryBlock(db, userID, categoryID, blockID)
|
||||
return s.addUserCategoryBoard(db, userID, categoryID, boardID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
/*
|
||||
func (s *SQLStore) userCategoryBlockExists(db sq.BaseRunner, userID, teamID, categoryID, blockID string) (bool, error) {
|
||||
func (s *SQLStore) userCategoryBoardExists(db sq.BaseRunner, userID, teamID, categoryID, boardID string) (bool, error) {
|
||||
query := s.getQueryBuilder(db).
|
||||
Select("blocks.id").
|
||||
From(s.tablePrefix + "categories AS categories").
|
||||
Join(s.tablePrefix + "category_blocks AS blocks ON blocks.category_id = categories.id").
|
||||
Join(s.tablePrefix + "category_boards AS blocks ON blocks.category_id = categories.id").
|
||||
Where(sq.Eq{
|
||||
"user_id": userID,
|
||||
"team_id": teamID,
|
||||
"categories.id": categoryID,
|
||||
"block_id": blockID,
|
||||
"board_id": boardID,
|
||||
})
|
||||
|
||||
rows, err := query.Query()
|
||||
if err != nil {
|
||||
s.logger.Error("getCategoryBlock error", mlog.Err(err))
|
||||
s.logger.Error("getCategoryBoard error", mlog.Err(err))
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
@ -102,39 +102,39 @@ func (s *SQLStore) userCategoryBlockExists(db sq.BaseRunner, userID, teamID, cat
|
|||
}
|
||||
*/
|
||||
|
||||
func (s *SQLStore) updateUserCategoryBlock(db sq.BaseRunner, userID, blockID, categoryID string) (int64, error) {
|
||||
func (s *SQLStore) updateUserCategoryBoard(db sq.BaseRunner, userID, boardID, categoryID string) (int64, error) {
|
||||
result, err := s.getQueryBuilder(db).
|
||||
Update(s.tablePrefix+"category_blocks").
|
||||
Update(s.tablePrefix+"category_boards").
|
||||
Set("category_id", categoryID).
|
||||
Set("delete_at", 0).
|
||||
Where(sq.Eq{
|
||||
"block_id": blockID,
|
||||
"board_id": boardID,
|
||||
"user_id": userID,
|
||||
}).
|
||||
Exec()
|
||||
|
||||
if err != nil {
|
||||
s.logger.Error("updateUserCategoryBlock error", mlog.Err(err))
|
||||
s.logger.Error("updateUserCategoryBoard error", mlog.Err(err))
|
||||
return 0, err
|
||||
}
|
||||
|
||||
rowsAffected, err := result.RowsAffected()
|
||||
if err != nil {
|
||||
s.logger.Error("updateUserCategoryBlock affected row count error", mlog.Err(err))
|
||||
s.logger.Error("updateUserCategoryBoard affected row count error", mlog.Err(err))
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return rowsAffected, nil
|
||||
}
|
||||
|
||||
func (s *SQLStore) addUserCategoryBlock(db sq.BaseRunner, userID, categoryID, blockID string) error {
|
||||
func (s *SQLStore) addUserCategoryBoard(db sq.BaseRunner, userID, categoryID, boardID string) error {
|
||||
_, err := s.getQueryBuilder(db).
|
||||
Insert(s.tablePrefix+"category_blocks").
|
||||
Insert(s.tablePrefix+"category_boards").
|
||||
Columns(
|
||||
"id",
|
||||
"user_id",
|
||||
"category_id",
|
||||
"block_id",
|
||||
"board_id",
|
||||
"create_at",
|
||||
"update_at",
|
||||
"delete_at",
|
||||
|
@ -143,34 +143,34 @@ func (s *SQLStore) addUserCategoryBlock(db sq.BaseRunner, userID, categoryID, bl
|
|||
utils.NewID(utils.IDTypeNone),
|
||||
userID,
|
||||
categoryID,
|
||||
blockID,
|
||||
boardID,
|
||||
utils.GetMillis(),
|
||||
utils.GetMillis(),
|
||||
0,
|
||||
).Exec()
|
||||
|
||||
if err != nil {
|
||||
s.logger.Error("addUserCategoryBlock error", mlog.Err(err))
|
||||
s.logger.Error("addUserCategoryBoard error", mlog.Err(err))
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLStore) deleteUserCategoryBlock(db sq.BaseRunner, userID, blockID string) error {
|
||||
func (s *SQLStore) deleteUserCategoryBoard(db sq.BaseRunner, userID, boardID string) error {
|
||||
_, err := s.getQueryBuilder(db).
|
||||
Update(s.tablePrefix+"category_blocks").
|
||||
Update(s.tablePrefix+"category_boards").
|
||||
Set("delete_at", utils.GetMillis()).
|
||||
Where(sq.Eq{
|
||||
"user_id": userID,
|
||||
"block_id": blockID,
|
||||
"board_id": boardID,
|
||||
"delete_at": 0,
|
||||
}).Exec()
|
||||
|
||||
if err != nil {
|
||||
s.logger.Error(
|
||||
"deleteUserCategoryBlock delete error",
|
||||
"deleteUserCategoryBoard delete error",
|
||||
mlog.String("userID", userID),
|
||||
mlog.String("blockID", blockID),
|
||||
mlog.String("boardID", boardID),
|
||||
mlog.Err(err),
|
||||
)
|
||||
return err
|
||||
|
@ -179,17 +179,17 @@ func (s *SQLStore) deleteUserCategoryBlock(db sq.BaseRunner, userID, blockID str
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLStore) categoryBlocksFromRows(rows *sql.Rows) ([]string, error) {
|
||||
func (s *SQLStore) categoryBoardsFromRows(rows *sql.Rows) ([]string, error) {
|
||||
blocks := []string{}
|
||||
|
||||
for rows.Next() {
|
||||
blockID := ""
|
||||
if err := rows.Scan(&blockID); err != nil {
|
||||
s.logger.Error("categoryBlocksFromRows row scan error", mlog.Err(err))
|
||||
boardID := ""
|
||||
if err := rows.Scan(&boardID); err != nil {
|
||||
s.logger.Error("categoryBoardsFromRows row scan error", mlog.Err(err))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blocks = append(blocks, blockID)
|
||||
blocks = append(blocks, boardID)
|
||||
}
|
||||
|
||||
return blocks, nil
|
||||
|
|
|
@ -238,7 +238,7 @@ func (s *SQLStore) updateCategoryID(db sq.BaseRunner, oldID, newID string) error
|
|||
// update category boards table
|
||||
|
||||
rows, err = s.getQueryBuilder(db).
|
||||
Update(s.tablePrefix+"category_blocks").
|
||||
Update(s.tablePrefix+"category_boards").
|
||||
Set("category_id", newID).
|
||||
Where(sq.Eq{"category_id": oldID}).
|
||||
Query()
|
||||
|
@ -258,7 +258,7 @@ func (s *SQLStore) updateCategoryID(db sq.BaseRunner, oldID, newID string) error
|
|||
|
||||
func (s *SQLStore) updateCategoryBlocksIDs(db sq.BaseRunner) error {
|
||||
// fetch all category IDs
|
||||
oldCategoryIDs, err := s.getIDs(db, "category_blocks")
|
||||
oldCategoryIDs, err := s.getIDs(db, "category_boards")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ func (s *SQLStore) updateCategoryBlocksIDs(db sq.BaseRunner) error {
|
|||
func (s *SQLStore) updateCategoryBlocksID(db sq.BaseRunner, oldID, newID string) error {
|
||||
// update in category table
|
||||
rows, err := s.getQueryBuilder(db).
|
||||
Update(s.tablePrefix+"category_blocks").
|
||||
Update(s.tablePrefix+"category_boards").
|
||||
Set("id", newID).
|
||||
Where(sq.Eq{"id": oldID}).
|
||||
Query()
|
||||
|
|
|
@ -23,6 +23,8 @@ UPDATE {{.prefix}}blocks SET fields = fields::jsonb - 'columnCalculations' || '{
|
|||
UPDATE {{.prefix}}blocks SET fields = replace(fields, '"columnCalculations":[]', '"columnCalculations":{}');
|
||||
{{end}}
|
||||
|
||||
/* TODO: Migrate the columnCalculations at app level and remove it from the boards and boards_history tables */
|
||||
|
||||
{{- /* add boards tables */ -}}
|
||||
CREATE TABLE {{.prefix}}boards (
|
||||
id VARCHAR(36) NOT NULL PRIMARY KEY,
|
||||
|
@ -62,6 +64,8 @@ CREATE TABLE {{.prefix}}boards (
|
|||
delete_at BIGINT
|
||||
) {{if .mysql}}DEFAULT CHARACTER SET utf8mb4{{end}};
|
||||
|
||||
CREATE INDEX idx_board_team_id ON {{.prefix}}boards(team_id, is_template);
|
||||
|
||||
CREATE TABLE {{.prefix}}boards_history (
|
||||
id VARCHAR(36) NOT NULL,
|
||||
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
CREATE TABLE {{.prefix}}categories (
|
||||
id varchar(36) NOT NULL,
|
||||
name varchar(100) NOT NULL,
|
||||
user_id varchar(32) NOT NULL,
|
||||
team_id varchar(32) NOT NULL,
|
||||
channel_id varchar(32),
|
||||
user_id varchar(36) NOT NULL,
|
||||
team_id varchar(36) NOT NULL,
|
||||
channel_id varchar(36),
|
||||
create_at BIGINT,
|
||||
update_at BIGINT,
|
||||
delete_at BIGINT,
|
||||
PRIMARY KEY (id)
|
||||
) {{if .mysql}}DEFAULT CHARACTER SET utf8mb4{{end}};
|
||||
|
||||
CREATE INDEX idx_categories_user_id_team_id ON {{.prefix}}categories(user_id, team_id);
|
||||
|
||||
{{if .plugin}}
|
||||
INSERT INTO {{.prefix}}categories(
|
||||
id,
|
||||
|
@ -28,9 +30,9 @@ CREATE TABLE {{.prefix}}categories (
|
|||
{{ if .mysql }}
|
||||
UUID(),
|
||||
{{ end }}
|
||||
COALESCE(nullif(c.DisplayName, ''), 'Direct Message') as category_name,
|
||||
c.DisplayName,
|
||||
cm.UserId,
|
||||
COALESCE(nullif(c.TeamId, ''), 'direct_message') as team_id,
|
||||
c.TeamId,
|
||||
cm.ChannelId,
|
||||
{{if .postgres}}(extract(epoch from now())*1000)::bigint,{{end}}
|
||||
{{if .mysql}}UNIX_TIMESTAMP() * 1000,{{end}}
|
||||
|
@ -39,6 +41,6 @@ CREATE TABLE {{.prefix}}categories (
|
|||
FROM
|
||||
{{.prefix}}boards boards
|
||||
JOIN ChannelMembers cm on boards.channel_id = cm.ChannelId
|
||||
JOIN Channels c on cm.ChannelId = c.id
|
||||
JOIN Channels c on cm.ChannelId = c.id and (c.Type = 'O' or c.Type = 'P')
|
||||
GROUP BY cm.UserId, c.TeamId, cm.ChannelId, c.DisplayName;
|
||||
{{end}}
|
||||
|
|
|
@ -1 +1 @@
|
|||
DELETE from {{.prefix}}category_blocks;
|
||||
DELETE from {{.prefix}}category_boards;
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
CREATE TABLE {{.prefix}}category_blocks (
|
||||
CREATE TABLE {{.prefix}}category_boards (
|
||||
id varchar(36) NOT NULL,
|
||||
user_id varchar(32) NOT NULL,
|
||||
user_id varchar(36) NOT NULL,
|
||||
category_id varchar(36) NOT NULL,
|
||||
block_id VARCHAR(36) NOT NULL,
|
||||
board_id VARCHAR(36) NOT NULL,
|
||||
create_at BIGINT,
|
||||
update_at BIGINT,
|
||||
delete_at BIGINT,
|
||||
PRIMARY KEY (id)
|
||||
) {{if .mysql}}DEFAULT CHARACTER SET utf8mb4{{end}};
|
||||
|
||||
CREATE INDEX idx_categoryboards_category_id ON {{.prefix}}category_boards(category_id);
|
||||
|
||||
{{if .plugin}}
|
||||
INSERT INTO {{.prefix}}category_blocks(id, user_id, category_id, block_id, create_at, update_at, delete_at)
|
||||
INSERT INTO {{.prefix}}category_boards(id, user_id, category_id, board_id, create_at, update_at, delete_at)
|
||||
SELECT
|
||||
{{ if .postgres }}
|
||||
REPLACE(uuid_in(md5(random()::text || clock_timestamp()::text)::cstring)::varchar, '-', ''),
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
CREATE TABLE {{.prefix}}board_members_history (
|
||||
{{if .postgres}}id SERIAL PRIMARY KEY,{{end}}
|
||||
{{if .sqlite}}id INTEGER PRIMARY KEY AUTOINCREMENT,{{end}}
|
||||
{{if .mysql}}id INT PRIMARY KEY AUTO_INCREMENT,{{end}}
|
||||
board_id VARCHAR(36) NOT NULL,
|
||||
user_id VARCHAR(36) NOT NULL,
|
||||
action VARCHAR(10),
|
||||
insert_at BIGINT NOT NULL
|
||||
{{if .postgres}}insert_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),{{end}}
|
||||
{{if .sqlite}}insert_at DATETIME NOT NULL DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),{{end}}
|
||||
{{if .mysql}}insert_at DATETIME(6) NOT NULL DEFAULT NOW(6),{{end}}
|
||||
PRIMARY KEY (board_id, user_id, insert_at)
|
||||
) {{if .mysql}}DEFAULT CHARACTER SET utf8mb4{{end}};
|
||||
|
||||
CREATE INDEX idx_boardmembershistory_user_id ON {{.prefix}}board_members_history(user_id);
|
||||
CREATE INDEX idx_boardmembershistory_board_id_userid ON {{.prefix}}board_members_history(board_id, user_id);
|
||||
CREATE INDEX idx_boardmembershistory_board_id_user_id ON {{.prefix}}board_members_history(board_id, user_id);
|
||||
|
||||
INSERT INTO {{.prefix}}board_members_history (board_id, user_id, action, insert_at) SELECT board_id, user_id, 'created',
|
||||
{{if .postgres}}CAST(extract(epoch from now()) * 1000 AS BIGINT){{end}}
|
||||
{{if .sqlite}}strftime('%s')*1000{{end}}
|
||||
{{if .mysql}}UNIX_TIMESTAMP(now())*1000{{end}}
|
||||
from {{.prefix}}board_members;
|
||||
INSERT INTO {{.prefix}}board_members_history (board_id, user_id, action) SELECT board_id, user_id, 'created' from {{.prefix}}board_members;
|
||||
|
|
|
@ -22,8 +22,8 @@ import (
|
|||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
)
|
||||
|
||||
func (s *SQLStore) AddUpdateCategoryBlock(userID string, categoryID string, blockID string) error {
|
||||
return s.addUpdateCategoryBlock(s.db, userID, categoryID, blockID)
|
||||
func (s *SQLStore) AddUpdateCategoryBoard(userID string, categoryID string, blockID string) error {
|
||||
return s.addUpdateCategoryBoard(s.db, userID, categoryID, blockID)
|
||||
|
||||
}
|
||||
|
||||
|
@ -450,8 +450,8 @@ func (s *SQLStore) GetUserByUsername(username string) (*model.User, error) {
|
|||
|
||||
}
|
||||
|
||||
func (s *SQLStore) GetUserCategoryBlocks(userID string, teamID string) ([]model.CategoryBlocks, error) {
|
||||
return s.getUserCategoryBlocks(s.db, userID, teamID)
|
||||
func (s *SQLStore) GetUserCategoryBoards(userID string, teamID string) ([]model.CategoryBoards, error) {
|
||||
return s.getUserCategoryBoards(s.db, userID, teamID)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -113,8 +113,8 @@ type Store interface {
|
|||
UpdateCategory(category model.Category) error
|
||||
DeleteCategory(categoryID, userID, teamID string) error
|
||||
|
||||
GetUserCategoryBlocks(userID, teamID string) ([]model.CategoryBlocks, error)
|
||||
AddUpdateCategoryBlock(userID, categoryID, blockID string) error
|
||||
GetUserCategoryBoards(userID, teamID string) ([]model.CategoryBoards, error)
|
||||
AddUpdateCategoryBoard(userID, categoryID, blockID string) error
|
||||
|
||||
CreateSubscription(sub *model.Subscription) (*model.Subscription, error)
|
||||
DeleteSubscription(blockID string, subscriberID string) error
|
||||
|
|
|
@ -17,7 +17,7 @@ const (
|
|||
websocketActionUpdateBlock = "UPDATE_BLOCK"
|
||||
websocketActionUpdateConfig = "UPDATE_CLIENT_CONFIG"
|
||||
websocketActionUpdateCategory = "UPDATE_CATEGORY"
|
||||
websocketActionUpdateCategoryBlock = "UPDATE_BLOCK_CATEGORY"
|
||||
websocketActionUpdateCategoryBoard = "UPDATE_BOARD_CATEGORY"
|
||||
websocketActionUpdateSubscription = "UPDATE_SUBSCRIPTION"
|
||||
)
|
||||
|
||||
|
@ -35,6 +35,6 @@ type Adapter interface {
|
|||
BroadcastMemberDelete(teamID, boardID, userID string)
|
||||
BroadcastConfigChange(clientConfig model.ClientConfig)
|
||||
BroadcastCategoryChange(category model.Category)
|
||||
BroadcastCategoryBlockChange(teamID, userID string, blockCategory model.BlockCategoryWebsocketData)
|
||||
BroadcastCategoryBoardChange(teamID, userID string, blockCategory model.BoardCategoryWebsocketData)
|
||||
BroadcastSubscriptionChange(teamID string, subscription *model.Subscription)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ type UpdateCategoryMessage struct {
|
|||
Action string `json:"action"`
|
||||
TeamID string `json:"teamId"`
|
||||
Category *model.Category `json:"category,omitempty"`
|
||||
BlockCategories *model.BlockCategoryWebsocketData `json:"blockCategories,omitempty"`
|
||||
BoardCategories *model.BoardCategoryWebsocketData `json:"blockCategories,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateBlockMsg is sent on block updates.
|
||||
|
|
|
@ -494,22 +494,22 @@ func (pa *PluginAdapter) BroadcastCategoryChange(category model.Category) {
|
|||
pa.sendUserMessageSkipCluster(websocketActionUpdateCategory, payload, category.UserID)
|
||||
}
|
||||
|
||||
func (pa *PluginAdapter) BroadcastCategoryBlockChange(teamID, userID string, blockCategory model.BlockCategoryWebsocketData) {
|
||||
func (pa *PluginAdapter) BroadcastCategoryBoardChange(teamID, userID string, boardCategory model.BoardCategoryWebsocketData) {
|
||||
pa.logger.Debug(
|
||||
"BroadcastCategoryBlockChange",
|
||||
"BroadcastCategoryBoardChange",
|
||||
mlog.String("userID", userID),
|
||||
mlog.String("teamID", teamID),
|
||||
mlog.String("categoryID", blockCategory.CategoryID),
|
||||
mlog.String("blockID", blockCategory.BlockID),
|
||||
mlog.String("categoryID", boardCategory.CategoryID),
|
||||
mlog.String("blockID", boardCategory.BoardID),
|
||||
)
|
||||
|
||||
message := UpdateCategoryMessage{
|
||||
Action: websocketActionUpdateCategoryBlock,
|
||||
Action: websocketActionUpdateCategoryBoard,
|
||||
TeamID: teamID,
|
||||
BlockCategories: &blockCategory,
|
||||
BoardCategories: &boardCategory,
|
||||
}
|
||||
|
||||
pa.sendTeamMessage(websocketActionUpdateCategoryBlock, teamID, utils.StructToMap(message))
|
||||
pa.sendTeamMessage(websocketActionUpdateCategoryBoard, teamID, utils.StructToMap(message))
|
||||
}
|
||||
|
||||
func (pa *PluginAdapter) BroadcastBlockDelete(teamID, blockID, boardID string) {
|
||||
|
|
|
@ -595,27 +595,27 @@ func (ws *Server) BroadcastCategoryChange(category model.Category) {
|
|||
}
|
||||
}
|
||||
|
||||
func (ws *Server) BroadcastCategoryBlockChange(teamID, userID string, blockCategory model.BlockCategoryWebsocketData) {
|
||||
func (ws *Server) BroadcastCategoryBoardChange(teamID, userID string, boardCategory model.BoardCategoryWebsocketData) {
|
||||
message := UpdateCategoryMessage{
|
||||
Action: websocketActionUpdateCategoryBlock,
|
||||
Action: websocketActionUpdateCategoryBoard,
|
||||
TeamID: teamID,
|
||||
BlockCategories: &blockCategory,
|
||||
BoardCategories: &boardCategory,
|
||||
}
|
||||
|
||||
listeners := ws.getListenersForTeam(teamID)
|
||||
ws.logger.Debug("listener(s) for teamID",
|
||||
mlog.Int("listener_count", len(listeners)),
|
||||
mlog.String("teamID", teamID),
|
||||
mlog.String("categoryID", blockCategory.CategoryID),
|
||||
mlog.String("blockID", blockCategory.BlockID),
|
||||
mlog.String("categoryID", boardCategory.CategoryID),
|
||||
mlog.String("blockID", boardCategory.BoardID),
|
||||
)
|
||||
|
||||
for _, listener := range listeners {
|
||||
ws.logger.Debug("Broadcast block change",
|
||||
mlog.Int("listener_count", len(listeners)),
|
||||
mlog.String("teamID", teamID),
|
||||
mlog.String("categoryID", blockCategory.CategoryID),
|
||||
mlog.String("blockID", blockCategory.BlockID),
|
||||
mlog.String("categoryID", boardCategory.CategoryID),
|
||||
mlog.String("blockID", boardCategory.BoardID),
|
||||
mlog.Stringer("remoteAddr", listener.conn.RemoteAddr()),
|
||||
)
|
||||
|
||||
|
|
|
@ -98,9 +98,9 @@ card3.boardId = fakeBoard.id
|
|||
|
||||
const me: IUser = {id: 'user-id-1', username: 'username_1', email: '', props: {}, create_at: 0, update_at: 0, is_bot: false}
|
||||
|
||||
const categoryAttribute1 = TestBlockFactory.createCategoryBlocks()
|
||||
const categoryAttribute1 = TestBlockFactory.createCategoryBoards()
|
||||
categoryAttribute1.name = 'Category 1'
|
||||
categoryAttribute1.blockIDs = [board.id]
|
||||
categoryAttribute1.boardIDs = [board.id]
|
||||
|
||||
describe('src/components/shareBoard/shareBoard', () => {
|
||||
const w = (window as any)
|
||||
|
|
|
@ -28,9 +28,9 @@ describe('components/sidebarSidebar', () => {
|
|||
const board = TestBlockFactory.createBoard()
|
||||
board.id = 'board1'
|
||||
|
||||
const categoryAttribute1 = TestBlockFactory.createCategoryBlocks()
|
||||
const categoryAttribute1 = TestBlockFactory.createCategoryBoards()
|
||||
categoryAttribute1.name = 'Category 1'
|
||||
categoryAttribute1.blockIDs = [board.id]
|
||||
categoryAttribute1.boardIDs = [board.id]
|
||||
|
||||
test('sidebar hidden', () => {
|
||||
const store = mockStore({
|
||||
|
|
|
@ -15,11 +15,11 @@ import {Utils} from '../../utils'
|
|||
import './sidebar.scss'
|
||||
|
||||
import {
|
||||
BlockCategoryWebsocketData,
|
||||
BoardCategoryWebsocketData,
|
||||
Category,
|
||||
CategoryBlocks,
|
||||
CategoryBoards,
|
||||
fetchSidebarCategories,
|
||||
getSidebarCategories, updateBlockCategories,
|
||||
getSidebarCategories, updateBoardCategories,
|
||||
updateCategories,
|
||||
} from '../../store/sidebar'
|
||||
|
||||
|
@ -55,7 +55,7 @@ const Sidebar = (props: Props) => {
|
|||
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions())
|
||||
const boards = useAppSelector(getSortedBoards)
|
||||
const dispatch = useAppDispatch()
|
||||
const partialCategories = useAppSelector<Array<CategoryBlocks>>(getSidebarCategories)
|
||||
const partialCategories = useAppSelector<Array<CategoryBoards>>(getSidebarCategories)
|
||||
const sidebarCategories = addMissingItems(partialCategories, boards)
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -63,8 +63,8 @@ const Sidebar = (props: Props) => {
|
|||
dispatch(updateCategories(categories))
|
||||
}, 'category')
|
||||
|
||||
wsClient.addOnChange((_: WSClient, blockCategories: Array<BlockCategoryWebsocketData>) => {
|
||||
dispatch(updateBlockCategories(blockCategories))
|
||||
wsClient.addOnChange((_: WSClient, blockCategories: Array<BoardCategoryWebsocketData>) => {
|
||||
dispatch(updateBoardCategories(blockCategories))
|
||||
}, 'blockCategories')
|
||||
}, [])
|
||||
|
||||
|
@ -182,7 +182,7 @@ const Sidebar = (props: Props) => {
|
|||
hideSidebar={hideSidebar}
|
||||
key={category.id}
|
||||
activeBoardID={props.activeBoardId}
|
||||
categoryBlocks={category}
|
||||
categoryBoards={category}
|
||||
boards={boards}
|
||||
allCategories={sidebarCategories}
|
||||
/>
|
||||
|
|
|
@ -24,20 +24,20 @@ describe('components/sidebarBoardItem', () => {
|
|||
view.fields.sortOptions = []
|
||||
const history = createMemoryHistory()
|
||||
|
||||
const categoryBlocks1 = TestBlockFactory.createCategoryBlocks()
|
||||
categoryBlocks1.name = 'Category 1'
|
||||
categoryBlocks1.blockIDs = [board.id]
|
||||
const categoryBoards1 = TestBlockFactory.createCategoryBoards()
|
||||
categoryBoards1.name = 'Category 1'
|
||||
categoryBoards1.boardIDs = [board.id]
|
||||
|
||||
const categoryBlocks2 = TestBlockFactory.createCategoryBlocks()
|
||||
categoryBlocks2.name = 'Category 2'
|
||||
const categoryBoards2 = TestBlockFactory.createCategoryBoards()
|
||||
categoryBoards2.name = 'Category 2'
|
||||
|
||||
const categoryBlocks3 = TestBlockFactory.createCategoryBlocks()
|
||||
categoryBlocks3.name = 'Category 3'
|
||||
const categoryBoards3 = TestBlockFactory.createCategoryBoards()
|
||||
categoryBoards3.name = 'Category 3'
|
||||
|
||||
const allCategoryBlocks = [
|
||||
categoryBlocks1,
|
||||
categoryBlocks2,
|
||||
categoryBlocks3,
|
||||
const allCategoryBoards = [
|
||||
categoryBoards1,
|
||||
categoryBoards2,
|
||||
categoryBoards3,
|
||||
]
|
||||
|
||||
const state = {
|
||||
|
@ -73,9 +73,9 @@ describe('components/sidebarBoardItem', () => {
|
|||
<ReduxProvider store={store}>
|
||||
<Router history={history}>
|
||||
<SidebarBoardItem
|
||||
categoryBlocks={categoryBlocks1}
|
||||
categoryBoards={categoryBoards1}
|
||||
board={board}
|
||||
allCategories={allCategoryBlocks}
|
||||
allCategories={allCategoryBoards}
|
||||
isActive={true}
|
||||
showBoard={jest.fn()}
|
||||
showView={jest.fn()}
|
||||
|
|
|
@ -15,7 +15,7 @@ import MenuWrapper from '../../widgets/menuWrapper'
|
|||
import BoardPermissionGate from '../permissions/boardPermissionGate'
|
||||
|
||||
import './sidebarBoardItem.scss'
|
||||
import {CategoryBlocks} from '../../store/sidebar'
|
||||
import {CategoryBoards} from '../../store/sidebar'
|
||||
import CreateNewFolder from '../../widgets/icons/newFolder'
|
||||
import {useAppSelector} from '../../store/hooks'
|
||||
import {getCurrentBoardViews, getCurrentViewId} from '../../store/views'
|
||||
|
@ -45,9 +45,9 @@ const iconForViewType = (viewType: IViewType): JSX.Element => {
|
|||
|
||||
type Props = {
|
||||
isActive: boolean
|
||||
categoryBlocks: CategoryBlocks
|
||||
categoryBoards: CategoryBoards
|
||||
board: Board
|
||||
allCategories: Array<CategoryBlocks>
|
||||
allCategories: Array<CategoryBoards>
|
||||
onDeleteRequest: (board: Board) => void
|
||||
showBoard: (boardId: string) => void
|
||||
showView: (viewId: string, boardId: string) => void
|
||||
|
@ -66,16 +66,16 @@ const SidebarBoardItem = (props: Props) => {
|
|||
const match = useRouteMatch<{boardId: string, viewId?: string, cardId?: string, teamId?: string}>()
|
||||
const history = useHistory()
|
||||
|
||||
const generateMoveToCategoryOptions = (blockID: string) => {
|
||||
const generateMoveToCategoryOptions = (boardID: string) => {
|
||||
return props.allCategories.map((category) => (
|
||||
<Menu.Text
|
||||
key={category.id}
|
||||
id={category.id}
|
||||
name={category.name}
|
||||
icon={category.id === props.categoryBlocks.id ? <Check/> : <Folder/>}
|
||||
icon={category.id === props.categoryBoards.id ? <Check/> : <Folder/>}
|
||||
onClick={async (toCategoryID) => {
|
||||
const fromCategoryID = props.categoryBlocks.id
|
||||
await mutator.moveBlockToCategory(teamID, blockID, toCategoryID, fromCategoryID)
|
||||
const fromCategoryID = props.categoryBoards.id
|
||||
await mutator.moveBoardToCategory(teamID, boardID, toCategoryID, fromCategoryID)
|
||||
}}
|
||||
/>
|
||||
))
|
||||
|
|
|
@ -28,20 +28,20 @@ describe('components/sidebarCategory', () => {
|
|||
const board1 = TestBlockFactory.createBoard()
|
||||
const board2 = TestBlockFactory.createBoard()
|
||||
const boards = [board1, board2]
|
||||
const categoryBlocks1 = TestBlockFactory.createCategoryBlocks()
|
||||
categoryBlocks1.name = 'Category 1'
|
||||
categoryBlocks1.blockIDs = [board1.id, board2.id]
|
||||
const categoryBoards1 = TestBlockFactory.createCategoryBoards()
|
||||
categoryBoards1.name = 'Category 1'
|
||||
categoryBoards1.boardIDs = [board1.id, board2.id]
|
||||
|
||||
const categoryBlocks2 = TestBlockFactory.createCategoryBlocks()
|
||||
categoryBlocks2.name = 'Category 2'
|
||||
const categoryBoards2 = TestBlockFactory.createCategoryBoards()
|
||||
categoryBoards2.name = 'Category 2'
|
||||
|
||||
const categoryBlocks3 = TestBlockFactory.createCategoryBlocks()
|
||||
categoryBlocks3.name = 'Category 3'
|
||||
const categoryBoards3 = TestBlockFactory.createCategoryBoards()
|
||||
categoryBoards3.name = 'Category 3'
|
||||
|
||||
const allCategoryBlocks = [
|
||||
categoryBlocks1,
|
||||
categoryBlocks2,
|
||||
categoryBlocks3,
|
||||
const allCategoryBoards = [
|
||||
categoryBoards1,
|
||||
categoryBoards2,
|
||||
categoryBoards3,
|
||||
]
|
||||
|
||||
const state = {
|
||||
|
@ -78,9 +78,9 @@ describe('components/sidebarCategory', () => {
|
|||
<Router history={history}>
|
||||
<SidebarCategory
|
||||
hideSidebar={() => {}}
|
||||
categoryBlocks={categoryBlocks1}
|
||||
categoryBoards={categoryBoards1}
|
||||
boards={boards}
|
||||
allCategories={allCategoryBlocks}
|
||||
allCategories={allCategoryBoards}
|
||||
/>
|
||||
</Router>
|
||||
</ReduxProvider>,
|
||||
|
|
|
@ -13,7 +13,7 @@ import Menu from '../../widgets/menu'
|
|||
import MenuWrapper from '../../widgets/menuWrapper'
|
||||
|
||||
import './sidebarCategory.scss'
|
||||
import {Category, CategoryBlocks} from '../../store/sidebar'
|
||||
import {Category, CategoryBoards} from '../../store/sidebar'
|
||||
import ChevronDown from '../../widgets/icons/chevronDown'
|
||||
import ChevronRight from '../../widgets/icons/chevronRight'
|
||||
import CreateNewFolder from '../../widgets/icons/newFolder'
|
||||
|
@ -37,9 +37,9 @@ type Props = {
|
|||
activeCategoryId?: string
|
||||
activeBoardID?: string
|
||||
hideSidebar: () => void
|
||||
categoryBlocks: CategoryBlocks
|
||||
categoryBoards: CategoryBoards
|
||||
boards: Board[]
|
||||
allCategories: Array<CategoryBlocks>
|
||||
allCategories: Array<CategoryBoards>
|
||||
}
|
||||
|
||||
const SidebarCategory = (props: Props) => {
|
||||
|
@ -76,14 +76,14 @@ const SidebarCategory = (props: Props) => {
|
|||
props.hideSidebar()
|
||||
}, [match, history])
|
||||
|
||||
const blocks = props.categoryBlocks.blockIDs || []
|
||||
const blocks = props.categoryBoards.boardIDs || []
|
||||
|
||||
const handleCreateNewCategory = () => {
|
||||
setShowCreateCategoryModal(true)
|
||||
}
|
||||
|
||||
const handleDeleteCategory = async () => {
|
||||
await mutator.deleteCategory(teamID, props.categoryBlocks.id)
|
||||
await mutator.deleteCategory(teamID, props.categoryBoards.id)
|
||||
}
|
||||
|
||||
const handleUpdateCategory = async () => {
|
||||
|
@ -101,7 +101,7 @@ const SidebarCategory = (props: Props) => {
|
|||
defaultMessage: 'Boards in <b>{categoryName}</b> will move back to the Boards categories. You\'re not removed from any boards.',
|
||||
},
|
||||
{
|
||||
categoryName: props.categoryBlocks.name,
|
||||
categoryName: props.categoryBoards.name,
|
||||
b: (...chunks) => <b>{chunks}</b>,
|
||||
},
|
||||
),
|
||||
|
@ -140,7 +140,7 @@ const SidebarCategory = (props: Props) => {
|
|||
return (
|
||||
<div className='SidebarCategory'>
|
||||
<div
|
||||
className={`octo-sidebar-item category ' ${collapsed ? 'collapsed' : 'expanded'} ${props.categoryBlocks.id === props.activeCategoryId ? 'active' : ''}`}
|
||||
className={`octo-sidebar-item category ' ${collapsed ? 'collapsed' : 'expanded'} ${props.categoryBoards.id === props.activeCategoryId ? 'active' : ''}`}
|
||||
>
|
||||
<IconButton
|
||||
icon={collapsed ? <ChevronRight/> : <ChevronDown/>}
|
||||
|
@ -148,9 +148,9 @@ const SidebarCategory = (props: Props) => {
|
|||
/>
|
||||
<div
|
||||
className='octo-sidebar-title category-title'
|
||||
title={props.categoryBlocks.name}
|
||||
title={props.categoryBoards.name}
|
||||
>
|
||||
{props.categoryBlocks.name}
|
||||
{props.categoryBoards.name}
|
||||
</div>
|
||||
<MenuWrapper
|
||||
className={categoryMenuOpen ? 'menuOpen' : ''}
|
||||
|
@ -166,7 +166,7 @@ const SidebarCategory = (props: Props) => {
|
|||
onClick={handleCreateNewCategory}
|
||||
/>
|
||||
{
|
||||
props.categoryBlocks.id !== '' &&
|
||||
props.categoryBoards.id !== '' &&
|
||||
<React.Fragment>
|
||||
<Menu.Text
|
||||
id='deleteCategory'
|
||||
|
@ -201,7 +201,7 @@ const SidebarCategory = (props: Props) => {
|
|||
<SidebarBoardItem
|
||||
key={board.id}
|
||||
board={board}
|
||||
categoryBlocks={props.categoryBlocks}
|
||||
categoryBoards={props.categoryBoards}
|
||||
allCategories={props.allCategories}
|
||||
isActive={board.id === props.activeBoardID}
|
||||
showBoard={showBoard}
|
||||
|
@ -243,7 +243,7 @@ const SidebarCategory = (props: Props) => {
|
|||
{
|
||||
showUpdateCategoryModal && (
|
||||
<CreateCategory
|
||||
initialValue={props.categoryBlocks.name}
|
||||
initialValue={props.categoryBoards.name}
|
||||
title={(
|
||||
<FormattedMessage
|
||||
id='SidebarCategories.CategoryMenu.Update'
|
||||
|
@ -259,7 +259,7 @@ const SidebarCategory = (props: Props) => {
|
|||
|
||||
const category: Category = {
|
||||
name,
|
||||
id: props.categoryBlocks.id,
|
||||
id: props.categoryBoards.id,
|
||||
userID: me.id,
|
||||
teamID,
|
||||
} as Category
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {CategoryBlocks, DefaultCategory} from '../../store/sidebar'
|
||||
import {CategoryBoards, DefaultCategory} from '../../store/sidebar'
|
||||
|
||||
import {Block} from '../../blocks/block'
|
||||
import {Board} from '../../blocks/board'
|
||||
|
||||
export function addMissingItems(sidebarCategories: Array<CategoryBlocks>, allItems: Array<Block | Board>): Array<CategoryBlocks> {
|
||||
export function addMissingItems(sidebarCategories: Array<CategoryBoards>, allItems: Array<Block | Board>): Array<CategoryBoards> {
|
||||
const blocksInCategories = new Map<string, boolean>()
|
||||
sidebarCategories.forEach(
|
||||
(category) => category.blockIDs.forEach(
|
||||
(blockID) => blocksInCategories.set(blockID, true),
|
||||
(category) => category.boardIDs.forEach(
|
||||
(boardID) => blocksInCategories.set(boardID, true),
|
||||
),
|
||||
)
|
||||
|
||||
const defaultCategory: CategoryBlocks = {
|
||||
const defaultCategory: CategoryBoards = {
|
||||
...DefaultCategory,
|
||||
blockIDs: [],
|
||||
boardIDs: [],
|
||||
}
|
||||
|
||||
allItems.forEach((block) => {
|
||||
if (!blocksInCategories.get(block.id)) {
|
||||
defaultCategory.blockIDs.push(block.id)
|
||||
defaultCategory.boardIDs.push(block.id)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ card3.boardId = fakeBoard.id
|
|||
|
||||
const me: IUser = {id: 'user-id-1', username: 'username_1', email: '', props: {}, create_at: 0, update_at: 0, is_bot: false}
|
||||
|
||||
const categoryAttribute1 = TestBlockFactory.createCategoryBlocks()
|
||||
const categoryAttribute1 = TestBlockFactory.createCategoryBoards()
|
||||
categoryAttribute1.name = 'Category 1'
|
||||
categoryAttribute1.blockIDs = [board.id]
|
||||
categoryAttribute1.boardIDs = [board.id]
|
||||
|
||||
jest.mock('react-router-dom', () => {
|
||||
const originalModule = jest.requireActual('react-router-dom')
|
||||
|
|
|
@ -914,8 +914,8 @@ class Mutator {
|
|||
await octoClient.updateSidebarCategory(category)
|
||||
}
|
||||
|
||||
async moveBlockToCategory(teamID: string, blockID: string, toCategoryID: string, fromCategoryID: string): Promise<void> {
|
||||
await octoClient.moveBlockToCategory(teamID, blockID, toCategoryID, fromCategoryID)
|
||||
async moveBoardToCategory(teamID: string, blockID: string, toCategoryID: string, fromCategoryID: string): Promise<void> {
|
||||
await octoClient.moveBoardToCategory(teamID, blockID, toCategoryID, fromCategoryID)
|
||||
}
|
||||
|
||||
async followBlock(blockId: string, blockType: string, userId: string) {
|
||||
|
|
|
@ -8,7 +8,7 @@ import {IUser, UserConfigPatch} from './user'
|
|||
import {Utils} from './utils'
|
||||
import {ClientConfig} from './config/clientConfig'
|
||||
import {UserSettings} from './userSettings'
|
||||
import {Category, CategoryBlocks} from './store/sidebar'
|
||||
import {Category, CategoryBoards} from './store/sidebar'
|
||||
import {Team} from './store/teams'
|
||||
import {Subscription} from './wsclient'
|
||||
import {PrepareOnboardingResponse} from './onboardingTour'
|
||||
|
@ -721,14 +721,14 @@ class OctoClient {
|
|||
})
|
||||
}
|
||||
|
||||
async getSidebarCategories(teamID: string): Promise<Array<CategoryBlocks>> {
|
||||
async getSidebarCategories(teamID: string): Promise<Array<CategoryBoards>> {
|
||||
const path = `/api/v2/teams/${teamID}/categories`
|
||||
const response = await fetch(this.getBaseURL() + path, {headers: this.headers()})
|
||||
if (response.status !== 200) {
|
||||
return []
|
||||
}
|
||||
|
||||
return (await this.getJson(response, [])) as Array<CategoryBlocks>
|
||||
return (await this.getJson(response, [])) as Array<CategoryBoards>
|
||||
}
|
||||
|
||||
async createSidebarCategory(category: Category): Promise<Response> {
|
||||
|
@ -759,8 +759,8 @@ class OctoClient {
|
|||
})
|
||||
}
|
||||
|
||||
async moveBlockToCategory(teamID: string, blockID: string, toCategoryID: string, fromCategoryID: string): Promise<Response> {
|
||||
const url = `/api/v2/teams/${teamID}/categories/${toCategoryID || '0'}/blocks/${blockID}`
|
||||
async moveBoardToCategory(teamID: string, boardID: string, toCategoryID: string, fromCategoryID: string): Promise<Response> {
|
||||
const url = `/api/v2/teams/${teamID}/categories/${toCategoryID || '0'}/boards/${boardID}`
|
||||
const payload = {
|
||||
fromCategoryID,
|
||||
}
|
||||
|
|
|
@ -29,11 +29,11 @@ const TeamToBoardAndViewRedirect = (): null => {
|
|||
if (!boardID && categories.length > 0) {
|
||||
// a category may exist without any boards.
|
||||
// find the first category with a board and pick it's first board
|
||||
const categoryWithBoards = categories.find((category) => category.blockIDs.length > 0)
|
||||
const categoryWithBoards = categories.find((category) => category.boardIDs.length > 0)
|
||||
|
||||
// there may even be no boards at all
|
||||
if (categoryWithBoards) {
|
||||
boardID = categoryWithBoards.blockIDs[0]
|
||||
boardID = categoryWithBoards.boardIDs[0]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,19 +17,19 @@ interface Category {
|
|||
deleteAt: number
|
||||
}
|
||||
|
||||
interface CategoryBlocks extends Category {
|
||||
blockIDs: Array<string>
|
||||
interface CategoryBoards extends Category {
|
||||
boardIDs: Array<string>
|
||||
}
|
||||
|
||||
interface BlockCategoryWebsocketData {
|
||||
blockID: string
|
||||
interface BoardCategoryWebsocketData {
|
||||
boardID: string
|
||||
categoryID: string
|
||||
}
|
||||
|
||||
export const DefaultCategory: CategoryBlocks = {
|
||||
export const DefaultCategory: CategoryBoards = {
|
||||
id: '',
|
||||
name: 'Boards',
|
||||
} as CategoryBlocks
|
||||
} as CategoryBoards
|
||||
|
||||
export const fetchSidebarCategories = createAsyncThunk(
|
||||
'sidebarCategories/fetch',
|
||||
|
@ -40,7 +40,7 @@ export const fetchSidebarCategories = createAsyncThunk(
|
|||
)
|
||||
|
||||
type Sidebar = {
|
||||
categoryAttributes: Array<CategoryBlocks>
|
||||
categoryAttributes: Array<CategoryBoards>
|
||||
}
|
||||
|
||||
const sidebarSlice = createSlice({
|
||||
|
@ -55,7 +55,7 @@ const sidebarSlice = createSlice({
|
|||
if (index === -1) {
|
||||
state.categoryAttributes.push({
|
||||
...updatedCategory,
|
||||
blockIDs: [],
|
||||
boardIDs: [],
|
||||
})
|
||||
} else if (updatedCategory.deleteAt) {
|
||||
// when category is deleted
|
||||
|
@ -70,17 +70,17 @@ const sidebarSlice = createSlice({
|
|||
}
|
||||
})
|
||||
},
|
||||
updateBlockCategories: (state, action: PayloadAction<Array<BlockCategoryWebsocketData>>) => {
|
||||
action.payload.forEach((blockCategory) => {
|
||||
updateBoardCategories: (state, action: PayloadAction<Array<BoardCategoryWebsocketData>>) => {
|
||||
action.payload.forEach((boardCategory) => {
|
||||
for (let i = 0; i < state.categoryAttributes.length; i++) {
|
||||
const categoryAttribute = state.categoryAttributes[i]
|
||||
|
||||
// first we remove the block from list of blocks
|
||||
categoryAttribute.blockIDs = categoryAttribute.blockIDs.filter((blockID) => blockID !== blockCategory.blockID)
|
||||
// first we remove the board from list of boards
|
||||
categoryAttribute.boardIDs = categoryAttribute.boardIDs.filter((boardID) => boardID !== boardCategory.boardID)
|
||||
|
||||
// then we add it if this is the target category
|
||||
if (categoryAttribute.id === blockCategory.categoryID) {
|
||||
categoryAttribute.blockIDs.push(blockCategory.blockID)
|
||||
if (categoryAttribute.id === boardCategory.categoryID) {
|
||||
categoryAttribute.boardIDs.push(boardCategory.boardID)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -94,13 +94,13 @@ const sidebarSlice = createSlice({
|
|||
})
|
||||
|
||||
export const getSidebarCategories = createSelector(
|
||||
(state: RootState): Array<CategoryBlocks> => state.sidebar.categoryAttributes,
|
||||
(state: RootState): Array<CategoryBoards> => state.sidebar.categoryAttributes,
|
||||
(sidebarCategories) => sidebarCategories,
|
||||
)
|
||||
|
||||
export const {reducer} = sidebarSlice
|
||||
|
||||
export const {updateCategories, updateBlockCategories} = sidebarSlice.actions
|
||||
export const {updateCategories, updateBoardCategories} = sidebarSlice.actions
|
||||
|
||||
export {Category, CategoryBlocks, BlockCategoryWebsocketData}
|
||||
export {Category, CategoryBoards, BoardCategoryWebsocketData}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import {createFilterClause} from '../blocks/filterClause'
|
|||
import {createFilterGroup} from '../blocks/filterGroup'
|
||||
import {ImageBlock, createImageBlock} from '../blocks/imageBlock'
|
||||
import {TextBlock, createTextBlock} from '../blocks/textBlock'
|
||||
import {Category, CategoryBlocks} from '../store/sidebar'
|
||||
import {Category, CategoryBoards} from '../store/sidebar'
|
||||
import {Utils} from '../utils'
|
||||
import {CheckboxBlock, createCheckboxBlock} from '../blocks/checkboxBlock'
|
||||
import {Block} from '../blocks/block'
|
||||
|
@ -175,10 +175,10 @@ class TestBlockFactory {
|
|||
}
|
||||
}
|
||||
|
||||
static createCategoryBlocks(): CategoryBlocks {
|
||||
static createCategoryBoards(): CategoryBoards {
|
||||
return {
|
||||
...TestBlockFactory.createCategory(),
|
||||
blockIDs: [],
|
||||
boardIDs: [],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import {createCard} from './blocks/card'
|
|||
import {createCommentBlock} from './blocks/commentBlock'
|
||||
import {IAppWindow} from './types'
|
||||
import {ChangeHandlerType, WSMessage} from './wsclient'
|
||||
import {BlockCategoryWebsocketData, Category} from './store/sidebar'
|
||||
import {BoardCategoryWebsocketData, Category} from './store/sidebar'
|
||||
|
||||
declare let window: IAppWindow
|
||||
|
||||
|
@ -26,7 +26,7 @@ const SpacerClass = 'octo-spacer'
|
|||
const HorizontalGripClass = 'HorizontalGrip'
|
||||
const base32Alphabet = 'ybndrfg8ejkmcpqxot1uwisza345h769'
|
||||
|
||||
export type WSMessagePayloads = Block | Category | BlockCategoryWebsocketData | BoardType | BoardMember | null
|
||||
export type WSMessagePayloads = Block | Category | BoardCategoryWebsocketData | BoardType | BoardMember | null
|
||||
|
||||
// eslint-disable-next-line no-shadow
|
||||
enum IDType {
|
||||
|
|
|
@ -7,7 +7,7 @@ import {Utils, WSMessagePayloads} from './utils'
|
|||
import {Block} from './blocks/block'
|
||||
import {Board, BoardMember} from './blocks/board'
|
||||
import {OctoUtils} from './octoUtils'
|
||||
import {BlockCategoryWebsocketData, Category} from './store/sidebar'
|
||||
import {BoardCategoryWebsocketData, Category} from './store/sidebar'
|
||||
|
||||
// These are outgoing commands to the server
|
||||
type WSCommand = {
|
||||
|
@ -23,7 +23,7 @@ export type WSMessage = {
|
|||
block?: Block
|
||||
board?: Board
|
||||
category?: Category
|
||||
blockCategories?: BlockCategoryWebsocketData
|
||||
blockCategories?: BoardCategoryWebsocketData
|
||||
error?: string
|
||||
teamId?: string
|
||||
member?: BoardMember
|
||||
|
@ -40,7 +40,7 @@ export const ACTION_UNSUBSCRIBE_TEAM = 'UNSUBSCRIBE_TEAM'
|
|||
export const ACTION_UNSUBSCRIBE_BLOCKS = 'UNSUBSCRIBE_BLOCKS'
|
||||
export const ACTION_UPDATE_CLIENT_CONFIG = 'UPDATE_CLIENT_CONFIG'
|
||||
export const ACTION_UPDATE_CATEGORY = 'UPDATE_CATEGORY'
|
||||
export const ACTION_UPDATE_BLOCK_CATEGORY = 'UPDATE_BLOCK_CATEGORY'
|
||||
export const ACTION_UPDATE_BOARD_CATEGORY = 'UPDATE_BOARD_CATEGORY'
|
||||
export const ACTION_UPDATE_SUBSCRIPTION = 'UPDATE_SUBSCRIPTION'
|
||||
|
||||
type WSSubscriptionMsg = {
|
||||
|
@ -81,7 +81,7 @@ export type ChangeHandlerType = 'block' | 'category' | 'blockCategories' | 'boar
|
|||
type UpdatedData = {
|
||||
Blocks: Block[]
|
||||
Categories: Category[]
|
||||
BlockCategories: Array<BlockCategoryWebsocketData>
|
||||
BoardCategories: Array<BoardCategoryWebsocketData>
|
||||
Boards: Board[]
|
||||
BoardMembers: BoardMember[]
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ type UpdatedData = {
|
|||
type ChangeHandlers = {
|
||||
Block: OnChangeHandler[]
|
||||
Category: OnChangeHandler[]
|
||||
BlockCategory: OnChangeHandler[]
|
||||
BoardCategory: OnChangeHandler[]
|
||||
Board: OnChangeHandler[]
|
||||
BoardMember: OnChangeHandler[]
|
||||
}
|
||||
|
@ -107,14 +107,14 @@ class WSClient {
|
|||
state: 'init'|'open'|'close' = 'init'
|
||||
onStateChange: OnStateChangeHandler[] = []
|
||||
onReconnect: OnReconnectHandler[] = []
|
||||
onChange: ChangeHandlers = {Block: [], Category: [], BlockCategory: [], Board: [], BoardMember: []}
|
||||
onChange: ChangeHandlers = {Block: [], Category: [], BoardCategory: [], Board: [], BoardMember: []}
|
||||
onError: OnErrorHandler[] = []
|
||||
onConfigChange: OnConfigChangeHandler[] = []
|
||||
onFollowBlock: FollowChangeHandler = () => {}
|
||||
onUnfollowBlock: FollowChangeHandler = () => {}
|
||||
private notificationDelay = 100
|
||||
private reopenDelay = 3000
|
||||
private updatedData: UpdatedData = {Blocks: [], Categories: [], BlockCategories: [], Boards: [], BoardMembers: []}
|
||||
private updatedData: UpdatedData = {Blocks: [], Categories: [], BoardCategories: [], Boards: [], BoardMembers: []}
|
||||
private updateTimeout?: NodeJS.Timeout
|
||||
private errorPollId?: NodeJS.Timeout
|
||||
|
||||
|
@ -169,7 +169,7 @@ class WSClient {
|
|||
this.onChange.Category.push(handler)
|
||||
break
|
||||
case 'blockCategories':
|
||||
this.onChange.BlockCategory.push(handler)
|
||||
this.onChange.BoardCategory.push(handler)
|
||||
break
|
||||
case 'board':
|
||||
this.onChange.Board.push(handler)
|
||||
|
@ -187,7 +187,7 @@ class WSClient {
|
|||
haystack = this.onChange.Block
|
||||
break
|
||||
case 'blockCategories':
|
||||
haystack = this.onChange.BlockCategory
|
||||
haystack = this.onChange.BoardCategory
|
||||
break
|
||||
case 'board':
|
||||
haystack = this.onChange.Board
|
||||
|
@ -385,7 +385,7 @@ class WSClient {
|
|||
case ACTION_UPDATE_CATEGORY:
|
||||
this.updateHandler(message)
|
||||
break
|
||||
case ACTION_UPDATE_BLOCK_CATEGORY:
|
||||
case ACTION_UPDATE_BOARD_CATEGORY:
|
||||
this.updateHandler(message)
|
||||
break
|
||||
case ACTION_UPDATE_SUBSCRIPTION:
|
||||
|
@ -568,8 +568,8 @@ class WSClient {
|
|||
this.updatedData.Categories = this.updatedData.Categories.filter((c) => c.id !== (data as Category).id)
|
||||
this.updatedData.Categories.push(data as Category)
|
||||
} else if (type === 'blockCategories') {
|
||||
this.updatedData.BlockCategories = this.updatedData.BlockCategories.filter((b) => b.blockID === (data as BlockCategoryWebsocketData).blockID)
|
||||
this.updatedData.BlockCategories.push(data as BlockCategoryWebsocketData)
|
||||
this.updatedData.BoardCategories = this.updatedData.BoardCategories.filter((b) => b.boardID === (data as BoardCategoryWebsocketData).boardID)
|
||||
this.updatedData.BoardCategories.push(data as BoardCategoryWebsocketData)
|
||||
} else if (type === 'board') {
|
||||
this.updatedData.Boards = this.updatedData.Boards.filter((b) => b.id !== (data as Board).id)
|
||||
this.updatedData.Boards.push(data as Board)
|
||||
|
@ -612,8 +612,8 @@ class WSClient {
|
|||
Utils.log(`WSClient flush update category: ${category.id}`)
|
||||
}
|
||||
|
||||
for (const blockCategories of this.updatedData.BlockCategories) {
|
||||
Utils.log(`WSClient flush update blockCategory: ${blockCategories.blockID} ${blockCategories.categoryID}`)
|
||||
for (const blockCategories of this.updatedData.BoardCategories) {
|
||||
Utils.log(`WSClient flush update blockCategory: ${blockCategories.boardID} ${blockCategories.categoryID}`)
|
||||
}
|
||||
|
||||
for (const board of this.updatedData.Boards) {
|
||||
|
@ -636,8 +636,8 @@ class WSClient {
|
|||
handler(this, this.updatedData.Categories)
|
||||
}
|
||||
|
||||
for (const handler of this.onChange.BlockCategory) {
|
||||
handler(this, this.updatedData.BlockCategories)
|
||||
for (const handler of this.onChange.BoardCategory) {
|
||||
handler(this, this.updatedData.BoardCategories)
|
||||
}
|
||||
|
||||
for (const handler of this.onChange.Board) {
|
||||
|
@ -651,7 +651,7 @@ class WSClient {
|
|||
this.updatedData = {
|
||||
Blocks: [],
|
||||
Categories: [],
|
||||
BlockCategories: [],
|
||||
BoardCategories: [],
|
||||
Boards: [],
|
||||
BoardMembers: [],
|
||||
}
|
||||
|
@ -667,7 +667,7 @@ class WSClient {
|
|||
// Use this sequence so the onclose method doesn't try to re-open
|
||||
const ws = this.ws
|
||||
this.ws = null
|
||||
this.onChange = {Block: [], Category: [], BlockCategory: [], Board: [], BoardMember: []}
|
||||
this.onChange = {Block: [], Category: [], BoardCategory: [], Board: [], BoardMember: []}
|
||||
this.onReconnect = []
|
||||
this.onStateChange = []
|
||||
this.onError = []
|
||||
|
|
Loading…
Reference in a new issue