Skip to content

Commit

Permalink
Added in all link bubbles code
Browse files Browse the repository at this point in the history
  • Loading branch information
jvorob committed Sep 23, 2023
1 parent 1b1970c commit 20874a2
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 2 deletions.
117 changes: 117 additions & 0 deletions app/client/components/buildViewSectionDom.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import BaseView from 'app/client/components/BaseView';
import {allCommands} from "app/client/components/commands";
import {GristDoc} from 'app/client/components/GristDoc';
import {makeT} from 'app/client/lib/localization';
import {ViewRec, ViewSectionRec} from 'app/client/models/DocModel';
Expand All @@ -13,6 +14,7 @@ import {menu} from 'app/client/ui2018/menus';
import {getWidgetTypes} from "app/client/ui/widgetTypesMap";
import {Computed, dom, DomElementArg, Observable, styled} from 'grainjs';
import {defaultMenuOptions} from 'popweasel';
import {EmptyFilterState} from "./LinkingState";

const t = makeT('ViewSection');

Expand Down Expand Up @@ -54,6 +56,118 @@ export function buildCollapsedSectionDom(options: {
}


function buildLinkStateIndicatorDom(options: {
gristDoc: GristDoc,
sectionRowId: number,
}, ...domArgs: DomElementArg[]) {
const {gristDoc, sectionRowId} = options;
const tgtSec = gristDoc.docModel.viewSections.getRowModel(sectionRowId);

return dom.domComputed((use) => {
//makes an observable for the passed-in section
const lstate = use(tgtSec.linkingState);
if(lstate == null) { return null; }

// Default to empty for ease of coding, will be set in cases where it's relevant
const lfilter = lstate.filterState ? use(lstate.filterState): EmptyFilterState;

// crunch filterVals into compact string for display in bubble (not tooltip),
// eg "USA", "USA;2022", "(USA +3 others)"
// only for filter linking and summary-filter-linking

//filters is a map {column: [vals...]}
// if multiple filters, join each with ";"
// each filter can have multiple vals (if reflist), show as "(SomeValue +3 others)",

const filterValsShortLabel = Object.keys(lfilter.filterLabels).map(colId => {
const vals = lfilter.filterLabels[colId];
//selector can be an empty reflist (filterLabels[colId] = [])
if(vals.length == 0)
{ return '- blank -'; }

// Even if vals != [], selector might be a null/empty cell value.
// - if a null reference: filter[colId] = [0], but filterLabels would be ['']
// - if an empty string/choice filter = [''], label = ['']
// - if an empty number/date/etc: filter[colId] = [null], but filterLabel will be ['']
//Note: numeric 0 won't become blank, since filterLabel will be "0", which is truthy
const dispVal = vals[0] || '- blank -';

//If 2 or more vals, abbreviate it
return vals.length <= 1 ? dispVal: `(${dispVal} +${vals.length - 1} others)`;
//TODO: could show multiple vals if short, and/or let css overflow ellipsis handle it?
}).join("; ");

let bubbleContent: DomElementArg[];
switch (use(lstate.linkTypeDescription)) {
case "Filter:Summary-Group":
case "Filter:Col->Col":
case "Filter:Row->Col":
case "Summary":
bubbleContent = [
dom("div", dom.style('width', '2px'), dom.style('display', 'inline-block')), //spacer for text
filterValsShortLabel,
];
break;
case "Show-Referenced-Records":
bubbleContent = [];
break;
case "Cursor:Same-Table":
case "Cursor:Reference":
bubbleContent = [];
break;
case "Error:Invalid":
default:
bubbleContent = ["Error"];
break;
}

return linkStateBubble(
customIcon(dom.style("background-color", theme.filterBarButtonSavedFg + "")),
bubbleContent,
dom.on("click", () => allCommands.dataSelectionTabOpen.run()),
...domArgs,
);

});

}

// eslint-disable-next-line
const tempIconSVGString= `url('data:image/svg+xml;utf8,<svg width="16px" height="16px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> <ellipse style="stroke: rgb(0, 0, 0);" cx="2.426" cy="13.913" rx="1.361" ry="1.361"/> <ellipse style="stroke: rgb(0, 0, 0);" cx="13.827" cy="3.039" rx="1.222" ry="1.222"/> <path style="stroke: rgb(0, 0, 0); fill: none;" d="M 2.396 12.802 C 2.363 7.985 6.014 2.893 11.895 3.027"/> <path style="stroke: rgb(0, 0, 0); fill: none;" d="M 8.49 1.047 L 12.265 2.871 L 8.986 5.874"/> </svg>')`;

//TODO JV TEMP: Shamelessly copied from icon.ts
const customIcon = styled('div', `
-webkit-mask-image: ${tempIconSVGString};
position: relative;
display: inline-block;
vertical-align: middle;
-webkit-mask-repeat: no-repeat;
-webkit-mask-position: center;
-webkit-mask-size: contain;
width: 16px;
height: 16px;
background-color: var(--icon-color, var(--grist-theme-text, black));
`);

const linkStateBubble = styled('div', `
cursor: pointer;
overflow: hidden;
border-radius: 3px;
padding: 3px;
text-overflow: ellipsis;
align-self: start;
height: 21px;
margin-top: -4px;
margin-left: 4px;
color: ${theme.filterBarButtonSavedFg};
background-color: ${theme.filterBarButtonSavedBg};
&:hover {
background-color: ${theme.filterBarButtonSavedHoverBg};
}
`);


export function buildViewSectionDom(options: {
gristDoc: GristDoc,
sectionRowId: number,
Expand Down Expand Up @@ -93,6 +207,9 @@ export function buildViewSectionDom(options: {
dom.maybe((use) => use(use(viewInstance.viewSection.table).summarySourceTable), () =>
cssSigmaIcon('Pivot', testId('sigma'))),
buildWidgetTitle(vs, options, testId('viewsection-title'), cssTestClick(testId("viewsection-blank"))),
dom.maybe((use) => use(vs.linkSrcSectionRef) != 0, () =>
buildLinkStateIndicatorDom({gristDoc, sectionRowId}, testId("viewsection-linkstate"))),
dom("div", dom.style("flex", "1 0 0px")), //spacer, 0 size by default, grows to take up remaining space
viewInstance.buildTitleControls(),
dom('div.viewsection_buttons',
dom.create(viewSectionMenu, gristDoc, vs)
Expand Down
2 changes: 1 addition & 1 deletion app/client/ui/WidgetTitle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ const updateOnKey = {onInput: true};

// Leave class for tests.
const cssTitleContainer = styled('div', `
flex: 1 1 0px;
flex: 0 1 auto; /* won't grow, starts at size of content, will shrink if needed */
min-width: 0px;
display: flex;
.info_toggle_icon {
Expand Down
2 changes: 1 addition & 1 deletion test/nbrowser/Views.ntest.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('Views.ntest', function() {
// Check that viewsection titles are correct and editable
var recordTitle = recordSection.find('.test-viewsection-title');
assert.equal(await recordTitle.text(), 'TABLE1');
await recordTitle.click();
await recordSection.find('.test-viewsection-blank').click(); //switch to recordSection without opening title widget
await gu.renameActiveSection('foo');
assert.equal(await recordTitle.text(), 'foo');

Expand Down

0 comments on commit 20874a2

Please sign in to comment.