Skip to content

Commit 039077b

Browse files
authored
Merge pull request #6881 from LibreSign/fix/sidebar-auto-close-on-deselect
fix: sidebar auto close on deselect
2 parents d01bb1d + 7048efb commit 039077b

File tree

3 files changed

+102
-68
lines changed

3 files changed

+102
-68
lines changed

src/store/files.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ export const useFilesStore = function(...args) {
4242
}
4343

4444
if (this.selectedFileId === fileId) {
45-
const sidebarStore = useSidebarStore()
46-
sidebarStore.hideSidebar()
47-
this.selectedFileId = 0
45+
this.selectFile()
4846
}
4947

5048
del(this.files, fileId)
@@ -90,6 +88,10 @@ export const useFilesStore = function(...args) {
9088
},
9189
selectFile(fileId) {
9290
this.selectedFileId = fileId ?? 0
91+
if (!fileId) {
92+
const sidebarStore = useSidebarStore()
93+
sidebarStore.hideSidebar()
94+
}
9395
},
9496
async selectFileByNodeId(nodeId) {
9597
let fileId = this.getFileIdByNodeId(nodeId)
@@ -607,9 +609,7 @@ export const useFilesStore = function(...args) {
607609
}
608610

609611
if (this.selectedFileId && !this.files[this.selectedFileId]) {
610-
const sidebarStore = useSidebarStore()
611-
sidebarStore.hideSidebar()
612-
this.selectedFileId = 0
612+
this.selectFile()
613613
}
614614

615615
this.loading = false

src/tests/actions/showStatusInlineAction.spec.js

Lines changed: 69 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,67 +3,74 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6-
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
7-
8-
const mocks = vi.hoisted(() => {
9-
const mockRegisterFileAction = vi.fn()
10-
const mockGetSidebar = vi.fn()
11-
const mockLoadState = vi.fn()
12-
const capturedActionRef = { value: null }
13-
14-
return {
15-
capturedActionRef,
16-
mockRegisterFileAction,
17-
mockGetSidebar,
18-
mockLoadState
19-
}
20-
})
21-
22-
vi.mock('@nextcloud/files', () => ({
23-
FileAction: class {
24-
constructor(config) {
25-
Object.assign(this, config)
26-
}
27-
},
28-
registerFileAction: (actionInstance) => {
29-
mocks.capturedActionRef.value = actionInstance
30-
mocks.mockRegisterFileAction(actionInstance)
31-
},
32-
getSidebar: mocks.mockGetSidebar,
33-
}))
34-
35-
vi.mock('@nextcloud/initial-state', () => ({
36-
loadState: (...args) => mocks.mockLoadState(...args),
37-
}))
38-
39-
vi.mock('@nextcloud/l10n', () => ({
40-
t: (app, text) => text,
41-
}))
42-
43-
vi.mock('../../constants.js', () => ({
44-
FILE_STATUS: {
45-
DRAFT: 0,
46-
SIGNED: 3,
47-
},
48-
}))
49-
50-
vi.mock('../../utils/fileStatus.js', () => ({
51-
getStatusLabel: (status) => `Status ${status}`,
52-
getStatusSvgInline: (status) => `<svg>${status}</svg>`,
53-
}))
6+
import { beforeAll, beforeEach, describe, expect, it, vi, afterEach } from 'vitest'
547

558
describe('showStatusInlineAction', () => {
569
let action
10+
let capturedActionRef
11+
let mockRegisterFileAction
12+
let mockGetSidebar
13+
let mockLoadState
5714

5815
beforeEach(async () => {
16+
// Clean up global state
17+
delete globalThis._nc_files_scope
18+
19+
// Create fresh mocks for this test
20+
capturedActionRef = { value: null }
21+
mockRegisterFileAction = vi.fn()
22+
mockGetSidebar = vi.fn()
23+
mockLoadState = vi.fn(() => true)
24+
25+
// Setup mocks with fresh state
26+
vi.doMock('@nextcloud/files', () => ({
27+
FileAction: class {
28+
constructor(config) {
29+
Object.assign(this, config)
30+
}
31+
},
32+
registerFileAction: (actionInstance) => {
33+
capturedActionRef.value = actionInstance
34+
mockRegisterFileAction(actionInstance)
35+
},
36+
getSidebar: mockGetSidebar,
37+
}))
38+
39+
vi.doMock('@nextcloud/initial-state', () => ({
40+
loadState: (...args) => mockLoadState(...args),
41+
}))
42+
43+
vi.doMock('@nextcloud/l10n', () => ({
44+
t: (app, text) => text,
45+
}))
46+
47+
vi.doMock('../../constants.js', () => ({
48+
FILE_STATUS: {
49+
DRAFT: 0,
50+
SIGNED: 3,
51+
},
52+
}))
53+
54+
vi.doMock('../../utils/fileStatus.js', () => ({
55+
getStatusLabel: (status) => `Status ${status}`,
56+
getStatusSvgInline: (status) => `<svg>${status}</svg>`,
57+
}))
58+
59+
// Reset modules and import the action
5960
vi.resetModules()
60-
mocks.capturedActionRef.value = null
61-
mocks.mockRegisterFileAction.mockClear()
62-
mocks.mockGetSidebar.mockClear()
63-
mocks.mockLoadState.mockClear()
64-
mocks.mockLoadState.mockReturnValue(true)
6561
await import('../../actions/showStatusInlineAction.js')
66-
action = mocks.capturedActionRef.value
62+
63+
// Capture the registered action
64+
action = capturedActionRef.value
65+
})
66+
67+
afterEach(() => {
68+
// Clean up all mocks after each test
69+
vi.unmock('@nextcloud/files')
70+
vi.unmock('@nextcloud/initial-state')
71+
vi.unmock('@nextcloud/l10n')
72+
vi.unmock('../../constants.js')
73+
vi.unmock('../../utils/fileStatus.js')
6774
})
6875

6976
it('has correct id', () => {
@@ -178,7 +185,7 @@ describe('showStatusInlineAction', () => {
178185
open: vi.fn(),
179186
setActiveTab: vi.fn(),
180187
}
181-
mocks.mockGetSidebar.mockReturnValue(mockSidebar)
188+
mockGetSidebar.mockReturnValue(mockSidebar)
182189

183190
const node = { fileid: 123, name: 'test.pdf' }
184191
const result = await action.exec({ nodes: [node] })
@@ -191,7 +198,7 @@ describe('showStatusInlineAction', () => {
191198

192199
describe('enabled', () => {
193200
it('returns false when certificate is not ok', () => {
194-
mocks.mockLoadState.mockReturnValue(false)
201+
mockLoadState.mockReturnValue(false)
195202

196203
const result = action.enabled({
197204
nodes: [{
@@ -206,7 +213,7 @@ describe('showStatusInlineAction', () => {
206213
})
207214

208215
it('returns false when nodes do not have status', () => {
209-
mocks.mockLoadState.mockReturnValue(true)
216+
mockLoadState.mockReturnValue(true)
210217

211218
const result = action.enabled({
212219
nodes: [{
@@ -219,7 +226,7 @@ describe('showStatusInlineAction', () => {
219226
})
220227

221228
it('returns true for PDF with status', () => {
222-
mocks.mockLoadState.mockReturnValue(true)
229+
mockLoadState.mockReturnValue(true)
223230

224231
const result = action.enabled({
225232
nodes: [{
@@ -234,7 +241,7 @@ describe('showStatusInlineAction', () => {
234241
})
235242

236243
it('returns true for folder with status', () => {
237-
mocks.mockLoadState.mockReturnValue(true)
244+
mockLoadState.mockReturnValue(true)
238245

239246
const result = action.enabled({
240247
nodes: [{
@@ -249,7 +256,7 @@ describe('showStatusInlineAction', () => {
249256
})
250257

251258
it('returns false for non-PDF/non-folder', () => {
252-
mocks.mockLoadState.mockReturnValue(true)
259+
mockLoadState.mockReturnValue(true)
253260

254261
const result = action.enabled({
255262
nodes: [{
@@ -265,7 +272,7 @@ describe('showStatusInlineAction', () => {
265272
})
266273

267274
it('returns true for multiple PDFs with status', () => {
268-
mocks.mockLoadState.mockReturnValue(true)
275+
mockLoadState.mockReturnValue(true)
269276

270277
const result = action.enabled({
271278
nodes: [
@@ -290,7 +297,7 @@ describe('showStatusInlineAction', () => {
290297

291298
describe('registration', () => {
292299
it('registers file action', () => {
293-
expect(mocks.mockRegisterFileAction).toHaveBeenCalled()
300+
expect(mockRegisterFileAction).toHaveBeenCalled()
294301
})
295302
})
296303
})

src/tests/store/files.spec.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,33 @@ describe('files store - critical business rules', () => {
128128

129129
expect(store.selectedFileId).toBe(0)
130130
})
131+
132+
it('selectFile without arguments resets to 0 (deselection)', () => {
133+
const store = useFilesStore()
134+
store.selectedFileId = 123
135+
136+
store.selectFile()
137+
138+
expect(store.selectedFileId).toBe(0)
139+
})
140+
141+
it('selectFile with fileId sets the file', () => {
142+
const store = useFilesStore()
143+
store.selectedFileId = 0
144+
145+
store.selectFile(456)
146+
147+
expect(store.selectedFileId).toBe(456)
148+
})
149+
150+
it('selectFile with 0 is treated as deselection', () => {
151+
const store = useFilesStore()
152+
store.selectedFileId = 789
153+
154+
store.selectFile(0)
155+
156+
expect(store.selectedFileId).toBe(0)
157+
})
131158
})
132159

133160
describe('RULE: file settings are merged, not replaced', () => {

0 commit comments

Comments
 (0)