Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lock board #3955

Merged
merged 66 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
d57035c
Add simple component to lock the board in the quick menu
brandstetterm Mar 7, 2024
039baeb
Add allowEditing boolean to board type
brandstetterm Mar 7, 2024
7196dc1
Set toggle value of lock board component to current value of allow
brandstetterm Mar 7, 2024
78b36a4
Clicking on the lock board button dispatches api request
brandstetterm Mar 8, 2024
af1bc6f
Merge branch 'main' into mb/lock-board
brandstetterm Mar 8, 2024
d876b3b
Add board settings toggle to change the locking of a board
brandstetterm Mar 8, 2024
578785f
Add gap between different groups of board settings and change order
brandstetterm Mar 8, 2024
f68d9ed
Update snapshots of board settings and header menu
brandstetterm Mar 8, 2024
77d9dc7
Translate label of board settings toggle
brandstetterm Mar 8, 2024
b5c881f
Add translated labels to header menu toggle
brandstetterm Mar 8, 2024
c4689a9
Update snapshots of header menu and board settings
brandstetterm Mar 8, 2024
15e46ab
Change import order of lock board component
brandstetterm Mar 8, 2024
9fcd848
Grey out disabled buttons when board is locked and add lock icon to note
brandstetterm Mar 11, 2024
b7b3eae
Disable the moving of notes for participants when the board is locked
brandstetterm Mar 11, 2024
0b7da39
Hide note reactions when board is locked and participant is not
brandstetterm Mar 11, 2024
2ff2f67
Resolve merge conflicts
brandstetterm Mar 12, 2024
6e92701
Merge branch 'main' into mb/lock-board
brandstetterm Mar 12, 2024
82805ba
Remove box shadow when noteinput is disabled (only for normal
brandstetterm Mar 12, 2024
b3a6381
Only disable the menu bar items when the participant is not moderator
brandstetterm Mar 12, 2024
912ad67
Disable textarea of note for participants
brandstetterm Mar 12, 2024
1d018ce
Hide note reactions button for participants when board is locked
brandstetterm Mar 12, 2024
c63f550
Disable button to remove own note reaction for non-moderator
brandstetterm Mar 12, 2024
7d5eb95
Gray out plus icon in noteinput if board is locked
brandstetterm Mar 14, 2024
0ea5b5a
Remove margins from elements and add padding to noteinput
brandstetterm Mar 14, 2024
d61f193
Hide note dialog options (delete and unstack button) if board is locked
brandstetterm Mar 14, 2024
e647811
Merge remote-tracking branch 'origin/main' into mb/lock-board
brandstetterm Mar 14, 2024
cf35022
Hide button to add votes and disable remove vote button for participants
brandstetterm Mar 14, 2024
07a3343
Remove disabled state from mark as ready and raise hand buttons in user
brandstetterm Mar 14, 2024
179cbb8
Merge branch 'main' into mb/lock-board
brandstetterm Mar 15, 2024
db9cebd
Make switch to lock board in header menu accessible by adding role and
brandstetterm Mar 15, 2024
8afb2ae
Update tests and snapshot of header menu component
brandstetterm Mar 15, 2024
ebeddb5
Update tests of note input component
brandstetterm Mar 15, 2024
ddb4df7
Add translated titles to add and remove vote buttons and update
brandstetterm Mar 15, 2024
bfcf352
Update tests of votes component
brandstetterm Mar 15, 2024
efb028b
Fix liniting warnings
brandstetterm Mar 15, 2024
f4da7cf
Add container queries to note input component to enhance responsibility
brandstetterm Mar 15, 2024
c3295f2
Fix typo in header menu unit tests
brandstetterm Mar 18, 2024
2461ce9
Revert changes in column settings component
brandstetterm Mar 18, 2024
eb0885b
Merge main and resolve conflicts
brandstetterm Mar 18, 2024
832b343
Merge branch 'main' into mb/lock-board
brandstetterm Mar 18, 2024
cb015c0
Merge branch 'main' into mb/lock-board
brandstetterm Mar 18, 2024
48f2461
Hide board reactions menu if board is locked for non-moderators
brandstetterm Mar 18, 2024
db6d354
Change logic to hide reactions menu if board is locked
brandstetterm Mar 18, 2024
036ec47
refactor: change import order of menu bars component
brandstetterm Mar 18, 2024
dc54e95
Merge branch 'main' into mb/lock-board
brandstetterm Mar 20, 2024
3d2027a
improvement: locked board notification (#4104)
Schwehn42 Apr 30, 2024
80770b4
fix hard coded size and color
Schwehn42 May 6, 2024
3f47b6b
Merge branch 'refs/heads/main' into mb/lock-board
Schwehn42 May 6, 2024
da6ee93
make linter happy
Schwehn42 May 6, 2024
dbffdf2
Merge branch 'main' into mb/lock-board
brandstetterm May 7, 2024
024b1db
Revert "Change logic to hide reactions menu if board is locked"
Schwehn42 May 13, 2024
e1abc02
no longer disable board reactions menu
Schwehn42 May 13, 2024
ec93947
Revert "Hide board reactions menu if board is locked for non-moderators"
Schwehn42 May 13, 2024
0dbd526
remove unused store selector
Schwehn42 May 13, 2024
c272368
revert: reallow locked board reactions (#4144)
Schwehn42 May 14, 2024
f45bf17
refactor: allowEditing -> isLocked (#4145)
Schwehn42 May 29, 2024
f91b3c3
Merge branch 'main' into mb/lock-board
Schwehn42 May 29, 2024
0b772df
Merge branch 'refs/heads/main' into mb/lock-board
Schwehn42 Jun 17, 2024
2442722
fix icon
Schwehn42 Jun 17, 2024
37a6774
Merge branch 'refs/heads/main' into mb/lock-board
Schwehn42 Jun 26, 2024
0ee90ed
update collection
Schwehn42 Jun 26, 2024
fb12918
Merge branch 'refs/heads/main' into mb/lock-board
Schwehn42 Jul 16, 2024
4fd9827
increment migration file prefix
Schwehn42 Jul 16, 2024
e2c09d1
fix color names
Schwehn42 Jul 16, 2024
ff5043f
update postman collection
Schwehn42 Jul 16, 2024
b8f8712
Merge branch 'refs/heads/main' into mb/lock-board
Schwehn42 Jul 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 95 additions & 21 deletions server/api.postman_collection.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"info": {
"_postman_id": "8a37e0fe-f06b-41e4-a538-6689616bd5a6",
"_postman_id": "45d5f690-f459-4371-a09f-8aff874591f2",
"name": "scrumlr.io",
"description": "This is the documentation for the REST API server of the application [scrumlr.io](https://scrumlr.io). You get in touch with us and send an email to [[email protected]](https://[email protected]). The software is [MIT licensed](https://opensource.org/licenses/MIT) so do whatever you want with it. If you want to checkout the progress of our development and take a peek into our backlog you can checkout our [GitHub repository](https://github.com/inovex/scrumlr.io). By the way, this already the third iteration of our server and we're still working on the interface and on further improvements. Since the API is mainly intended for our web client we won't start with API versions at the moment so breaking changes may be incoming. Once it got stable we'll maybe start with that.\n\nIf you're using the postman collection in order to explore the different resources you should also checkout the variables of the collection. Anytime you'll create new resources (e.g. your login or a board) variables will be stored and used for subsequent calls on other resources.\n\nAccess to protected resources will be authorized if a bearer token is sent or it is included in the `jwt` Cookie, which will be automatically set upon login.\n\n## Getting started\n\nLet's try to explain the basic flow of how a new board can will be created and someone tries to join the board as a participant.\n\nFirst you can check whether you are already logged in by a `GET` request on `/user`. See the _User_ section for more information.\n\n1. A user signs into the application (see _Login_ section)\n2. The user creates a new board (`POST` on `/boards`, checkout _Boards_ section)\n3. Another logged in user tries to join the board (`POST` on `/boards/{id}/participants`, checkout _Participants_ section)\n 1. If the boards access policy is set to `PUBLIC` the participant will be added to the board and afterwards all resources will be available\n 2. If the board requires a passphrase and the access policy is set to `BY_PASSPHRASE` a client error will be reported until the user sends the correct passphrase within the payload of the request\n 3. If the boards access policy is set to `BY_INVITE` a session request will be created instead and the user will be redirected to the new resource. The board owner now needs to accept or reject the request until the user can continue\n\nThese are just the basic steps of how sessions can be created. You can also have a look into the section _Realtime_ to see how you can open websockets and listen to live updates on the data.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"_exporter_id": "32423964"
"_exporter_id": "32837949"
},
"item": [
{
Expand Down Expand Up @@ -1962,15 +1962,6 @@
"originalRequest": {
"method": "GET",
"header": [],
"body": {
"mode": "raw",
"raw": "",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{base_url}}/boards",
"host": [
Expand All @@ -1981,8 +1972,8 @@
]
}
},
"_postman_previewlanguage": null,
"header": null,
"_postman_previewlanguage": "Text",
"header": [],
"cookie": [],
"body": "[\n {\n \"board\": {\n \"id\": \"4b08e0e9-f141-49b0-a75f-17d181f96969\",\n \"name\": \"My board\",\n \"description\": \"This is a test description\",\n \"accessPolicy\": \"PUBLIC\",\n \"showAuthors\": true,\n \"showNotesOfOtherUsers\": true,\n \"showNoteReactions\": true,\n \"allowStacking\": true,\n \"allowEditing\": true,\n \"sharedNote\": null,\n \"showVoting\": null\n },\n \"columnsNumber\": 2,\n \"createdAt\": \"0001-01-01T00:00:00Z\",\n \"participants\": 1\n }\n]"
}
Expand Down Expand Up @@ -2393,13 +2384,97 @@
" var allowStacking = pm.response.json().allowStacking;",
" pm.expect(allowStacking).to.eql(false);",
"})",
"",
""
],
"type": "text/javascript",
"packages": {}
}
}
],
"protocolProfileBehavior": {
"disabledSystemHeaders": {}
},
"request": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"sharedNote\": null,\n \"showVoting\": null,\n \"timerStart\": \"2024-01-18T13:38:49.304Z\",\n \"timerEnd\": \"2024-01-18T13:39:49.304Z\",\n \"showAuthors\": false,\n \"showNotesOfOtherUsers\": false,\n \"showNoteReactions\": false,\n \"allowStacking\": false\n // \"isLocked\": true // tested separately in next request\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{base_url}}/boards/{{board_id}}",
"host": [
"{{base_url}}"
],
"path": [
"boards",
"{{board_id}}"
]
}
},
"response": [
{
"name": "Success",
"originalRequest": {
"method": "PUT",
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"sharedNote\":null,\n \"showVoting\":null,\n \"timerStart\":\"2024-01-18T13:38:49.304Z\",\n \"timerEnd\":\"2024-01-18T13:39:49.304Z\"\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{base_url}}/boards/{{board_id}}",
"host": [
"{{base_url}}"
],
"path": [
"boards",
"{{board_id}}"
]
}
},
"_postman_previewlanguage": "json",
"header": [
{
"key": "Content-Type",
"value": "application/json",
"description": "",
"type": "text"
}
],
"cookie": [],
"body": "{\n \"id\": \"{{board_id}}\",\n \"name\": \"My board\",\n \"description\": \"Updated to new description\",\n \"accessPolicy\": \"BY_PASSPHRASE\",\n \"showAuthors\": false,\n \"showNotesOfOtherUsers\": false,\n \"showNoteReactions\": false,\n \"allowStacking\": false,\n \"isLocked\": false,\n \"timerStart\": \"2024-01-18T13:38:49.304Z\",\n \"timerEnd\": \"2024-01-18T13:39:49.304Z\",\n \"sharedNote\": null,\n \"showVoting\": null\n}"
}
]
},
{
"name": "Lock Board",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test(\"Successful PUT request\", function () {",
" pm.expect(pm.response).to.have.status(200);",
"});",
"",
"pm.test(\"Check allowEditing changed\", function () {",
" var allowEditing = pm.response.json().allowEditing;",
" pm.expect(allowEditing).to.eql(false);",
" var isLocked = pm.response.json().isLocked;",
" pm.expect(isLocked).to.eql(true);",
"})",
""
"",
"// one could add a test which checks whether the lock actually works, ",
"// but you'd need to change your role from moderator to normal participant or add another participant to verify"
],
"type": "text/javascript",
"packages": {}
Expand All @@ -2414,7 +2489,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"sharedNote\": null,\n \"showVoting\": null,\n \"timerStart\": \"2024-01-18T13:38:49.304Z\",\n \"timerEnd\": \"2024-01-18T13:39:49.304Z\",\n \"showAuthors\": false,\n \"showNotesOfOtherUsers\": false,\n \"showNoteReactions\": false,\n \"allowStacking\": false,\n \"allowEditing\": false\n}",
"raw": "{\n \"isLocked\": true\n}",
"options": {
"raw": {
"language": "json"
Expand All @@ -2440,7 +2515,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"sharedNote\":null,\n \"showVoting\":null,\n \"timerStart\":\"2024-01-18T13:38:49.304Z\",\n \"timerEnd\":\"2024-01-18T13:39:49.304Z\",\n \"allowEditing\":true\n}",
"raw": "{\n \"isLocked\": true\n}",
"options": {
"raw": {
"language": "json"
Expand All @@ -2463,13 +2538,12 @@
{
"key": "Content-Type",
"value": "application/json",
"name": "Content-Type",
"description": "",
"type": "text"
}
],
"cookie": [],
"body": "{\n \"id\": \"{{board_id}}\",\n \"name\": \"My board\",\n \"description\": \"Updated to new description\",\n \"accessPolicy\": \"BY_PASSPHRASE\",\n \"showAuthors\": false,\n \"showNotesOfOtherUsers\": false,\n \"showNoteReactions\": false,\n \"allowStacking\": false,\n \"allowEditing\": false,\n \"timerStart\": \"2024-01-18T13:38:49.304Z\",\n \"timerEnd\": \"2024-01-18T13:39:49.304Z\",\n \"sharedNote\": null,\n \"showVoting\": null\n}"
"body": "{\n \"id\": \"{{board_id}}\",\n \"name\": \"My board\",\n \"description\": \"Updated to new description\",\n \"accessPolicy\": \"BY_PASSPHRASE\",\n \"showAuthors\": false,\n \"showNotesOfOtherUsers\": false,\n \"showNoteReactions\": false,\n \"isLocked\": true,\n \"allowEditing\": false,\n \"timerStart\": \"2024-01-18T13:38:49.304Z\",\n \"timerEnd\": \"2024-01-18T13:39:49.304Z\",\n \"sharedNote\": null,\n \"showVoting\": null\n}"
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions server/src/api/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,13 @@ func (s *Server) BoardEditableContext(next http.Handler) http.Handler {
return
}

if !isMod && !settings.AllowEditing {
if !isMod && settings.IsLocked {
log.Errorw("not allowed to edit board", "err", err)
common.Throw(w, r, common.ForbiddenError(errors.New("not authorized to change board")))
return
}

boardEditable := context.WithValue(r.Context(), identifiers.BoardEditableIdentifier, settings.AllowEditing)
boardEditable := context.WithValue(r.Context(), identifiers.BoardEditableIdentifier, settings.IsLocked)
next.ServeHTTP(w, r.WithContext(boardEditable))
})
}
Expand Down
16 changes: 8 additions & 8 deletions server/src/api/notes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,12 +254,12 @@ func (suite *NotesTestSuite) TestDeleteNote() {
name string
expectedCode int
err error
allowEditing bool
isLocked bool
}{
{
name: "Delete Note when board is unlocked",
expectedCode: http.StatusNoContent,
allowEditing: true,
isLocked: true,
},
{
name: "Delete Note when board is locked",
Expand All @@ -270,7 +270,7 @@ func (suite *NotesTestSuite) TestDeleteNote() {
StatusText: "Bad request",
ErrorText: "something",
},
allowEditing: false,
isLocked: false,
},
}
for _, tt := range tests {
Expand All @@ -289,8 +289,8 @@ func (suite *NotesTestSuite) TestDeleteNote() {
r := chi.NewRouter()
s.initNoteResources(r)
boardMock.On("Get", boardID).Return(&dto.Board{
ID: boardID,
AllowEditing: tt.allowEditing,
ID: boardID,
IsLocked: tt.isLocked,
}, nil)

// Mock the SessionExists method
Expand All @@ -302,12 +302,12 @@ func (suite *NotesTestSuite) TestDeleteNote() {
// Mock the ParticipantBanned method
sessionMock.On("ParticipantBanned", mock.Anything, boardID, userID).Return(false, nil)

if tt.allowEditing {
if tt.isLocked {
noteMock.On("Delete", mock.Anything, mock.Anything).Return(nil)
} else {
boardMock.On("Get", boardID).Return(&dto.Board{
ID: boardID,
AllowEditing: tt.allowEditing,
ID: boardID,
IsLocked: tt.isLocked,
}, tt.err)
noteMock.On("Delete", mock.Anything, mock.Anything).Return(tt.err)
}
Expand Down
1 change: 0 additions & 1 deletion server/src/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,6 @@ func (s *Server) initReactionResources(r chi.Router) {
func (s *Server) initBoardReactionResources(r chi.Router) {
r.Route("/board-reactions", func(r chi.Router) {
r.Use(s.BoardParticipantContext)
r.Use(s.BoardEditableContext)

r.Post("/", s.createBoardReaction)
})
Expand Down
6 changes: 3 additions & 3 deletions server/src/common/dto/boards.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Board struct {

AllowStacking bool `json:"allowStacking"`

AllowEditing bool `json:"allowEditing"`
IsLocked bool `json:"isLocked"`

TimerStart *time.Time `json:"timerStart,omitempty"`
TimerEnd *time.Time `json:"timerEnd,omitempty"`
Expand All @@ -57,7 +57,7 @@ func (b *Board) From(board database.Board) *Board {
b.ShowNotesOfOtherUsers = board.ShowNotesOfOtherUsers
b.ShowNoteReactions = board.ShowNoteReactions
b.AllowStacking = board.AllowStacking
b.AllowEditing = board.AllowEditing
b.IsLocked = board.IsLocked
b.SharedNote = board.SharedNote
b.ShowVoting = board.ShowVoting
b.TimerStart = board.TimerStart
Expand Down Expand Up @@ -121,7 +121,7 @@ type BoardUpdateRequest struct {
AllowStacking *bool `json:"allowStacking"`

// Set whether changes to board should be allowed to all users or only moderators.
AllowEditing *bool `json:"allowEditing"`
IsLocked *bool `json:"isLocked"`

// Set the timer start.
TimerStart *time.Time `json:"timerStart"`
Expand Down
8 changes: 4 additions & 4 deletions server/src/database/boards.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type Board struct {
ShowNotesOfOtherUsers bool
ShowNoteReactions bool
AllowStacking bool
AllowEditing bool
IsLocked bool
CreatedAt time.Time
TimerStart *time.Time
TimerEnd *time.Time
Expand Down Expand Up @@ -60,7 +60,7 @@ type BoardUpdate struct {
ShowNotesOfOtherUsers *bool
ShowNoteReactions *bool
AllowStacking *bool
AllowEditing *bool
IsLocked *bool
TimerStart *time.Time
TimerEnd *time.Time
SharedNote uuid.NullUUID
Expand Down Expand Up @@ -143,8 +143,8 @@ func (d *Database) UpdateBoard(update BoardUpdate) (Board, error) {
if update.AllowStacking != nil {
query.Column("allow_stacking")
}
if update.AllowEditing != nil {
query.Column("allow_editing")
if update.IsLocked != nil {
query.Column("is_locked")
}

var board Board
Expand Down
6 changes: 3 additions & 3 deletions server/src/database/boards_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,13 +442,13 @@ func testUpdateBoardSettings(t *testing.T) {

showAuthors := true
showNotesOfOtherUsers := true
allowEditing := true
updatedBoard, err := testDb.UpdateBoard(BoardUpdate{ID: board.ID, ShowAuthors: &showAuthors, ShowNotesOfOtherUsers: &showNotesOfOtherUsers, AllowEditing: &allowEditing})
isLocked := true
updatedBoard, err := testDb.UpdateBoard(BoardUpdate{ID: board.ID, ShowAuthors: &showAuthors, ShowNotesOfOtherUsers: &showNotesOfOtherUsers, IsLocked: &isLocked})

assert.Nil(t, err)
assert.Equal(t, showAuthors, updatedBoard.ShowAuthors)
assert.Equal(t, showNotesOfOtherUsers, updatedBoard.ShowNotesOfOtherUsers)
assert.Equal(t, allowEditing, updatedBoard.AllowEditing)
assert.Equal(t, isLocked, updatedBoard.IsLocked)
}

func testGetBoard(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE boards ALTER COLUMN is_locked SET DEFAULT TRUE;
ALTER TABLE boards RENAME COLUMN is_locked TO allow_editing;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE boards ALTER COLUMN allow_editing SET DEFAULT FALSE;
ALTER TABLE boards RENAME COLUMN allow_editing TO is_locked;
2 changes: 1 addition & 1 deletion server/src/services/boards/boards.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (s *BoardService) Update(ctx context.Context, body dto.BoardUpdateRequest)
ShowNotesOfOtherUsers: body.ShowNotesOfOtherUsers,
ShowNoteReactions: body.ShowNoteReactions,
AllowStacking: body.AllowStacking,
AllowEditing: body.AllowEditing,
IsLocked: body.IsLocked,
TimerStart: body.TimerStart,
TimerEnd: body.TimerEnd,
SharedNote: body.SharedNote,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import "./AccessPolicySelection.scss";
import {AccessPolicy} from "types/board";
import {generateRandomString} from "utils/random";
import {useTranslation} from "react-i18next";
import {Visible, Hidden, Duplicate,Refresh} from "components/Icon";
import {Visible, Hidden, Duplicate, Refresh} from "components/Icon";
import {TextInputAdornment} from "components/TextInputAdornment";
import {TextInputLabel} from "../TextInputLabel";
import {TextInput} from "../TextInput";
Expand Down
12 changes: 11 additions & 1 deletion src/components/Board/Board.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ import "./Board.scss";
import {useDndMonitor} from "@dnd-kit/core";
import classNames from "classnames";
import {useStripeOffset} from "utils/hooks/useStripeOffset";
import {Toast} from "utils/Toast";
import {useTranslation} from "react-i18next";

export interface BoardProps {
children: React.ReactElement<ColumnProps> | React.ReactElement<ColumnProps>[];
currentUserIsModerator: boolean;
moderating: boolean;
locked: boolean;
}

export interface BoardState {
Expand All @@ -26,7 +29,8 @@ export interface ColumnState {
lastVisibleColumnIndex: number;
}

export const BoardComponent = ({children, currentUserIsModerator, moderating}: BoardProps) => {
export const BoardComponent = ({children, currentUserIsModerator, moderating, locked}: BoardProps) => {
const {t} = useTranslation();
const [state, setState] = useState<BoardState & ColumnState>({
firstVisibleColumnIndex: 0,
lastVisibleColumnIndex: React.Children.count(children),
Expand Down Expand Up @@ -135,6 +139,12 @@ export const BoardComponent = ({children, currentUserIsModerator, moderating}: B
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [columnState]);

useEffect(() => {
if (locked) {
Toast.info({title: t("Toast.lockedBoard"), autoClose: 10_000});
}
}, [t, locked]);

if (!children || columnsCount === 0) {
// Empty board
return (
Expand Down
Loading
Loading