Skip to content

Commit 6ce8c8e

Browse files
committed
Merge branch 'epic-sections' of github.com:ideo/shape into resizable-sections
2 parents 0dfcf7d + 357b522 commit 6ce8c8e

23 files changed

+158
-120
lines changed

__js_test_config/mocks/fakeUiStore.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ const fakeUiStore = {
151151
clearTempTextCardItems: jest.fn(),
152152
setTextEditingCard: jest.fn(),
153153
positionForCoordinates: jest.fn().mockReturnValue({ x:0, y:0, xPos: 0, yPos: 0, width: 1, height: 1 }),
154+
coordinatesForPosition: jest.fn().mockReturnValue({ row: 0, col: 0 }),
154155
dragGridSpot: new Map(),
155156
droppingFilesCount: 0,
156157
foamcoreBoundingRectangle: {

__tests__/stores/UiStore.unit.test.js

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ let uiStore
1414
const fakeCollection = {
1515
id: '123',
1616
isCollection: true,
17+
isBoard: true,
18+
num_columns: 4,
1719
parent_collection_card: {},
1820
setCollaborators: jest.fn(),
1921
}
@@ -319,16 +321,7 @@ describe('UiStore', () => {
319321
maxY: 200,
320322
}
321323
beforeEach(() => {
322-
uiStore.setSelectedArea(coords)
323-
// cardPositions determines where each card is placed on the grid
324-
// gets called in GridCard when it sets the ref
325-
uiStore.setCardPosition('1', { top: 0, right: 100, bottom: 100, left: 0 })
326-
uiStore.setCardPosition('2', {
327-
top: 300,
328-
right: 100,
329-
bottom: 500,
330-
left: 0,
331-
})
324+
fakeCollection.cardIdsBetweenByColRow = jest.fn().mockReturnValue(['1'])
332325
uiStore.setViewingRecord({
333326
...fakeCollection,
334327
collection_cards: [],
@@ -338,22 +331,23 @@ describe('UiStore', () => {
338331

339332
it('selects cards in within the selectedArea', () => {
340333
expect(uiStore.selectedCardIds).toEqual([])
341-
uiStore.selectCardsWithinSelectedArea()
334+
uiStore.setSelectedArea(coords)
335+
expect(fakeCollection.cardIdsBetweenByColRow).toHaveBeenCalledWith({
336+
minMaxCorners: {
337+
maxCol: 0,
338+
maxRow: 0,
339+
minCol: 0,
340+
minRow: 0,
341+
},
342+
})
342343
expect(uiStore.selectedCardIds).toEqual(['1'])
343344
})
344345

345346
it('adds to selection if shifted', () => {
346347
uiStore.reselectCardIds(['5'])
347348
uiStore.setSelectedArea(coords, { shifted: true })
348-
uiStore.selectCardsWithinSelectedArea()
349349
expect(uiStore.selectedCardIds).toEqual(['1', '5'])
350350
})
351-
352-
it('omits cards that are not in viewingCollection', () => {
353-
uiStore.setViewingRecord({ ...fakeCollection, id: '999', cardIds: ['2'] })
354-
uiStore.selectCardsWithinSelectedArea()
355-
expect(uiStore.selectedCardIds).toEqual([])
356-
})
357351
})
358352

359353
describe('zoom functions', () => {

__tests__/stores/jsonApi/Collection.unit.test.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -345,23 +345,38 @@ describe('Collection', () => {
345345

346346
it('returns cards in rectangular area from two cards', () => {
347347
expect(
348-
collection.cardIdsBetweenByColRow(cardIds[0], cardIds[1])
348+
collection.cardIdsBetweenByColRow({
349+
firstCardId: cardIds[0],
350+
lastCardId: cardIds[1],
351+
})
349352
).toEqual([cardIds[0], cardIds[1]])
350353

351354
expect(
352-
collection.cardIdsBetweenByColRow(cardIds[2], cardIds[4])
355+
collection.cardIdsBetweenByColRow({
356+
firstCardId: cardIds[2],
357+
lastCardId: cardIds[4],
358+
})
353359
).toEqual([cardIds[2], cardIds[4]])
354360

355361
expect(
356-
collection.cardIdsBetweenByColRow(cardIds[0], cardIds[2])
362+
collection.cardIdsBetweenByColRow({
363+
firstCardId: cardIds[0],
364+
lastCardId: cardIds[2],
365+
})
357366
).toEqual([cardIds[0], cardIds[1], cardIds[2]])
358367

359368
expect(
360-
collection.cardIdsBetweenByColRow(cardIds[0], cardIds[3])
369+
collection.cardIdsBetweenByColRow({
370+
firstCardId: cardIds[0],
371+
lastCardId: cardIds[3],
372+
})
361373
).toEqual(cardIds)
362374

363375
expect(
364-
collection.cardIdsBetweenByColRow(cardIds[3], cardIds[0])
376+
collection.cardIdsBetweenByColRow({
377+
firstCardId: cardIds[3],
378+
lastCardId: cardIds[0],
379+
})
365380
).toEqual(cardIds)
366381
})
367382
})

__tests__/ui/grid/FoamcoreGrid.unit.test.js

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import CardMoveService from '~/utils/CardMoveService'
55
import fakeApiStore from '#/mocks/fakeApiStore'
66
import fakeUiStore from '#/mocks/fakeUiStore'
77
import { fakeCollectionCard, fakeCollection, fakeItemCard } from '#/mocks/data'
8-
import v from '~/utils/variables'
98

109
// because of mdlPlaceholder... without this mock it blows up
1110
jest.mock('../../../app/javascript/stores/jsonApi/CollectionCard')
@@ -183,25 +182,10 @@ describe('FoamcoreGrid', () => {
183182
})
184183

185184
describe('coordinatesForPosition', () => {
186-
it('should calculate the appropriate coordinates', () => {
187-
const { gridW, gutter } = v.defaultGridSettings
188-
const zoom = component.relativeZoomLevel
189-
let x = (gridW + gutter) / zoom
190-
const y = 0
191-
let width = 1
192-
expect(component.coordinatesForPosition({ x, y, width })).toEqual({
193-
col: 1,
194-
outsideDraggableArea: false,
195-
row: 0,
196-
})
197-
x = (16 * (gridW + gutter)) / zoom
198-
width = 4
199-
expect(component.coordinatesForPosition({ x, y, width })).toEqual({
200-
// this will get bumped back to 12 (where it fits)
201-
col: 12,
202-
outsideDraggableArea: true,
203-
row: 0,
204-
})
185+
it('should call uiStore function', () => {
186+
const params = { x: 10, y: 20, width: 2 }
187+
component.coordinatesForPosition(params)
188+
expect(props.uiStore.coordinatesForPosition).toHaveBeenCalledWith(params)
205189
})
206190
})
207191

__tests__/ui/grid/GridCard.unit.test.js

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ describe('GridCard', () => {
3939
describe('as viewer', () => {
4040
beforeEach(() => {
4141
props.record.can_edit = false
42-
uiStore.setCardPosition = jest.fn()
4342
rerender()
4443
})
4544

@@ -78,16 +77,6 @@ describe('GridCard', () => {
7877
expect(wrapper.find('SelectionCircle').exists()).toBe(true)
7978
expect(wrapper.find('GridCardHotspot').exists()).toBe(false)
8079
})
81-
82-
it('sets the card ref and calls uiStore.setCardPosition', () => {
83-
const rect = {}
84-
const fakeRef = { getBoundingClientRect: () => rect }
85-
component.setCardRef(fakeRef)
86-
expect(uiStore.setCardPosition).toHaveBeenCalledWith(
87-
props.card.id,
88-
rect
89-
)
90-
})
9180
})
9281

9382
describe('as editor', () => {
@@ -308,8 +297,8 @@ describe('GridCard', () => {
308297

309298
describe('when selected', () => {
310299
beforeEach(() => {
311-
props.hoveringOver = false
312-
uiStore.selectCardId(props.card.id)
300+
// simulate getter function
301+
props.card.isSelected = true
313302
rerender()
314303
})
315304

@@ -417,6 +406,7 @@ describe('GridCard', () => {
417406
beforeEach(() => {
418407
uiStore.editingCardCover = null
419408
uiStore.selectedArea.minX = 10
409+
uiStore.selectedArea.maxX = 20
420410
rerender()
421411
})
422412

__tests__/ui/grid/MovableGridCard.unit.test.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ uiStore.apiStore = {
3333

3434
const rerender = () => {
3535
wrapper = shallow(<MovableGridCard {...props} />)
36+
component = wrapper.instance()
3637
}
3738

3839
describe('MovableGridCard', () => {
@@ -165,11 +166,6 @@ describe('MovableGridCard', () => {
165166
})
166167

167168
describe('handleDrag', () => {
168-
beforeEach(() => {
169-
rerender()
170-
component = wrapper.instance()
171-
})
172-
173169
it('should initiate uiStore.drag, but not call other drag functions until >10 px movement', () => {
174170
const pageX = 0
175171
const pageY = 10

__tests__/ui/pages/shared/EditableName.unit.test.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ describe('EditableName', () => {
2828
beforeEach(() => {
2929
props.fieldName = 'name'
3030
props.TypographyComponent = Heading2
31+
props.onDoneEditing.mockClear()
3132
wrapper = shallow(<EditableName.wrappedComponent {...props} canEdit />)
3233
const fakeEvent = {
3334
stopPropagation: jest.fn(),
@@ -51,15 +52,24 @@ describe('EditableName', () => {
5152
expect(props.updateNameHandler).toHaveBeenCalledWith('Stellar Collection')
5253
})
5354

54-
it('saves and returns to read-only name when enter is pressed in input', () => {
55+
it('saves and returns to read-only name when Enter is pressed in input', () => {
5556
expect(props.onDoneEditing).not.toHaveBeenCalled()
56-
wrapper.find('AutosizeInput').simulate('keyPress', {
57+
wrapper.find('AutosizeInput').simulate('keyDown', {
5758
key: 'Enter',
5859
})
5960
expect(props.uiStore.editingName).toEqual([])
6061
expect(props.onDoneEditing).toHaveBeenCalled()
6162
})
6263

64+
it('saves and returns to read-only name when Escape is pressed in input', () => {
65+
expect(props.onDoneEditing).not.toHaveBeenCalled()
66+
wrapper.find('AutosizeInput').simulate('keyDown', {
67+
key: 'Escape',
68+
})
69+
expect(props.uiStore.editingName).toEqual([])
70+
expect(props.onDoneEditing).toHaveBeenCalled()
71+
})
72+
6373
describe('with placeholder prop and empty name string', () => {
6474
beforeEach(() => {
6575
wrapper.setProps({

app/controllers/api/v1/collection_cards_controller.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ def check_valid_duplication
580580

581581
def create_notification(card, action)
582582
# Only notify for archiving of collections (and not link cards)
583-
return if card.link?
583+
return if card.link? || card.section?
584584

585585
from_id = @from_collection&.id
586586
to_id = @to_collection&.id
@@ -678,6 +678,7 @@ def collection_card_update_params
678678
:order,
679679
:hidden,
680680
:section_type,
681+
:section_name,
681682
:font_color,
682683
:font_background,
683684
:cover_card_id,

app/javascript/stores/UiStore.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import v, {
1212
FOAMCORE_INTERACTION_LAYER,
1313
ACTIVITY_LOG_PAGE_KEY,
1414
COLLECTION_CHANNEL_NAME,
15+
SECTION_BORDER,
1516
} from '~/utils/variables'
1617
import { POPUP_ACTION_TYPES } from '~/enums/actionEnums'
1718
import { calculatePopoutMenuOffset } from '~/utils/clickUtils'
@@ -401,11 +402,11 @@ export default class UiStore {
401402

402403
const { minX, minY, maxX, maxY } = selectedArea
403404
const rect = this.foamcoreBoundingRectangle
404-
const scrollTop = window.pageYOffset
405-
const scrollLeft = window.pageXOffset
405+
const scrollTop = window.pageYOffset || 0
406+
const scrollLeft = window.pageXOffset || 0
406407

407-
const top = rect.y + scrollTop
408-
const left = rect.x + scrollLeft
408+
const top = rect.top + scrollTop
409+
const left = rect.left + scrollLeft
409410

410411
const minRawCoords = {
411412
x: minX - left,
@@ -445,7 +446,6 @@ export default class UiStore {
445446
@action
446447
selectCardsWithinSelectedArea(minMaxCorners) {
447448
const { selectedCardIds, selectedAreaShifted, viewingCollection } = this
448-
// const viewingCardIds = viewingCollection.cardIds
449449
let newSelectedCardIds = []
450450

451451
if (minMaxCorners.minRow === null || minMaxCorners.minCol === null) {
@@ -472,6 +472,11 @@ export default class UiStore {
472472
this.editingName.push(nameKey)
473473
}
474474

475+
@action
476+
clearEditingName() {
477+
this.editingName = []
478+
}
479+
475480
@action
476481
performPopupAction(message, actionType) {
477482
switch (actionType) {
@@ -1954,13 +1959,12 @@ export default class UiStore {
19541959
}
19551960

19561961
if (isSection) {
1957-
// sections are positioned in (x,y) by half a card, and adjusted to be smaller by a full card amount
1958-
// TODO: sections should actually overlap the gutter so this should adjust slightly
1962+
// sections are positioned in (x,y) by half a card, and adjusted to be smaller by a full card amount.
19591963
_.assign(pos, {
19601964
x: (col * (gridW + gutter) + gridW / 2) / relativeZoomLevel,
19611965
y: (row * (gridH + gutter) + gridH / 2) / relativeZoomLevel,
1962-
w: (width - 1) * (gridW + gutter) - gutter,
1963-
h: (height - 1) * (gridH + gutter) - gutter,
1966+
w: (width - 1) * (gridW + gutter) + SECTION_BORDER,
1967+
h: (height - 1) * (gridH + gutter) + SECTION_BORDER,
19641968
})
19651969
}
19661970

app/javascript/stores/jsonApi/Collection.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,12 @@ class Collection extends SharedRecordMixin(BaseRecord) {
189189
return this.cardIdsBetweenByColRow({ firstCardId, lastCardId })
190190
}
191191
// For all other collection types, find cards by order
192-
return this.cardIdsBetweenByOrder({ firstCardId, lastCardId })
192+
return this.cardIdsBetweenByOrder(firstCardId, lastCardId)
193193
}
194194

195195
// Find all cards that are between these two card ids,
196196
// using the card order
197-
cardIdsBetweenByOrder({ firstCardId, lastCardId }) {
197+
cardIdsBetweenByOrder(firstCardId, lastCardId) {
198198
const firstIdx = this.cardIds.findIndex(id => id === firstCardId)
199199
const lastIdx = this.cardIds.findIndex(id => id === lastCardId)
200200
const cardIdsBetween = [...this.cardIds]
@@ -309,6 +309,7 @@ class Collection extends SharedRecordMixin(BaseRecord) {
309309
const matrix = this.cardMatrix
310310
const cardIds = []
311311
_.each(rowRange, row => {
312+
if (!matrix[row]) return
312313
_.each(colRange, col => {
313314
const card = matrix[row][col]
314315
if (card && !_.includes(cardIds, card.id)) cardIds.push(card.id)
@@ -2070,8 +2071,9 @@ class Collection extends SharedRecordMixin(BaseRecord) {
20702071
}
20712072

20722073
get styledTheme() {
2073-
const { fontColor } = this
2074+
const { fontColor, uiStore } = this
20742075
const theme = {
2076+
zoomLevel: uiStore.relativeZoomLevel,
20752077
// can probably deprecate this once we fully migrate 4WFC?
20762078
useResponsiveText: !this.isBoard,
20772079
}

0 commit comments

Comments
 (0)