Skip to content

Commit b4953db

Browse files
committed
(ui) add a "new record" button at the bottom of grid and detail views
very beginning wip: - there are no tests - the show/hide condition certainly needs refinement - clicking behavior certainly needs refinement But: something works!
1 parent 573c0b6 commit b4953db

File tree

6 files changed

+66
-1
lines changed

6 files changed

+66
-1
lines changed

app/client/components/buildViewSectionDom.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {menu} from 'app/client/ui2018/menus';
1313
import {getWidgetTypes} from "app/client/ui/widgetTypesMap";
1414
import {Computed, dom, DomElementArg, Observable, styled} from 'grainjs';
1515
import {defaultMenuOptions} from 'popweasel';
16+
import {newRecordButton} from 'app/client/ui/NewRecordButton';
1617

1718
const t = makeT('ViewSection');
1819

@@ -129,7 +130,12 @@ export function buildViewSectionDom(options: {
129130
dom('div.viewsection_truncated', t('Not all data is shown'))
130131
),
131132
dom.cls((use) => 'viewsection_type_' + use(vs.parentKey)),
132-
viewInstance.viewPane
133+
viewInstance.viewPane,
134+
dom.domComputed(use =>
135+
(use(viewInstance.viewSection.hasFocus) && use(viewInstance.enableAddRow)),
136+
(showNewRecordButton) =>
137+
showNewRecordButton ? newRecordButton(viewInstance) : null
138+
)
133139
),
134140
dom.maybe(use => !use(isNarrowScreenObs()), () => viewInstance.selectionSummary?.buildDom()),
135141
]),

app/client/declarations.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ declare module "app/client/components/BaseView" {
6363
public tableModel: DataTableModel;
6464
public selectionSummary?: SelectionSummary;
6565
public currentEditingColumnIndex: ko.Observable<number>;
66+
public enableAddRow: ko.Computed<boolean>;
6667

6768
constructor(gristDoc: GristDoc, viewSectionModel: any, options?: {addNewRow?: boolean, isPreview?: boolean});
6869
public setCursorPos(cursorPos: CursorPos): void;
@@ -79,6 +80,7 @@ declare module "app/client/components/BaseView" {
7980
public getAnchorLinkForSection(sectionId: number): IGristUrlState;
8081
public viewSelectedRecordAsCard(): void;
8182
public isRecordCardDisabled(): boolean;
83+
public insertRow(index?: number): Promise<any> | undefined | null;
8284
}
8385
export = BaseView;
8486
}

app/client/ui/NewRecordButton.ts

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {dom, styled} from 'grainjs';
2+
import {testId, vars} from 'app/client/ui2018/cssVars';
3+
import {makeT} from 'app/client/lib/localization';
4+
import {primaryButton} from 'app/client/ui2018/buttons';
5+
import {iconSpan} from 'app/client/ui2018/icons';
6+
import BaseView from 'app/client/components/BaseView';
7+
8+
const t = makeT('NewRecordButton');
9+
10+
const translationStrings = {
11+
'record': 'New record',
12+
'single': 'New card',
13+
};
14+
15+
/**
16+
* "New Record" button for the given view that inserts a new record at the end on click.
17+
*
18+
* Appears in the bottom-left corner of its parent element.
19+
*/
20+
export function newRecordButton(view: BaseView) {
21+
const viewType = view.viewSection.parentKey.peek();
22+
23+
const translationString = translationStrings[viewType as keyof typeof translationStrings]
24+
|| 'New record';
25+
return cssNewRecordButton(
26+
iconSpan('Plus'),
27+
dom('span', t(translationString)),
28+
dom.on('click', () => view.insertRow()),
29+
testId('new-record-button'),
30+
testId(`new-record-button-${view.constructor.name}`),
31+
);
32+
}
33+
34+
const cssNewRecordButton = styled(primaryButton, `
35+
position: absolute;
36+
bottom: -12px;
37+
left: -12px;
38+
z-index: ${vars.newRecordButtonZIndex};
39+
display: flex;
40+
align-items: center;
41+
gap: 6px;
42+
43+
/* 16px on the plus icon is blurry, 17px is sharp, needs more test. */
44+
& > span:first-child {
45+
width: 17px;
46+
height: 17px;
47+
}
48+
`);

app/client/ui2018/cssVars.ts

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ export const vars = {
136136
stickyHeaderZIndex: new CustomProp('sticky-header-z-index', '20'),
137137
insertColumnLineZIndex: new CustomProp('insert-column-line-z-index', '20'),
138138
emojiPickerZIndex: new CustomProp('modal-z-index', '20'),
139+
newRecordButtonZIndex: new CustomProp('new-record-button-z-index', '30'),
139140
popupSectionBackdropZIndex: new CustomProp('popup-section-backdrop-z-index', '100'),
140141
menuZIndex: new CustomProp('menu-z-index', '999'),
141142
modalZIndex: new CustomProp('modal-z-index', '999'),

static/locales/en.client.json

+4
Original file line numberDiff line numberDiff line change
@@ -1886,5 +1886,9 @@
18861886
"Name": "Name",
18871887
"Rename and set icon": "Rename and set icon",
18881888
"Reset icon": "Reset icon"
1889+
},
1890+
"NewRecordButton": {
1891+
"New card": "New card",
1892+
"New record": "New record"
18891893
}
18901894
}

static/locales/fr.client.json

+4
Original file line numberDiff line numberDiff line change
@@ -1836,5 +1836,9 @@
18361836
"Contact us": "Nous contacter",
18371837
"Only site owners may access audit logs.": "Seuls les propriétaires de site peuvent accéder aux journaux d'audit.",
18381838
"upgrade your plan": "actualiser son contrat"
1839+
},
1840+
"NewRecordButton": {
1841+
"New card": "Nouvelle fiche",
1842+
"New record": "Nouvelle ligne"
18391843
}
18401844
}

0 commit comments

Comments
 (0)