Skip to content
This repository has been archived by the owner on Nov 30, 2022. It is now read-only.

Commit

Permalink
Adding filterbox to selections in topbar (#77)
Browse files Browse the repository at this point in the history
Still work in progress, should not be merged. Styling and tweeks should be added, and also the feature to remove a single selection.

Refactoring Field and Filterbox to use in TableField and SelectionField components.

Closes #54 
Closes #68
  • Loading branch information
Helene Rignér committed Nov 5, 2018
1 parent 77df1a8 commit 780000f
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 205 deletions.
166 changes: 24 additions & 142 deletions src/components/field.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';

import Filterbox from './filterbox';
import useModel from './use/model';
import useLayout from './use/layout';

import './field.pcss';

function fieldCounts(dimInfo, field) {
Expand All @@ -24,170 +20,56 @@ function fieldCounts(dimInfo, field) {
return str;
}

function firstFewValues(layout) {
const rowToText = row => `${row[0].qText || '<empty>'}`;

const selected = layout.qListObject.qDataPages[0].qMatrix.filter(row => row[0].qState === 'S' || row[0].qState === 'O');
const excluded = layout.qListObject.qDataPages[0].qMatrix.filter(row => row[0].qState === 'X');

let result = '';
if (selected.length > 0) {
result += `Example values:\n${selected.map(rowToText).join(', ')}\n`;
}
if (excluded.length > 0) {
result += `\nExample of excluded values:\n${excluded.map(rowToText).join(', ')}`;
}

return result;
}

export function FieldWithoutState({
field, fieldData, layout, showFilterbox, model,
export default function Field({
layout, field, fieldData, onClearSelection,
}) {
let classes = `field ${fieldData.qKeyType}`;

if (!layout) {
return (
<div
className={classes}
>
<div className="name">
{field}
</div>
</div>
);
return null;
}

const total = layout.qListObject.qDimensionInfo.qCardinal;
const states = layout.qListObject.qDimensionInfo.qStateCounts;
const green = { width: `${Math.ceil((states.qSelected / total) * 100)}%` };
const grey = { width: `${Math.ceil((states.qExcluded / total) * 100)}%` };

let descriptions = '';
if (states.qSelected) {
classes += ' filtered';
}

if (fieldData.qHasDuplicates) {
classes += ' has-duplicates';
descriptions += '. Duplicate values';
} else {
descriptions += '. Unique values';
}

if (fieldData.qHasNull) {
classes += ' has-null';
descriptions += ', has nulls';
} else {
descriptions += ', no nulls.';
}

const allExcluded = states.qExcluded === total;
const singleHit = states.qExcluded === total - 1;

if (allExcluded) {
classes += ' all-excluded';
}

if (singleHit) {
classes += ' single-hit';
}

const isSynthetic = (fieldData.qTags && fieldData.qTags.find(item => item === '$synthetic'));
if (isSynthetic) {
const syntheticFieldStyle = {
border: `2px dashed ${fieldData.backgroundColor}`,
};

return (
<div
className={classes}
style={syntheticFieldStyle}
title="Synthetic key"
>
<div className="name">
{field}
</div>
const clearSelection = onClearSelection !== null
? (
<div className="clear-selection" tabIndex="-1" role="button" onClick={(event) => { onClearSelection(event, field); }}>
<i className="x">X</i>
</div>
);
}
) : null;

const fieldStyle = {
border: `2px solid ${fieldData.backgroundColor}`,
};
return (
<div
className={classes}
style={fieldStyle}
title={`${states.qSelected} selected, ${states.qOption
+ states.qAlternative} possible, ${
states.qExcluded
} excluded, total of ${total} values. ${descriptions}\n\n${firstFewValues(layout)}`}
>
<div className="name">
{field}
</div>
<div className="bartext">
{' '}
{fieldCounts(layout.qListObject.qDimensionInfo, fieldData)}
<div className="field">
<div className="inner-container">
<div className="name-and-text">
<div className="name">
{field}
</div>
<div className="bartext">
{' '}
{fieldCounts(layout.qListObject.qDimensionInfo, fieldData)}
</div>
</div>
{clearSelection}
</div>
<div className="gwg">
<span className="green" style={green} />
<span className="grey" style={grey} />
</div>
{ showFilterbox ? <div className="details"><Filterbox model={model} layout={layout} /></div> : null}
</div>
);
}

FieldWithoutState.propTypes = {
Field.propTypes = {
layout: PropTypes.object,
field: PropTypes.string.isRequired,
model: PropTypes.object.isRequired,
fieldData: PropTypes.object,
showFilterbox: PropTypes.bool,
onClearSelection: PropTypes.func,
};

FieldWithoutState.defaultProps = {
Field.defaultProps = {
layout: null,
fieldData: null,
showFilterbox: false,
onClearSelection: null,
};

const createDefinition = field => ({
qInfo: { qType: 'dmi-field' },
qListObjectDef: {
qFrequencyMode: 'V',
qDef: {
qFieldDefs: [field],
qSortCriterias: [
{
qSortByState: 1,
qSortByFrequency: 1,
// qSortByNumeric: 1,
// qSortByAscii: 1,
// qSortByLoadOrder: 1,
},
],
},
qInitialDataFetch: [
{
qTop: 0,
qLeft: 0,
qHeight: 10,
qWidth: 1,
},
],
},
});

export default function Field({
app, field, fieldData, showFilterbox,
}) {
const model = useModel(app, createDefinition(field));
const layout = useLayout(model);

return FieldWithoutState({
field, fieldData, showFilterbox, model, layout,
});
}
67 changes: 20 additions & 47 deletions src/components/field.pcss
Original file line number Diff line number Diff line change
@@ -1,36 +1,12 @@
.field {
background: #fff;
border: 2px solid #d9d9d9;
border-radius: 0.4em;
box-sizing: border-box;
cursor: pointer;
display: flex;
flex-direction: column;
font-size: 1rem;
height: 100%;
min-width: 22em;
padding: 1em;
position: relative;
z-index: 1;

&:hover {
box-shadow: 0 0 2em -0.5em #999;
}

&.NOT_KEY {
background-color: #fff;
}

&.all-excluded {
background-color: #e8e8e8;
}

&.single-hit {
box-shadow: inset 0 0 4px #ff0;
.inner-container {
display: flex;
}

&.filtered {
box-shadow: inset 0 0 2px #0f0;
.name-and-text {
display: flex;
flex: 1;
flex-direction: column;
}

.name,
Expand All @@ -43,14 +19,27 @@
}

.name {
display: inline-block;
font-size: 1.5em;
font-weight: 600;
line-height: 2rem;
overflow: hidden;
white-space: pre;
}

.clear-selection {
align-self: center;
outline: none;

&:hover {
box-shadow: 0 0 2em -0.5em #999;
}

.x {
font-size: 2rem;
font-style: normal;
}
}

.gwg {
background-color: #f2f2f2;
display: flex;
Expand All @@ -71,20 +60,4 @@
font-size: 1.375em;
line-height: 2rem;
}

.details {
box-sizing: border-box;
display: flex;
flex: 1 0 auto;
position: relative;

.filterbox {
bottom: 0;
display: block;
left: 0;
position: absolute;
right: 0;
top: 0.5em;
}
}
}
1 change: 0 additions & 1 deletion src/components/filterbox.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export default function Filterbox({ model, layout }) {
if (layout.qSelectionInfo.qMadeSelections) {
classes += ' made-selections';
}

return (
<div role="Listbox" tabIndex="-1" className={classes} onClick={preventDefaultFn} ref={selfRef}>
<input
Expand Down
1 change: 1 addition & 0 deletions src/components/filterbox.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
box-sizing: border-box;
color: #333;
font-size: 1.5rem;
height: 100%;
outline: none;
position: relative;
user-select: none;
Expand Down
6 changes: 3 additions & 3 deletions src/components/model.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import usePromise from 'react-use-promise';

import ScrollArea from './scroll-area';
import Field from './field';
import TableField from './table-field';
import logic from '../logic/logic';
import atplay from '../logic/atplay';

Expand Down Expand Up @@ -145,7 +145,7 @@ export default function Model({ app, appLayout }) {
key={`${tableName}:${fieldName}`}
fieldz={fieldName}
>
<Field app={app} field={fieldName} fieldData={x} showFilterbox={isFilterboxOpen} />
<TableField app={app} field={fieldName} fieldData={x} showFilterbox={isFilterboxOpen} />
{x.subsetRatioText ? (
<div className="subsetratio" title={x.subsetRatioTitle}>{x.subsetRatioText}</div>
) : null}
Expand Down Expand Up @@ -223,7 +223,7 @@ export default function Model({ app, appLayout }) {
key={field.qName}
style={cellContainerStyle}
>
<Field app={app} field={field.qName} fieldData={field} showFilterbox={isFilterboxOpen} />
<TableField app={app} field={field.qName} fieldData={field} showFilterbox={isFilterboxOpen} />
</div>
);
}
Expand Down
Loading

0 comments on commit 780000f

Please sign in to comment.