@@ -3,9 +3,10 @@ import React from 'react'
3
3
import Spinner from 'part:@sanity/components/loading/spinner'
4
4
import styles from './styles/DocumentsPane.css'
5
5
import { StateLink , IntentLink , withRouterHOC } from 'part:@sanity/base/router'
6
- import { Item } from 'part:@sanity/components/lists/default'
6
+ import SortIcon from 'part:@sanity/base/sort-icon'
7
+
7
8
import ListView from './ListView'
8
- import { partition } from 'lodash'
9
+ import { partition , uniqBy } from 'lodash'
9
10
import VisibilityOffIcon from 'part:@sanity/base/visibility-off-icon'
10
11
import EditIcon from 'part:@sanity/base/edit-icon'
11
12
import QueryContainer from 'part:@sanity/base/query-container'
@@ -21,18 +22,43 @@ import Snackbar from 'part:@sanity/components/snackbar/default'
21
22
22
23
const NOOP = ( ) => { } // eslint-disable-line
23
24
24
- function readListLayoutSettings ( ) {
25
- return JSON . parse ( window . localStorage . getItem ( 'desk-tool.listlayout-settings' ) || '{}' )
25
+ const LOCALSTORAGE_KEY = 'desk-tool.documents-pane-settings'
26
+
27
+ function readSettings ( ) {
28
+ return JSON . parse ( window . localStorage . getItem ( LOCALSTORAGE_KEY ) || '{}' )
26
29
}
27
30
28
- function writeListLayoutSettings ( settings ) {
29
- window . localStorage . setItem ( 'desk-tool.listlayout-settings' , JSON . stringify ( settings ) )
31
+ function writeSettings ( settings ) {
32
+ window . localStorage . setItem ( LOCALSTORAGE_KEY , JSON . stringify ( settings ) )
30
33
}
31
34
32
35
function getDocumentKey ( document ) {
33
36
return getPublishedId ( document . _id )
34
37
}
35
38
39
+ function toGradientOrderClause ( orderBy ) {
40
+ return orderBy . map (
41
+ ordering => [ ordering . field , ordering . direction ]
42
+ . filter ( Boolean )
43
+ . join ( ' ' )
44
+ ) . join ( ', ' )
45
+ }
46
+
47
+ const ORDER_BY_UPDATED_AT = {
48
+ title : 'Last edited' ,
49
+ name : 'updatedAt' ,
50
+ by : [ { field : '_updatedAt' , direction : 'desc' } ]
51
+ }
52
+
53
+ const ORDER_BY_CREATED_AT = {
54
+ title : 'Created' ,
55
+ name : 'createdAt' ,
56
+ by : [ { field : '_createdAt' , direction : 'desc' } ]
57
+ }
58
+
59
+ const DEFAULT_SELECTED_ORDERING_OPTION = ORDER_BY_UPDATED_AT
60
+ const DEFAULT_ORDERING_OPTIONS = [ ORDER_BY_UPDATED_AT , ORDER_BY_CREATED_AT ]
61
+
36
62
function removePublishedWithDrafts ( documents ) {
37
63
38
64
const [ draftIds , publishedIds ] = partition ( documents . map ( doc => doc . _id ) , isDraftId )
@@ -50,57 +76,61 @@ function removePublishedWithDrafts(documents) {
50
76
. filter ( doc => ! ( isPublishedId ( doc . _id ) && doc . hasDraft ) )
51
77
}
52
78
79
+ function writeSettingsForType ( type , settings ) {
80
+ writeSettings ( Object . assign ( readSettings ( ) , {
81
+ [ type ] : settings
82
+ } ) )
83
+ }
84
+
53
85
export default withRouterHOC ( class DocumentsPane extends React . PureComponent {
54
86
static propTypes = {
55
87
selectedType : PropTypes . string ,
56
88
selectedDocumentId : PropTypes . string ,
57
89
schemaType : PropTypes . object ,
58
90
isCollapsed : PropTypes . bool ,
59
- router : PropTypes . shape ( {
60
- state : PropTypes . shape ( {
61
- selectType : PropTypes . string ,
62
- selectedType : PropTypes . string
63
- } )
64
- } )
91
+ router : PropTypes . object
65
92
}
66
93
67
94
static defaultProps = {
68
95
loading : false ,
69
96
isCollapsed : false ,
70
97
published : [ ] ,
71
98
drafts : [ ] ,
72
- onSetSorting : NOOP ,
73
99
onSetListLayout : NOOP
74
100
}
75
101
76
- state = {
77
- listLayoutSettings : readListLayoutSettings ( ) ,
78
- sorting : '_updatedAt desc' ,
79
- menuIsOpen : false
80
- }
81
-
82
- static contextTypes = {
83
- __internalRouter : PropTypes . object
102
+ handleSetListLayout = listLayout => {
103
+ this . setState ( prevState => ( {
104
+ settings : {
105
+ ...prevState . settings ,
106
+ listLayout : listLayout . key
107
+ }
108
+ } ) , this . writeSettings )
84
109
}
85
110
86
-
87
- handleSetListLayout = listLayout => {
88
- const { selectedType} = this . props . router . state
89
- const nextSettings = Object . assign ( readListLayoutSettings ( ) , {
90
- [ selectedType ] : listLayout
91
- } )
92
- writeListLayoutSettings ( nextSettings )
93
- this . setState ( { listLayoutSettings : nextSettings } )
111
+ constructor ( props ) {
112
+ super ( )
113
+ const settings = readSettings ( )
114
+ this . state = {
115
+ settings : ( settings && settings [ props . selectedType ] ) || {
116
+ listLayout : 'default' ,
117
+ ordering : DEFAULT_SELECTED_ORDERING_OPTION
118
+ } ,
119
+ menuIsOpen : false
120
+ }
94
121
}
95
122
96
- getListLayoutForType ( typeName ) {
97
- return this . state . listLayoutSettings [ typeName ] || 'default'
123
+ handleSetOrdering = ordering => {
124
+ this . setState ( prevState => ( {
125
+ settings : {
126
+ ...prevState . settings ,
127
+ ordering : ordering . name
128
+ }
129
+ } ) , this . writeSettings )
98
130
}
99
131
100
- handleSetSorting = sorting => {
101
- this . setState ( {
102
- sorting : sorting
103
- } )
132
+ writeSettings ( ) {
133
+ writeSettingsForType ( this . props . selectedType , this . state . settings )
104
134
}
105
135
106
136
handleToggleMenu = ( ) => {
@@ -115,31 +145,52 @@ export default withRouterHOC(class DocumentsPane extends React.PureComponent {
115
145
} )
116
146
}
117
147
118
- handleGoToCreateNew = ( ) => {
119
- const { selectedType} = this . props
148
+ getOrderingOptions ( selectedType ) {
120
149
const type = schema . get ( selectedType )
121
- const url = this . context . __internalRouter . resolveIntentLink ( 'create' , {
122
- type : type . name
123
- } )
124
- this . context . __internalRouter . navigateUrl ( url )
150
+
151
+ const optionsWithDefaults = type . orderings
152
+ ? type . orderings . concat ( DEFAULT_ORDERING_OPTIONS )
153
+ : DEFAULT_ORDERING_OPTIONS
154
+
155
+ return uniqBy ( optionsWithDefaults , 'name' )
156
+ . map ( option => {
157
+ return {
158
+ ...option ,
159
+ icon : option . icon || SortIcon ,
160
+ title : < span > Sort by < b > { option . title } </ b > </ span >
161
+ }
162
+ } )
163
+ }
164
+
165
+ handleGoToCreateNew = ( ) => {
166
+ const { selectedType, router} = this . props
167
+ router . navigateIntent ( 'create' , { type : selectedType } )
125
168
}
126
169
127
170
renderDocumentsPaneMenu = ( ) => {
171
+ const { selectedType} = this . props
172
+ const type = schema . get ( selectedType )
128
173
return (
129
174
< DocumentsPaneMenu
130
175
onSetListLayout = { this . handleSetListLayout }
131
- onSetSorting = { this . handleSetSorting }
176
+ onSetOrdering = { this . handleSetOrdering }
132
177
onGoToCreateNew = { this . handleGoToCreateNew }
133
178
onMenuClose = { this . handleCloseMenu }
134
179
onClickOutside = { this . handleCloseMenu }
135
180
isOpen = { this . state . menuIsOpen }
181
+ orderingOptions = { this . getOrderingOptions ( selectedType ) }
182
+ type = { type }
136
183
/>
137
184
)
138
185
}
139
186
140
187
renderDocumentPaneItem = ( item , index , options = { } ) => {
141
188
const { selectedType, selectedDocumentId} = this . props
142
- const listLayout = this . getListLayoutForType ( selectedType )
189
+ const { settings} = this . state
190
+
191
+ const ordering = this . getOrderingOptions ( selectedType )
192
+ . find ( option => option . name === settings . ordering )
193
+
143
194
const type = schema . get ( selectedType )
144
195
const linkState = {
145
196
selectedDocumentId : getPublishedId ( item . _id ) ,
@@ -158,7 +209,8 @@ export default withRouterHOC(class DocumentsPane extends React.PureComponent {
158
209
< div className = { isSelected ? styles . selectedItem : styles . item } >
159
210
< Preview
160
211
value = { item }
161
- layout = { listLayout }
212
+ ordering = { ordering }
213
+ layout = { settings . listLayout }
162
214
type = { type }
163
215
/>
164
216
< div className = { styles . itemStatus } >
@@ -194,16 +246,17 @@ export default withRouterHOC(class DocumentsPane extends React.PureComponent {
194
246
195
247
render ( ) {
196
248
const {
197
- router,
198
249
selectedDocumentId,
199
250
schemaType,
200
251
isCollapsed
201
252
} = this . props
202
253
254
+ const { settings} = this . state
255
+ const currentOrderingOption = this . getOrderingOptions ( schemaType . name )
256
+ . find ( option => option . name === settings . ordering ) || DEFAULT_SELECTED_ORDERING_OPTION
203
257
204
258
const params = { type : schemaType . name , draftsPath : `${ DRAFTS_FOLDER } .**` }
205
- const query = `*[_type == $type] | order(${ this . state . sorting } ) [0...10000] {_id, _type}`
206
-
259
+ const query = `*[_type == $type] | order(${ toGradientOrderClause ( currentOrderingOption . by ) } ) [0...10000] {_id, _type}`
207
260
return (
208
261
< Pane
209
262
{ ...this . props }
@@ -218,9 +271,9 @@ export default withRouterHOC(class DocumentsPane extends React.PureComponent {
218
271
params = { params }
219
272
type = { schemaType }
220
273
selectedId = { selectedDocumentId }
221
- listLayout = { this . getListLayoutForType ( schemaType . name ) }
274
+ settings = { settings }
222
275
>
223
- { ( { result, loading, error, onRetry, type, listLayout } ) => {
276
+ { ( { result, loading, error, onRetry, type} ) => {
224
277
if ( error ) {
225
278
return (
226
279
< Snackbar
@@ -264,7 +317,7 @@ export default withRouterHOC(class DocumentsPane extends React.PureComponent {
264
317
items = { items }
265
318
getItemKey = { getDocumentKey }
266
319
renderItem = { this . renderDocumentPaneItem }
267
- listLayout = { listLayout }
320
+ listLayout = { settings . listLayout }
268
321
/>
269
322
) }
270
323
0 commit comments