Skip to content

Commit 9d6d7af

Browse files
committed
feat(data-browser): add optional row number column
1 parent 0e17e29 commit 9d6d7af

7 files changed

Lines changed: 175 additions & 67 deletions

File tree

src/components/BrowserRow/BrowserRow.react.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ export default class BrowserRow extends Component {
3333
row,
3434
rowValue,
3535
rowWidth,
36+
showRowNumber,
37+
rowNumberWidth,
38+
skip,
3639
selection,
3740
selectRow,
3841
setCopyableValue,
@@ -82,12 +85,12 @@ export default class BrowserRow extends Component {
8285
style={
8386
freezeIndex >= 0
8487
? {
85-
position: 'sticky',
86-
left: 0,
87-
zIndex: 1,
88-
background: rowBackground,
89-
borderBottom: '1px solid #e3e3ea',
90-
}
88+
position: 'sticky',
89+
left: 0,
90+
zIndex: 1,
91+
background: rowBackground,
92+
borderBottom: '1px solid #e3e3ea',
93+
}
9194
: {}
9295
}
9396
>
@@ -98,6 +101,25 @@ export default class BrowserRow extends Component {
98101
onMouseDown={e => onMouseDownRowCheckBox(e.target.checked)}
99102
/>
100103
</span>
104+
{showRowNumber && (
105+
<span
106+
className={styles.rowNumberCell}
107+
style={
108+
freezeIndex >= 0
109+
? {
110+
position: 'sticky',
111+
left: 30,
112+
zIndex: 1,
113+
background: rowBackground,
114+
borderBottom: '1px solid #e3e3ea',
115+
width: rowNumberWidth,
116+
}
117+
: { width: rowNumberWidth }
118+
}
119+
>
120+
{row >= 0 ? (skip + row + 1).toLocaleString() : ''}
121+
</span>
122+
)}
101123
{order.map(({ name, width, visible }, j) => {
102124
if (!visible) {
103125
return null;

src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.react.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,23 @@ import { DndProvider } from 'react-dnd';
1515
export default class DataBrowserHeaderBar extends React.Component {
1616
handleContextMenu = (index, event) => {
1717
event.preventDefault();
18-
const { freezeIndex, freezeColumns, unfreezeColumns, setContextMenu } = this.props;
19-
const items =
18+
const {
19+
freezeIndex,
20+
freezeColumns,
21+
unfreezeColumns,
22+
setContextMenu,
23+
showRowNumber,
24+
setShowRowNumber,
25+
} = this.props;
26+
const items = [
27+
{
28+
text: showRowNumber ? 'Hide row number' : 'Display row number',
29+
callback: () => setShowRowNumber(!showRowNumber),
30+
},
2031
freezeIndex >= 0 && index <= freezeIndex
21-
? [{ text: 'Unfreeze column', callback: () => unfreezeColumns() }]
22-
: [{ text: 'Freeze column', callback: () => freezeColumns(index) }];
32+
? { text: 'Unfreeze column', callback: () => unfreezeColumns() }
33+
: { text: 'Freeze column', callback: () => freezeColumns(index) },
34+
];
2335
setContextMenu(event.pageX, event.pageY, items);
2436
};
2537

@@ -39,6 +51,8 @@ export default class DataBrowserHeaderBar extends React.Component {
3951
stickyLefts,
4052
handleLefts,
4153
freezeIndex,
54+
showRowNumber,
55+
rowNumberWidth,
4256
} = this.props;
4357
const elements = [
4458
<div
@@ -52,6 +66,22 @@ export default class DataBrowserHeaderBar extends React.Component {
5266
</div>,
5367
];
5468

69+
if (showRowNumber) {
70+
elements.push(
71+
<div
72+
key="rowNumber"
73+
className={[styles.wrap, styles.rowNumber].join(' ')}
74+
style={
75+
freezeIndex >= 0
76+
? { position: 'sticky', left: 30, zIndex: 11, width: rowNumberWidth }
77+
: { width: rowNumberWidth }
78+
}
79+
>
80+
#
81+
</div>
82+
);
83+
}
84+
5585
headers.forEach(({ width, name, type, targetClass, order, visible, preventSort }, i) => {
5686
if (!visible) {
5787
return;

src/components/DataBrowserHeaderBar/DataBrowserHeaderBar.scss

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
display: inline-block;
1919
min-width: 100%;
2020
// to resolve rendering issue with retina displays
21-
-webkit-transform: translate3d(0,0,0);
21+
-webkit-transform: translate3d(0, 0, 0);
2222
}
2323

2424
.wrap {
@@ -53,7 +53,18 @@
5353
vertical-align: top;
5454
text-align: center;
5555
width: 30px;
56-
background: rgb(114, 111, 133)
56+
background: rgb(114, 111, 133);
57+
}
58+
59+
.rowNumber {
60+
line-height: 30px;
61+
height: 30px;
62+
vertical-align: top;
63+
text-align: right;
64+
background: rgb(114, 111, 133);
65+
border-right: 1px solid #e3e3ea;
66+
padding: 0 4px;
67+
box-sizing: border-box;
5768
}
5869

5970
.handle {
@@ -90,20 +101,19 @@
90101
border-top: 1px solid #e3e3ea;
91102
border-bottom: 1px solid #e3e3ea;
92103
height: 30px;
93-
width:100%;
104+
width: 100%;
94105
vertical-align: middle;
95106
padding-left: 2px;
96107
margin-top: 30px;
97108
line-height: 31px;
98109
animation: skeleton-loading 1s linear infinite alternate;
99110
}
100-
111+
101112
@keyframes skeleton-loading {
102113
0% {
103-
background-color:#ffffff;
114+
background-color: #ffffff;
104115
}
105116
100% {
106117
background-color: #e3e3ea;
107-
108118
}
109119
}

src/dashboard/Data/Browser/Browser.react.js

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ class Browser extends DashboardView {
661661
}
662662
obj.save(null, { useMasterKey }).then(
663663
objectSaved => {
664-
const msg = objectSaved.className + ' with id \'' + objectSaved.id + '\' created';
664+
const msg = objectSaved.className + " with id '" + objectSaved.id + "' created";
665665
this.showNote(msg, false);
666666

667667
const state = { data: this.state.data };
@@ -764,7 +764,7 @@ class Browser extends DashboardView {
764764

765765
obj.save(null, { useMasterKey: true }).then(
766766
objectSaved => {
767-
const msg = objectSaved.className + ' with id \'' + objectSaved.id + '\' ' + 'created';
767+
const msg = objectSaved.className + " with id '" + objectSaved.id + "' " + 'created';
768768
this.showNote(msg, false);
769769

770770
const state = {
@@ -908,7 +908,7 @@ class Browser extends DashboardView {
908908
const { useMasterKey, skip, limit } = this.state;
909909
this.setState({
910910
data: null,
911-
})
911+
});
912912
const query = await queryFromFilters(source, filters);
913913
const sortDir = this.state.ordering[0] === '-' ? '-' : '+';
914914
const field = this.state.ordering.substr(sortDir === '-' ? 1 : 0);
@@ -1270,7 +1270,7 @@ class Browser extends DashboardView {
12701270
const { useMasterKey } = this.state;
12711271
obj.save(null, { useMasterKey }).then(
12721272
objectSaved => {
1273-
const msg = objectSaved.className + ' with id \'' + objectSaved.id + '\' updated';
1273+
const msg = objectSaved.className + " with id '" + objectSaved.id + "' updated";
12741274
this.showNote(msg, false);
12751275

12761276
const state = {
@@ -1398,7 +1398,7 @@ class Browser extends DashboardView {
13981398
let deletedNote;
13991399

14001400
if (toDeleteObjectIds.length == 1) {
1401-
deletedNote = className + ' with id \'' + toDeleteObjectIds[0] + '\' deleted';
1401+
deletedNote = className + " with id '" + toDeleteObjectIds[0] + "' deleted";
14021402
} else {
14031403
deletedNote = toDeleteObjectIds.length + ' ' + className + ' objects deleted';
14041404
}
@@ -1426,7 +1426,7 @@ class Browser extends DashboardView {
14261426
if (error.code === Parse.Error.AGGREGATE_ERROR) {
14271427
if (error.errors.length == 1) {
14281428
errorDeletingNote =
1429-
'Error deleting ' + className + ' with id \'' + error.errors[0].object.id + '\'';
1429+
'Error deleting ' + className + " with id '" + error.errors[0].object.id + "'";
14301430
} else if (error.errors.length < toDeleteObjectIds.length) {
14311431
errorDeletingNote =
14321432
'Error deleting ' +
@@ -1443,7 +1443,7 @@ class Browser extends DashboardView {
14431443
} else {
14441444
if (toDeleteObjectIds.length == 1) {
14451445
errorDeletingNote =
1446-
'Error deleting ' + className + ' with id \'' + toDeleteObjectIds[0] + '\'';
1446+
'Error deleting ' + className + " with id '" + toDeleteObjectIds[0] + "'";
14471447
} else {
14481448
errorDeletingNote =
14491449
'Error deleting ' + toDeleteObjectIds.length + ' ' + className + ' objects';
@@ -1598,13 +1598,15 @@ class Browser extends DashboardView {
15981598
script.cloudCodeFunction,
15991599
{ object: object.toPointer() },
16001600
{ useMasterKey: true }
1601-
).then(response => ({
1602-
objectId: object.id,
1603-
response,
1604-
})).catch(error => ({
1605-
objectId: object.id,
1606-
error,
1607-
}))
1601+
)
1602+
.then(response => ({
1603+
objectId: object.id,
1604+
response,
1605+
}))
1606+
.catch(error => ({
1607+
objectId: object.id,
1608+
error,
1609+
}))
16081610
);
16091611

16101612
const results = await Promise.all(promises);
@@ -1631,12 +1633,18 @@ class Browser extends DashboardView {
16311633
totalErrorCount += batchErrorCount;
16321634

16331635
if (objects.length > 1) {
1634-
this.showNote(`Ran script "${script.title}" on ${batch.length} objects in batch ${batchCount}/${totalBatchCount} with ${batchErrorCount} errors.`, batchErrorCount > 0);
1636+
this.showNote(
1637+
`Ran script "${script.title}" on ${batch.length} objects in batch ${batchCount}/${totalBatchCount} with ${batchErrorCount} errors.`,
1638+
batchErrorCount > 0
1639+
);
16351640
}
16361641
}
16371642

16381643
if (objects.length > 1) {
1639-
this.showNote(`Ran script "${script.title}" on ${objects.length} objects in ${batchCount} batches with ${totalErrorCount} errors.`, totalErrorCount > 0);
1644+
this.showNote(
1645+
`Ran script "${script.title}" on ${objects.length} objects in ${batchCount} batches with ${totalErrorCount} errors.`,
1646+
totalErrorCount > 0
1647+
);
16401648
}
16411649
this.refresh();
16421650
} catch (e) {
@@ -1957,7 +1965,7 @@ class Browser extends DashboardView {
19571965
}}
19581966
removeFilter={filter => {
19591967
this.resetPage();
1960-
this.removeFilter(filter)
1968+
this.removeFilter(filter);
19611969
}}
19621970
classClicked={() => {
19631971
this.resetPage();
@@ -1978,7 +1986,7 @@ class Browser extends DashboardView {
19781986
// Scroll to top
19791987
window.scrollTo({
19801988
top: 0,
1981-
behavior: 'smooth'
1989+
behavior: 'smooth',
19821990
});
19831991

19841992
// Reset pagination to page 1
@@ -2201,6 +2209,7 @@ class Browser extends DashboardView {
22012209
errorAggregatedData={this.state.errorAggregatedData}
22022210
appName={this.props.params.appId}
22032211
limit={this.state.limit}
2212+
skip={this.state.skip}
22042213
/>
22052214
<BrowserFooter
22062215
skip={this.state.skip}

0 commit comments

Comments
 (0)