forked from M-Labs/web2019
Minimal working warnings and resources
TODO: * Add all other warnings for cards * Add crate level warnings * Add reminders to the bottom of the crate * Refactor crate mode selection (???) * Add resource consumers, instead of a bunch of nbrOccupiedSLots Signed-off-by: Egor Savkin <es@m-labs.hk>
This commit is contained in:
parent
530be12334
commit
abb472f0ea
|
@ -1,11 +1,10 @@
|
||||||
import React, {PureComponent} from 'react'
|
import React, {PureComponent} from 'react'
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import {Draggable} from "@hello-pangea/dnd";
|
import {Draggable} from "@hello-pangea/dnd";
|
||||||
import {OverlayTrigger} from "react-bootstrap";
|
|
||||||
import {DialogPopup} from "./options/DialogPopup.jsx";
|
import {DialogPopup} from "./options/DialogPopup.jsx";
|
||||||
import {productStyle} from "./utils";
|
import {productStyle} from "./utils";
|
||||||
import {Resources} from "./Resources.jsx";
|
import {Resources} from "./Resources.jsx";
|
||||||
import {Warnings} from "./Warnings";
|
import {Warnings} from "./Warnings.jsx";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that renders a product.
|
* Component that renders a product.
|
||||||
|
@ -82,20 +81,12 @@ export class ProductCartItem extends PureComponent {
|
||||||
first,
|
first,
|
||||||
last,
|
last,
|
||||||
ext_data,
|
ext_data,
|
||||||
resources,
|
|
||||||
onCardUpdate,
|
onCardUpdate,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
let warning, options, options_data;
|
let options, options_data;
|
||||||
if (data && data.warnings) {
|
const warnings = data && data.show_warnings;
|
||||||
const warningsKeys = Object.keys(data.warnings);
|
const resources = data && data.counted_resources;
|
||||||
if (warningsKeys && warningsKeys.length > 0) {
|
|
||||||
// we display only the first warning
|
|
||||||
warning = data.warnings[warningsKeys[0]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (data && data.options) {
|
if (data && data.options) {
|
||||||
options = data.options;
|
options = data.options;
|
||||||
|
@ -104,10 +95,6 @@ export class ProductCartItem extends PureComponent {
|
||||||
options_data.ext_data = ext_data;
|
options_data.ext_data = ext_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
let render_progress;
|
|
||||||
if (data) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable draggableId={model.id} index={index}>
|
<Draggable draggableId={model.id} index={index}>
|
||||||
|
@ -132,8 +119,8 @@ export class ProductCartItem extends PureComponent {
|
||||||
{/* warning container */}
|
{/* warning container */}
|
||||||
|
|
||||||
<div className="progress-container warning d-flex justify-content-evenly">
|
<div className="progress-container warning d-flex justify-content-evenly">
|
||||||
{warning &&
|
{warnings && warnings.length > 0 &&
|
||||||
(<Warnings warnings={warning} />)
|
(<Warnings warnings={warnings} />)
|
||||||
}
|
}
|
||||||
|
|
||||||
{options && (
|
{options && (
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {OverlayTrigger} from "react-bootstrap";
|
import {OverlayTrigger} from "react-bootstrap";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import {v4 as uuidv4} from "uuid";
|
||||||
|
|
||||||
|
|
||||||
const resourcesWidthStyle = (occupied, max) => {
|
const resourcesWidthStyle = (occupied, max) => {
|
||||||
|
@ -10,7 +11,7 @@ const resourcesWidthStyle = (occupied, max) => {
|
||||||
|
|
||||||
function EEMRenderer({occupied, max}) {
|
function EEMRenderer({occupied, max}) {
|
||||||
return (
|
return (
|
||||||
<div className="nbr-connectors">
|
<div className="nbr-connectors" key={uuidv4()}>
|
||||||
<div style={{...resourcesWidthStyle(occupied, max)}}></div>
|
<div style={{...resourcesWidthStyle(occupied, max)}}></div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -18,7 +19,7 @@ function EEMRenderer({occupied, max}) {
|
||||||
|
|
||||||
function ClockRenderer({occupied, max}) {
|
function ClockRenderer({occupied, max}) {
|
||||||
return (
|
return (
|
||||||
<div className="nbr-clocks">
|
<div className="nbr-clocks" key={uuidv4()}>
|
||||||
<div style={{...resourcesWidthStyle(occupied, max)}}></div>
|
<div style={{...resourcesWidthStyle(occupied, max)}}></div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -32,15 +33,15 @@ const resource_progress_renderers = {
|
||||||
|
|
||||||
|
|
||||||
function EEMTipRender({occupied, max}) {
|
function EEMTipRender({occupied, max}) {
|
||||||
return (<p>{`${occupied}/${max} EEM connectors used`}</p>);
|
return (<p key={uuidv4()}>{`${occupied}/${max} EEM connectors used`}</p>);
|
||||||
}
|
}
|
||||||
|
|
||||||
function IDCTipRender({occupied, max}) {
|
function IDCTipRender({occupied, max}) {
|
||||||
return (<p>{`${occupied}/${max} IDC connectors used`}</p>);
|
return (<p key={uuidv4()}>{`${occupied}/${max} IDC connectors used`}</p>);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ClockTipRender({occupied, max}) {
|
function ClockTipRender({occupied, max}) {
|
||||||
return (<p>{`${occupied}/${max} clock connectors used`}</p>);
|
return (<p key={uuidv4()}>{`${occupied}/${max} clock connectors used`}</p>);
|
||||||
}
|
}
|
||||||
|
|
||||||
const resource_tip = {
|
const resource_tip = {
|
||||||
|
|
|
@ -14,6 +14,8 @@ import {Crate} from "./Crate.jsx";
|
||||||
import {Cart} from "./Cart.jsx";
|
import {Cart} from "./Cart.jsx";
|
||||||
import {OrderSummary} from "./OrderSummary.jsx";
|
import {OrderSummary} from "./OrderSummary.jsx";
|
||||||
import {OrderForm} from "./OrderForm.jsx";
|
import {OrderForm} from "./OrderForm.jsx";
|
||||||
|
import {TriggerWarnings} from "./warnings";
|
||||||
|
import {FillResources} from "./count_resources";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that render the entire shop
|
* Component that render the entire shop
|
||||||
|
@ -465,18 +467,18 @@ export class Shop extends PureComponent {
|
||||||
crateRules,
|
crateRules,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const itemsCloned = Array.from(newItems);
|
let itemsCloned = Array.from(newItems);
|
||||||
const itemsData = [];
|
|
||||||
const rules = {};
|
const rules = {};
|
||||||
|
|
||||||
itemsCloned.forEach((elem, idx) => {
|
itemsCloned.forEach((elem, idx) => {
|
||||||
if (!(idx in itemsData)) itemsData[idx] = elem;
|
if (!(idx in itemsCloned)) itemsCloned[idx] = elem;
|
||||||
if (idx in this.state.columns.cart.itemsData && this.state.columns.cart.itemsData[idx].options_data) {
|
if (idx in this.state.columns.cart.itemsData && this.state.columns.cart.itemsData[idx].options_data) {
|
||||||
itemsCloned[idx].options_data = this.state.columns.cart.itemsData[idx].options_data;
|
itemsCloned[idx].options_data = this.state.columns.cart.itemsData[idx].options_data;
|
||||||
}
|
}
|
||||||
itemsData[idx].warnings = {};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itemsCloned = FillResources(itemsCloned);
|
||||||
|
itemsCloned = TriggerWarnings(itemsCloned);
|
||||||
|
|
||||||
// check number of slot in crate
|
// check number of slot in crate
|
||||||
const nbrOccupied = nbrOccupiedSlotsInCrate(newItems);
|
const nbrOccupied = nbrOccupiedSlotsInCrate(newItems);
|
||||||
|
@ -486,278 +488,6 @@ export class Shop extends PureComponent {
|
||||||
rules[crateRules.compactSlot.type] = {...crateRules.compactSlot};
|
rules[crateRules.compactSlot.type] = {...crateRules.compactSlot};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// check the number of EEM connectors available for all Kasli
|
|
||||||
const idxK = itemsCloned.reduce((prev, next, i) => {
|
|
||||||
if (next.type === 'kasli' || next.type === 'vhdcicarrier') {
|
|
||||||
prev.push(i);
|
|
||||||
}
|
|
||||||
return prev;
|
|
||||||
}, []);
|
|
||||||
for (let i = 0; i <= idxK.length - 1; i++) {
|
|
||||||
let slots;
|
|
||||||
let nbUsedSlot = 0;
|
|
||||||
let nbrCurrentClock = 0;
|
|
||||||
let idx = idxK[i];
|
|
||||||
|
|
||||||
if (i !== idxK.length - 1) {
|
|
||||||
slots = itemsCloned.slice(idx + 1, idxK[i + 1]);
|
|
||||||
} else {
|
|
||||||
slots = itemsCloned.slice(idx + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
const slots_need_resource = itemsCloned.slice(0, idx);
|
|
||||||
const idx_need = slots_need_resource.findIndex(e => (e.rules && e.rules.resources));
|
|
||||||
|
|
||||||
if (idx_need != -1) {
|
|
||||||
if (idx_need in itemsData) {
|
|
||||||
if ('warnings' in itemsData[idx_need]) {
|
|
||||||
itemsData[idx_need].warnings.resources = {...itemsCloned[idx_need].rules.resources};
|
|
||||||
} else {
|
|
||||||
itemsData[idx_need].warnings = {};
|
|
||||||
itemsData[idx_need].warnings.resources = {...itemsCloned[idx_need].rules.resources};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itemsData[idx_need] = {...itemsCloned[idx_need]};
|
|
||||||
itemsData[idx_need].warnings = {};
|
|
||||||
itemsData[idx_need].warnings.resources = {...itemsCloned[idx_need].rules.resources};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const process_slots = (item) => {
|
|
||||||
if (!item.options_data
|
|
||||||
|| item.options_data.ext_pwr === false
|
|
||||||
|| item.options_data.mono_eem === false
|
|
||||||
)
|
|
||||||
return item.slotOccupied;
|
|
||||||
else if (item.options_data.ext_pwr === true)
|
|
||||||
return 0;
|
|
||||||
else if (item.options_data.mono_eem === true || item.options_data.n_eem === "1 EEM")
|
|
||||||
return 1;
|
|
||||||
else if (item.options_data.n_eem === "3 EEM")
|
|
||||||
return 3;
|
|
||||||
|
|
||||||
return item.slotOccupied;
|
|
||||||
}
|
|
||||||
|
|
||||||
nbUsedSlot = slots
|
|
||||||
.filter(item => item.type !== 'idc-bnc')
|
|
||||||
.reduce((prev, next) => {
|
|
||||||
return prev + process_slots(next);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
nbrCurrentClock = slots
|
|
||||||
.reduce((prev, next) => {
|
|
||||||
return next.type === 'clocker' ? prev + ((next.options_data && next.options_data.ext_clk === true) ? 0 : next.clockOccupied) : prev;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
if (idx in itemsData) {
|
|
||||||
itemsData[idx].nbrCurrentSlot = nbUsedSlot;
|
|
||||||
itemsData[idx].nbrCurrentClock = nbrCurrentClock;
|
|
||||||
if (!('warnings' in itemsData[idx])) {
|
|
||||||
itemsData[idx].warnings = {};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itemsData[idx] = {...itemsCloned[idx]};
|
|
||||||
itemsData[idx].nbrCurrentSlot = nbUsedSlot;
|
|
||||||
itemsData[idx].nbrCurrentClock = nbrCurrentClock;
|
|
||||||
itemsData[idx].warnings = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbUsedSlot > itemsCloned[idx].nbrSlotMax) {
|
|
||||||
if (itemsCloned[idx].rules.maxSlot.message) {
|
|
||||||
rules[itemsCloned[idx].rules.maxSlot.type] = {...itemsCloned[idx].rules.maxSlot};
|
|
||||||
}
|
|
||||||
itemsData[idx].warnings.maxSlotWarning = {...itemsCloned[idx].rules.maxSlotWarning};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbrCurrentClock > itemsCloned[idx].nbrClockMax) {
|
|
||||||
rules[itemsCloned[idx].rules.maxClock.type] = {...itemsCloned[idx].rules.maxClock};
|
|
||||||
itemsData[idx].warnings.maxClockWarning = {...itemsCloned[idx].rules.maxClockWarning};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemsCloned.length > (idx + 1)) {
|
|
||||||
const ddkali = itemsCloned[idx + 1];
|
|
||||||
if (ddkali.type === 'kasli' || ddkali.type === 'vhdcicarrier') {
|
|
||||||
rules[ddkali.rules.follow.type] = {...ddkali.rules.follow};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idxK.length === 0) {
|
|
||||||
const slots_need_resource = itemsCloned.slice(0);
|
|
||||||
const idx_need = slots_need_resource.findIndex(e => (e.rules && e.rules.resources));
|
|
||||||
|
|
||||||
if (idx_need != -1) {
|
|
||||||
if (idx_need in itemsData) {
|
|
||||||
if ('warnings' in itemsData[idx_need]) {
|
|
||||||
itemsData[idx_need].warnings.resources = {...itemsCloned[idx_need].rules.resources};
|
|
||||||
} else {
|
|
||||||
itemsData[idx_need].warnings = {};
|
|
||||||
itemsData[idx_need].warnings.resources = {...itemsCloned[idx_need].rules.resources};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itemsData[idx_need] = {...itemsCloned[idx_need]};
|
|
||||||
itemsData[idx_need].warnings = {};
|
|
||||||
itemsData[idx_need].warnings.resources = {...itemsCloned[idx_need].rules.resources};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// check number of clock connector available
|
|
||||||
const idxC = itemsCloned.reduce((prev, next, i) => {
|
|
||||||
if (next.type === 'kasli' || next.type === 'clocker') {
|
|
||||||
prev.push(i);
|
|
||||||
}
|
|
||||||
return prev;
|
|
||||||
}, []);
|
|
||||||
for (let i = 0; i <= idxC.length - 1; i++) {
|
|
||||||
let slots;
|
|
||||||
let nbrCurrentClock = 0;
|
|
||||||
let idx = idxC[i];
|
|
||||||
|
|
||||||
if (i !== idxC.length - 1) {
|
|
||||||
slots = itemsCloned.slice(idx + 1, idxC[i + 1]);
|
|
||||||
} else {
|
|
||||||
slots = itemsCloned.slice(idx + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
nbrCurrentClock = slots.reduce((prev, next) => {
|
|
||||||
return prev + ((next.options_data && next.options_data.ext_clk && next.options_data.ext_clk.checked) ? 0 : next.clockOccupied);
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
if (idx in itemsData) {
|
|
||||||
if (itemsData[idx].nbrCurrentClock && itemsData[idx].type !== "clocker") {
|
|
||||||
itemsData[idx].nbrCurrentClock += nbrCurrentClock;
|
|
||||||
} else {
|
|
||||||
itemsData[idx].nbrCurrentClock = nbrCurrentClock;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itemsData[idx] = {...itemsCloned[idx]};
|
|
||||||
itemsData[idx].nbrCurrentClock = nbrCurrentClock;
|
|
||||||
itemsData[idx].warnings = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbrCurrentClock > itemsCloned[idx].nbrClockMax) {
|
|
||||||
rules[itemsCloned[idx].rules.maxClock.type] = {...itemsCloned[idx].rules.maxClock};
|
|
||||||
itemsData[idx].warnings.maxClockWarning = {...itemsCloned[idx].rules.maxClockWarning};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (itemsCloned.find(elem => elem.type === 'urukul')) {
|
|
||||||
if (this.state.items['urukul'].rules.info) {
|
|
||||||
rules[this.state.items['urukul'].rules.info.type] = {...this.state.items['urukul'].rules.info};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// check if IDC-BNC is correctly positionned (after Zotino or HD68)
|
|
||||||
const idxIDCBNC = itemsCloned.reduce((prev, next, i) => {
|
|
||||||
if (next.type === 'idc-bnc') {
|
|
||||||
prev.push(i);
|
|
||||||
}
|
|
||||||
return prev;
|
|
||||||
}, []);
|
|
||||||
for (var i = idxIDCBNC.length - 1; i >= 0; i--) {
|
|
||||||
const ce = idxIDCBNC[i];
|
|
||||||
let shouldWarning = false;
|
|
||||||
|
|
||||||
if (ce == 0) {
|
|
||||||
shouldWarning = true;
|
|
||||||
} else if (ce >= 1) {
|
|
||||||
const pe = idxIDCBNC[i] - 1;
|
|
||||||
if (itemsCloned[pe].type !== 'zotino' &&
|
|
||||||
itemsCloned[pe].type !== 'hd68' &&
|
|
||||||
itemsCloned[pe].type !== 'idc-bnc') {
|
|
||||||
shouldWarning = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldWarning) {
|
|
||||||
itemsData[ce] = {...itemsCloned[ce]};
|
|
||||||
itemsData[ce].warnings = {};
|
|
||||||
itemsData[ce].warnings.wrong = {...itemsCloned[ce].rules.wrong};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// check number of IDC-BNC adapters for a Zotino and HD68-IDC
|
|
||||||
const idxZH = itemsCloned.reduce((prev, next, i) => {
|
|
||||||
if (next.type === 'zotino' || next.type === 'hd68') {
|
|
||||||
prev.push(i);
|
|
||||||
}
|
|
||||||
return prev;
|
|
||||||
}, []);
|
|
||||||
for (let i = 0; i <= idxZH.length - 1; i++) {
|
|
||||||
let slots;
|
|
||||||
let nbUsedSlot = 0;
|
|
||||||
let idx = idxZH[i];
|
|
||||||
|
|
||||||
if (i !== idxZH.length - 1) {
|
|
||||||
slots = itemsCloned.slice(idx + 1, idxZH[i + 1]);
|
|
||||||
} else {
|
|
||||||
slots = itemsCloned.slice(idx + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let stopCount = false;
|
|
||||||
nbUsedSlot = slots.reduce((prev, next, ci, ca) => {
|
|
||||||
if (ci === 0 && next.type === 'idc-bnc') {
|
|
||||||
return prev + 1;
|
|
||||||
} else if (ca[0].type === 'idc-bnc' && ci > 0 && ca[ci - 1].type === 'idc-bnc') {
|
|
||||||
if (next.type !== 'idc-bnc') { stopCount = true; }
|
|
||||||
return prev + (next.type === 'idc-bnc' && !stopCount ? 1 : 0);
|
|
||||||
}
|
|
||||||
return prev;
|
|
||||||
}, 0);
|
|
||||||
|
|
||||||
if (idx in itemsData) {
|
|
||||||
itemsData[idx].nbrCurrentSlot = nbUsedSlot;
|
|
||||||
if (!('warnings' in itemsData[idx])) {
|
|
||||||
itemsData[idx].warnings = {};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itemsData[idx] = {...itemsCloned[idx]};
|
|
||||||
itemsData[idx].nbrCurrentSlot = nbUsedSlot;
|
|
||||||
itemsData[idx].warnings = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbUsedSlot > 0) {
|
|
||||||
if (itemsCloned[idx].rules.maxSlot.message) {
|
|
||||||
rules[itemsCloned[idx].rules.maxSlot.type] = {...itemsCloned[idx].rules.maxSlot};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nbUsedSlot > itemsCloned[idx].nbrSlotMax) {
|
|
||||||
itemsData[idx].warnings.maxSlotWarning = {...itemsCloned[idx].rules.maxSlotWarning};
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if HD68-IDC has at least 1 IDC-BNC adapter
|
|
||||||
if (itemsCloned[idx].type === 'hd68') {
|
|
||||||
let shouldWarning = false;
|
|
||||||
|
|
||||||
if (idx < itemsCloned.length - 1) {
|
|
||||||
if (itemsCloned[idx + 1].type !== 'idc-bnc') {
|
|
||||||
shouldWarning = true;
|
|
||||||
}
|
|
||||||
} else if (idx === itemsCloned.length - 1) {
|
|
||||||
shouldWarning = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldWarning) {
|
|
||||||
if (idx in itemsData) {
|
|
||||||
itemsData[idx].warnings.minAdapter = {...itemsCloned[idx].rules.minAdapter};
|
|
||||||
} else {
|
|
||||||
itemsData[idx] = {...itemsCloned[idx]};
|
|
||||||
itemsData[idx].warnings = {};
|
|
||||||
itemsData[idx].warnings.minAdapter = {...itemsCloned[idx].rules.minAdapter};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update state with rules
|
// update state with rules
|
||||||
this.setState({
|
this.setState({
|
||||||
...this.state,
|
...this.state,
|
||||||
|
@ -765,7 +495,7 @@ export class Shop extends PureComponent {
|
||||||
...this.state.columns,
|
...this.state.columns,
|
||||||
cart: {
|
cart: {
|
||||||
...this.state.columns.cart,
|
...this.state.columns.cart,
|
||||||
itemsData: itemsData,
|
itemsData: itemsCloned,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import {OverlayTrigger} from "react-bootstrap";
|
import {OverlayTrigger} from "react-bootstrap";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import {MaxLevel} from "./warnings";
|
||||||
|
|
||||||
|
|
||||||
export function Warnings({warnings}) {
|
export function Warnings({warnings}) {
|
||||||
|
const max_level = MaxLevel(warnings);
|
||||||
return (
|
return (
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
|
@ -11,15 +12,18 @@ export function Warnings({warnings}) {
|
||||||
overlay={
|
overlay={
|
||||||
({arrowProps, hasDoneInitialMeasure, show, ...props}) => (
|
({arrowProps, hasDoneInitialMeasure, show, ...props}) => (
|
||||||
<div className="k-popup-warning" {...props}>
|
<div className="k-popup-warning" {...props}>
|
||||||
|
{warnings.map((warning, _i) => {
|
||||||
<p className="rule warning">
|
return (
|
||||||
<i>{warnings.message}</i>
|
<p className="rule warning">
|
||||||
</p>
|
<i>{warning.message}</i>
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
rootClose
|
rootClose
|
||||||
>
|
>
|
||||||
<img className="alert-warning" src={`/images${warning.icon}`}/>
|
<img className="alert-warning" src={max_level.icon}/>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
export const count_item_occupied_eem = (item) => {
|
const count_item_occupied_eem = (item) => {
|
||||||
if (!item.options_data
|
if (!item.options_data
|
||||||
|| item.options_data.ext_pwr === false
|
|| item.options_data.ext_pwr === false
|
||||||
|| item.options_data.mono_eem === false
|
|| item.options_data.mono_eem === false
|
||||||
|
@ -15,49 +15,38 @@ export const count_item_occupied_eem = (item) => {
|
||||||
return item.slotOccupied || 0;
|
return item.slotOccupied || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const count_item_occupied_clock = (item) => {
|
const count_item_occupied_clock = (item) => {
|
||||||
return (item.options_data && item.options_data.ext_clk === true) ? 0 : (item.clockOccupied || 0);
|
return (item.options_data && item.options_data.ext_clk === true) ? 0 : (item.clockOccupied || 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const count_item_occupied_idc = (item) => {
|
const count_item_occupied_idc = (item) => {
|
||||||
return item.idcOccupied || 0;
|
return item.idcOccupied || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function EEMCounter(data, index) {
|
export const item_occupied_counters = {
|
||||||
let count = 0;
|
"eem": count_item_occupied_eem,
|
||||||
for (let i = index + 1; i < data.length; i++) {
|
"clk": count_item_occupied_clock,
|
||||||
if (!!data[i].resources.find((value, _i) => value.name === "eem")) break;
|
"idc": count_item_occupied_idc,
|
||||||
count += count_item_occupied_eem(data[i]);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function ClockCounter(data, index) {
|
function CounterFactory(name) {
|
||||||
let count = 0;
|
return (data, index) => {
|
||||||
for (let i = index + 1; i < data.length; i++) {
|
let count = 0;
|
||||||
if (!!data[i].resources.find((value, _i) => value.name === "clk")) break;
|
for (let i = index + 1; i < data.length; i++) {
|
||||||
count += count_item_occupied_clock(data[i]);
|
if (data[i].resources && !!data[i].resources.find((value, _i) => value.name === name)) break;
|
||||||
|
count += item_occupied_counters[name](data[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function IDCCounter(data, index) {
|
|
||||||
let count = 0;
|
|
||||||
for (let i = index + 1; i < data.length; i++) {
|
|
||||||
if (!!data[i].resources.find((value, _i) => value.name === "idc")) break;
|
|
||||||
count += count_item_occupied_idc(data[i]);
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const resource_counters = {
|
const resource_counters = {
|
||||||
"eem": EEMCounter,
|
"eem": CounterFactory("eem"),
|
||||||
"clk": ClockCounter,
|
"clk": CounterFactory("clk"),
|
||||||
"idc": IDCCounter
|
"idc": CounterFactory("idc")
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CountResources(data, index) {
|
function CountResources(data, index) {
|
||||||
if (!data[index].resources) return null;
|
if (!data[index].resources) return null;
|
||||||
let result = [];
|
let result = [];
|
||||||
data[index].resources.forEach((item, _) => {
|
data[index].resources.forEach((item, _) => {
|
||||||
|
@ -69,3 +58,10 @@ export function CountResources(data, index) {
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function FillResources(data) {
|
||||||
|
return data.map((element, index) => {
|
||||||
|
element.counted_resources = CountResources(data, index);
|
||||||
|
return element;
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import React from "react";
|
||||||
import {apply as json_logic_apply} from "json-logic-js";
|
import {apply as json_logic_apply} from "json-logic-js";
|
||||||
import {componentsList} from "./components/components";
|
import {componentsList} from "./components/components";
|
||||||
import {true_type_of} from "./utils";
|
import {true_type_of} from "./utils";
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
* Second - resources indicator should be separate component
|
* Second - resources indicator should be separate component
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {count_item_occupied_eem, count_item_occupied_clock, count_item_occupied_idc} from "./count_resources";
|
import {item_occupied_counters} from "./count_resources";
|
||||||
|
|
||||||
const Levels = {
|
const Levels = {
|
||||||
"reminder": {priority: 0, icon: '/images/shop/icon-reminder.svg'},
|
"reminder": {priority: 1, icon: '/images/shop/icon-reminder.svg'},
|
||||||
"warning": {priority: 1, icon: '/images/shop/icon-warning.svg'},
|
"warning": {priority: 2, icon: '/images/shop/icon-warning.svg'},
|
||||||
}
|
}
|
||||||
|
|
||||||
const find_in_counters = (counters, name) => {
|
const find_in_counters = (counters, name) => {
|
||||||
|
@ -17,7 +17,15 @@ const find_in_counters = (counters, name) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const find_previous_source = (data, index, source) => {
|
const find_previous_source = (data, index, source) => {
|
||||||
return data.slice(0, index).find((element) => {element.resources.find((value) => value.name === source)})
|
return data.slice(0, index).find((element) => {
|
||||||
|
return element.resources && find_in_counters(element.resources, source)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const find_next_source_index = (data, index, source) => {
|
||||||
|
return data.slice(index + 1).findIndex((element) => {
|
||||||
|
return element.resources && find_in_counters(element.resources, source)
|
||||||
|
}) + index + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
const not_enough_resource_trigger = (name) => {
|
const not_enough_resource_trigger = (name) => {
|
||||||
|
@ -29,20 +37,31 @@ const not_enough_resource_trigger = (name) => {
|
||||||
|
|
||||||
const no_source_trigger = (name) => {
|
const no_source_trigger = (name) => {
|
||||||
return (data, index, _counters) => {
|
return (data, index, _counters) => {
|
||||||
const occupied = count_item_occupied_eem(data[index]);
|
const occupied = item_occupied_counters[name](data[index]);
|
||||||
if (occupied > 0)
|
if (occupied > 0)
|
||||||
return !!find_previous_source(data, index, name);
|
return !find_previous_source(data, index, name);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wiring_constraint = (name) => {
|
||||||
|
return (data, index, _counters) => {
|
||||||
|
const next = find_next_source_index(data, index, name);
|
||||||
|
return next - index === 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const crate_overload = (data, index, _counters) => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
const Types = {
|
const Types = {
|
||||||
"eem_resource": {
|
"eem_resource": {
|
||||||
level: "warning",
|
level: "warning",
|
||||||
trigger: not_enough_resource_trigger("eem"),
|
trigger: not_enough_resource_trigger("eem"),
|
||||||
message: "Insufficient EEM connectors"
|
message: "Insufficient EEM connectors"
|
||||||
},
|
},
|
||||||
"no_eem_source" : {
|
"no_eem_source": {
|
||||||
level: "warning",
|
level: "warning",
|
||||||
trigger: no_source_trigger("eem"),
|
trigger: no_source_trigger("eem"),
|
||||||
message: 'This card needs a card that provides a EEM connector (e.g. Kasli) at its left.'
|
message: 'This card needs a card that provides a EEM connector (e.g. Kasli) at its left.'
|
||||||
|
@ -52,7 +71,7 @@ const Types = {
|
||||||
trigger: not_enough_resource_trigger("idc"),
|
trigger: not_enough_resource_trigger("idc"),
|
||||||
message: "Insufficient IDC connectors."
|
message: "Insufficient IDC connectors."
|
||||||
},
|
},
|
||||||
"no_idc_source" : {
|
"no_idc_source": {
|
||||||
level: "warning",
|
level: "warning",
|
||||||
trigger: no_source_trigger("idc"),
|
trigger: no_source_trigger("idc"),
|
||||||
message: 'Should be after a Zotino or a HD68-IDC or with another IDC-BNC.'
|
message: 'Should be after a Zotino or a HD68-IDC or with another IDC-BNC.'
|
||||||
|
@ -62,10 +81,52 @@ const Types = {
|
||||||
trigger: not_enough_resource_trigger("clk"),
|
trigger: not_enough_resource_trigger("clk"),
|
||||||
message: "Insufficient clock connectors."
|
message: "Insufficient clock connectors."
|
||||||
},
|
},
|
||||||
"no_clk_source" : {
|
"no_clk_source": {
|
||||||
level: "warning",
|
level: "warning",
|
||||||
trigger: no_source_trigger("clk"),
|
trigger: no_source_trigger("clk"),
|
||||||
message: 'This card needs either a card that provides a clock source (e.g. Kasli or Clocker) at its left or use external clock source.'
|
message: 'This card needs either a card that provides a clock source (e.g. Kasli or Clocker) at its left or use an external clock source.'
|
||||||
},
|
},
|
||||||
|
"eem_wiring_constraint": {
|
||||||
|
level: "reminder",
|
||||||
|
trigger: wiring_constraint("eem"),
|
||||||
|
message: "Due to wiring constraints, the carrier can only connect to EEM cards immediately at its right, without crossing another carrier."
|
||||||
|
},
|
||||||
|
"crate_overload": {
|
||||||
|
level: "warning",
|
||||||
|
trigger: crate_overload,
|
||||||
|
message: 'This card needs either a card that provides a clock source (e.g. Kasli or Clocker) at its left or use an external clock source.'
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
level: "warning",
|
||||||
|
trigger: (_a, _b, _c) => {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
message: 'This item has unimplemented warning'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function TriggerWarnings(data) {
|
||||||
|
return data.map((element, index) => {
|
||||||
|
if (!element.warnings) return element;
|
||||||
|
element.show_warnings = element.warnings
|
||||||
|
.map((warning, _) => {
|
||||||
|
if (!!Types[warning])
|
||||||
|
return Types[warning].trigger(data, index, element.counted_resources) ? {trigger: undefined, ...Types[warning]} : null;
|
||||||
|
else
|
||||||
|
return Types.default.trigger(data, index, element.counted_resources);
|
||||||
|
})
|
||||||
|
.filter((warning, _) => {
|
||||||
|
return !!warning
|
||||||
|
});
|
||||||
|
return element;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function MaxLevel(warnings) {
|
||||||
|
let mx = {priority: 0, icon: null};
|
||||||
|
for (const warning of warnings) {
|
||||||
|
if (Levels[warning.level].priority > mx.priority) mx = Levels[warning.level];
|
||||||
|
}
|
||||||
|
return mx;
|
||||||
|
}
|
|
@ -91,38 +91,15 @@ const shop_data = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
rules: {
|
resources: [
|
||||||
maxSlot: {
|
{name: "eem", max: 5},
|
||||||
type: 'kasli-max-slot',
|
{name: "clk", max: 4},
|
||||||
icon: '/shop/icon-reminder.svg',
|
],
|
||||||
name: 'Kasli',
|
warnings: [
|
||||||
message: 'Insufficient EEM connectors.',
|
"eem_resource",
|
||||||
},
|
"clk_resource",
|
||||||
maxSlotWarning: {
|
"eem_wiring_constraint"
|
||||||
type: 'kasli-max-slot-warning',
|
]
|
||||||
icon: '/shop/icon-warning.svg',
|
|
||||||
name: 'Kasli',
|
|
||||||
message: 'Insufficient EEM connectors',
|
|
||||||
},
|
|
||||||
maxClock: {
|
|
||||||
type: 'kasli-max-clock',
|
|
||||||
icon: '/shop/icon-reminder.svg',
|
|
||||||
name: 'Kasli',
|
|
||||||
message: 'Insufficient clock connectors. Kasli has at most 4 clock connections.',
|
|
||||||
},
|
|
||||||
maxClockWarning: {
|
|
||||||
type: 'kasli-max-clock-warning',
|
|
||||||
icon: '/shop/icon-warning.svg',
|
|
||||||
name: 'Kasli',
|
|
||||||
message: 'Insufficient clock connectors.',
|
|
||||||
},
|
|
||||||
follow: {
|
|
||||||
type: 'kasli-follow',
|
|
||||||
icon: '/shop/icon-reminder.svg',
|
|
||||||
name: 'Kasli',
|
|
||||||
message: 'Due to wiring constraints, a Kasli can only connect to EEM cards immediately at its right, without crossing another carrier.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'kaslisoc': {
|
'kaslisoc': {
|
||||||
id: 'kaslisoc',
|
id: 'kaslisoc',
|
||||||
|
@ -338,14 +315,9 @@ const shop_data = {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
rules: {
|
warnings: [
|
||||||
resources: {
|
"no_eem_source"
|
||||||
type: 'bnc-dio',
|
]
|
||||||
icon: '/shop/icon-warning.svg',
|
|
||||||
name: 'BNC-DIO',
|
|
||||||
message: 'This card needs a card that provides a EEM connector (e.g. Kasli) at its left.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'sma-dio': {
|
'sma-dio': {
|
||||||
id: 'sma-dio',
|
id: 'sma-dio',
|
||||||
|
@ -411,14 +383,9 @@ const shop_data = {
|
||||||
nbrClockMax: 0,
|
nbrClockMax: 0,
|
||||||
slotOccupied: 1,
|
slotOccupied: 1,
|
||||||
clockOccupied: 0,
|
clockOccupied: 0,
|
||||||
rules: {
|
warnings: [
|
||||||
resources: {
|
"no_eem_source"
|
||||||
type: 'sma-dio',
|
]
|
||||||
icon: '/shop/icon-warning.svg',
|
|
||||||
name: 'SMA-DIO',
|
|
||||||
message: 'This card needs a card that provides a EEM connector (e.g. Kasli) at its left.',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'mcx-dio': {
|
'mcx-dio': {
|
||||||
id: 'mcx-dio',
|
id: 'mcx-dio',
|
||||||
|
|
Loading…
Reference in New Issue