forked from M-Labs/web2019
Compare commits
11 Commits
5e5246e8ae
...
608f253684
Author | SHA1 | Date |
---|---|---|
Egor Savkin | 608f253684 | |
Egor Savkin | 66bb5b25d8 | |
Egor Savkin | 34a86e24c5 | |
Egor Savkin | 175e625cc6 | |
Egor Savkin | 49882c7af2 | |
Egor Savkin | efd6b12c83 | |
Egor Savkin | 18bd98a204 | |
Egor Savkin | f29807a913 | |
Egor Savkin | 9d9a4c9f5a | |
Egor Savkin | 92f7428ac8 | |
Egor Savkin | a163a269b9 |
|
@ -90,6 +90,7 @@ a {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
.navbar-light .navbar-nav .nav-link,
|
.navbar-light .navbar-nav .nav-link,
|
||||||
.dropdown-item {
|
.dropdown-item {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@ -112,6 +113,29 @@ a {
|
||||||
color: $color-secondary;
|
color: $color-secondary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.dropdown-item {
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dropdown-item.active {
|
||||||
|
color: $color-secondary;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-toggler {
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&:hover {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,22 +151,6 @@ a {
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu {
|
|
||||||
border: none;
|
|
||||||
margin-top: 0;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
.dropdown-item {
|
|
||||||
&:hover,
|
|
||||||
&:active {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.dropdown-item.active {
|
|
||||||
color: $color-secondary;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background-color: $btn-primary-2;
|
background-color: $btn-primary-2;
|
||||||
color: #fff !important;
|
color: #fff !important;
|
||||||
|
@ -155,18 +163,11 @@ a {
|
||||||
border: 1px solid $btn-secondary-2 !important;
|
border: 1px solid $btn-secondary-2 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-lg {
|
.btn-lg {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
padding: 1rem 1.25rem;
|
padding: 1rem 1.25rem;
|
||||||
}
|
}
|
||||||
.navbar-toggler {
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
&:focus,
|
|
||||||
&:hover {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.th {
|
ul.th {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
@ -200,6 +201,63 @@ ul:not(.navbar-nav) li {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.download-selector {
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
border-right: solid 1px white;
|
||||||
|
margin: 0.125rem 0;
|
||||||
|
height: inherit;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu {
|
||||||
|
border: none;
|
||||||
|
margin-top: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
background-color: $btn-primary-2;
|
||||||
|
&:hover {
|
||||||
|
background-color: $btn-secondary-2;
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
&[aria-expanded='true']:after {
|
||||||
|
transform: rotate(-180deg);
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
margin-left: 0!important;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
|
||||||
|
a {
|
||||||
|
padding: 0.75rem 0.5rem 0.75rem 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li::before {
|
||||||
|
content: none;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.bg-white-shadow {
|
.bg-white-shadow {
|
||||||
background: url(../images/migen-links@2x.png);
|
background: url(../images/migen-links@2x.png);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
|
@ -485,6 +485,12 @@ button {
|
||||||
padding: 5px 5px 12px;
|
padding: 5px 5px 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
&.horizontal {
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 50px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
@ -571,67 +577,6 @@ button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlayVariant {
|
|
||||||
top: 24px;
|
|
||||||
width: 140px;
|
|
||||||
min-height: 40px;
|
|
||||||
max-height: 320px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
position: absolute;
|
|
||||||
display: flex;
|
|
||||||
align-items: start;
|
|
||||||
text-align: left;
|
|
||||||
background-color: white;
|
|
||||||
color: black;
|
|
||||||
flex-direction: column;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.2rem 0;
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: .65rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
|
||||||
margin: 0.1rem 0.2rem;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
|
|
||||||
input {
|
|
||||||
padding: 0;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
line-height: 1.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin-bottom: 0.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.options-icon {
|
|
||||||
display: inline;
|
|
||||||
height: .875rem;
|
|
||||||
margin-right: 0.2rem;
|
|
||||||
margin-left: 0.2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-check {
|
|
||||||
min-height: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.overlay-smallcard {
|
|
||||||
left: -38.5px; // (card width (63) - overlay width (140)) / 2
|
|
||||||
|
|
||||||
&.overlay-first {
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
&.overlay-last {
|
|
||||||
left: -67px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.overlay-bigcard {
|
|
||||||
left: -7px; // (card width (126) - overlay width (140)) / 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hovered {
|
.hovered {
|
||||||
|
@ -778,3 +723,49 @@ button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.overlayVariant {
|
||||||
|
width: 140px;
|
||||||
|
min-height: 40px;
|
||||||
|
max-height: 320px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
text-align: left;
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
flex-direction: column;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.2rem 0;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: .65rem;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div {
|
||||||
|
margin: 0.1rem 0.2rem;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
|
||||||
|
input {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-bottom: 0.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options-icon {
|
||||||
|
display: inline;
|
||||||
|
height: .875rem;
|
||||||
|
margin-right: 0.2rem;
|
||||||
|
margin-left: 0.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check {
|
||||||
|
min-height: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" stroke-linecap="round" stroke-opacity=".6" stroke-width=".35269"><path d="m0.52917 0.52917h5.5563v5.5563h-5.5563z"/><path d="m6.6146 0.52917h5.5563v5.5563h-5.5563z"/><path d="m0.52917 6.6146h5.5563v5.5563h-5.5563z"/><path d="m6.6146 6.6146h5.5563v5.5563h-5.5563z"/></g></svg>
|
After Width: | Height: | Size: 392 B |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 13 KiB |
File diff suppressed because one or more lines are too long
|
@ -32,8 +32,6 @@ export function Cart({crate_index}) {
|
||||||
<ProductCartItem
|
<ProductCartItem
|
||||||
card_index={index}
|
card_index={index}
|
||||||
crate_index={crate_index}
|
crate_index={crate_index}
|
||||||
first={index === 0}
|
|
||||||
last={index === crate.items.length - 1 && nbrOccupied >= nbrSlots}
|
|
||||||
key={item.id}/>
|
key={item.id}/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {Droppable} from "@hello-pangea/dnd";
|
||||||
|
import {cartStyle, compareArraysWithIds} from "./utils";
|
||||||
|
import {ProductCartItemHorizontal} from "./ProductCartItemHorizontal";
|
||||||
|
import {HORIZONTAL_CART_MARKER, useShopStore} from "./shop_store";
|
||||||
|
|
||||||
|
// #!render_count
|
||||||
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that displays a list of <ProductCartItem>
|
||||||
|
*/
|
||||||
|
export function CartHorizontal({crate_index}) {
|
||||||
|
// #!render_count
|
||||||
|
const renderCount = useRenderCount();
|
||||||
|
|
||||||
|
const crate = useShopStore((state) => state.crates[crate_index], (a, b) => {
|
||||||
|
return compareArraysWithIds(a.h_items, b.h_items)
|
||||||
|
});
|
||||||
|
|
||||||
|
// #!render_count
|
||||||
|
console.log("CartHorizontal renders: ", renderCount)
|
||||||
|
|
||||||
|
|
||||||
|
const products = crate.h_items.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<ProductCartItemHorizontal
|
||||||
|
card_index={index}
|
||||||
|
crate_index={crate_index}
|
||||||
|
key={item.id}/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Droppable droppableId={crate.id+HORIZONTAL_CART_MARKER} direction="vertical">
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<div
|
||||||
|
ref={provided.innerRef}
|
||||||
|
{...provided.droppableProps}
|
||||||
|
style={cartStyle(
|
||||||
|
provided.droppableProps.style,
|
||||||
|
snapshot,
|
||||||
|
)}
|
||||||
|
className="items-cart-list horizontal">
|
||||||
|
|
||||||
|
{products}
|
||||||
|
|
||||||
|
{provided.placeholder && (
|
||||||
|
<div style={{display: 'none'}}>
|
||||||
|
{provided.placeholder}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Droppable>
|
||||||
|
);
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import {CrateMode} from "./CrateMode";
|
||||||
import {CrateWarnings} from "./CrateWarnings";
|
import {CrateWarnings} from "./CrateWarnings";
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
import {CrateOptions} from "./CrateOptions";
|
import {CrateOptions} from "./CrateOptions";
|
||||||
|
import {CartHorizontal} from "./CartHorizontal";
|
||||||
|
|
||||||
// #!render_count
|
// #!render_count
|
||||||
import {useRenderCount} from "@uidotdev/usehooks";
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
|
@ -28,7 +29,7 @@ export function Crate({crate_index}) {
|
||||||
return (
|
return (
|
||||||
<div className="crate">
|
<div className="crate">
|
||||||
{
|
{
|
||||||
modes_order.includes(crate.crate_mode) ? (
|
modes_order.includes(crate.crate_mode) && (
|
||||||
<div className="crate-bar d-inline-flex justify-content-between">
|
<div className="crate-bar d-inline-flex justify-content-between">
|
||||||
<CrateMode crate_index={crate_index}/>
|
<CrateMode crate_index={crate_index}/>
|
||||||
|
|
||||||
|
@ -36,13 +37,15 @@ export function Crate({crate_index}) {
|
||||||
Delete crate <img src="/images/shop/icon-remove.svg" alt="remove"/>
|
Delete crate <img src="/images/shop/icon-remove.svg" alt="remove"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : <></>
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
<div className="crate-products">
|
<div className="crate-products">
|
||||||
|
|
||||||
<Cart crate_index={crate_index}/>
|
<Cart crate_index={crate_index}/>
|
||||||
|
|
||||||
|
<CartHorizontal crate_index={crate_index}/>
|
||||||
|
|
||||||
<CrateWarnings crate_index={crate_index} />
|
<CrateWarnings crate_index={crate_index} />
|
||||||
|
|
||||||
<CrateOptions crate_index={crate_index}/>
|
<CrateOptions crate_index={crate_index}/>
|
||||||
|
|
|
@ -3,11 +3,11 @@ import React from "react";
|
||||||
import {useShopStore} from "./shop_store";
|
import {useShopStore} from "./shop_store";
|
||||||
import {SummaryPopup} from "./options/SummaryPopup";
|
import {SummaryPopup} from "./options/SummaryPopup";
|
||||||
|
|
||||||
export function OptionsDialogWrapper({crate_index, card_index, first, last}) {
|
export function OptionsDialogWrapper({crate_index, card_index, horizontal}) {
|
||||||
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
||||||
const options = useShopStore((state) => state.crates[crate_index].items[card_index].options);
|
const use_options = useShopStore((state) => state.crateParams(state.crates[crate_index].crate_mode).options);
|
||||||
|
const options = useShopStore((state) => state.crates[crate_index].items[card_index][use_options]);
|
||||||
const options_data = useShopStore((state) => state.crates[crate_index].items[card_index].options_data);
|
const options_data = useShopStore((state) => state.crates[crate_index].items[card_index].options_data);
|
||||||
const card_size = useShopStore((state) => state.crates[crate_index].items[card_index].size);
|
|
||||||
const card_id = useShopStore((state) => state.crates[crate_index].items[card_index].id);
|
const card_id = useShopStore((state) => state.crates[crate_index].items[card_index].id);
|
||||||
const options_class = useShopStore((state) => state.crates[crate_index].items[card_index].options_class);
|
const options_class = useShopStore((state) => state.crates[crate_index].items[card_index].options_class);
|
||||||
const sideMenuIsOpen = useShopStore((state) => state.sideMenuIsOpen);
|
const sideMenuIsOpen = useShopStore((state) => state.sideMenuIsOpen);
|
||||||
|
@ -26,12 +26,10 @@ export function OptionsDialogWrapper({crate_index, card_index, first, last}) {
|
||||||
options_class={options_class}
|
options_class={options_class}
|
||||||
key={"popover" + crate_id +card_id}
|
key={"popover" + crate_id +card_id}
|
||||||
id={"popover"+ crate_id + card_id}
|
id={"popover"+ crate_id + card_id}
|
||||||
big={card_size === "big"}
|
|
||||||
first={first}
|
|
||||||
last={last}
|
|
||||||
sideMenuIsOpen={sideMenuIsOpen}
|
sideMenuIsOpen={sideMenuIsOpen}
|
||||||
onHideNotification={hideNotification}
|
onHideNotification={hideNotification}
|
||||||
displayNotification={displayNotification}
|
displayNotification={displayNotification}
|
||||||
|
horizontal={horizontal}
|
||||||
target={{
|
target={{
|
||||||
construct: ((outvar, value) => {
|
construct: ((outvar, value) => {
|
||||||
// #!options_log
|
// #!options_log
|
||||||
|
@ -53,7 +51,8 @@ export function OptionsDialogWrapper({crate_index, card_index, first, last}) {
|
||||||
|
|
||||||
export function OptionsSummaryWrapper({crate_index, card_index}) {
|
export function OptionsSummaryWrapper({crate_index, card_index}) {
|
||||||
const card_id = useShopStore((state) => state.crates[crate_index].items[card_index].id);
|
const card_id = useShopStore((state) => state.crates[crate_index].items[card_index].id);
|
||||||
const options = useShopStore((state) => state.crates[crate_index].items[card_index].options);
|
const use_options = useShopStore((state) => state.crateParams(state.crates[crate_index].crate_mode).options);
|
||||||
|
const options = useShopStore((state) => state.crates[crate_index].items[card_index][use_options]);
|
||||||
const options_data = useShopStore((state) => state.crates[crate_index].items[card_index].options_data);
|
const options_data = useShopStore((state) => state.crates[crate_index].items[card_index].options_data);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
* Component that renders a product.
|
* Component that renders a product.
|
||||||
* Used in the crate
|
* Used in the crate
|
||||||
*/
|
*/
|
||||||
export function ProductCartItem({card_index, crate_index, first, last}) {
|
export function ProductCartItem({card_index, crate_index}) {
|
||||||
// #!render_count
|
// #!render_count
|
||||||
const renderCount = useRenderCount();
|
const renderCount = useRenderCount();
|
||||||
|
|
||||||
|
@ -25,7 +25,8 @@ export function ProductCartItem({card_index, crate_index, first, last}) {
|
||||||
const card_counted_resources = useShopStore(state => state.crates[crate_index].items[card_index].counted_resources, compareObjectsEmptiness);
|
const card_counted_resources = useShopStore(state => state.crates[crate_index].items[card_index].counted_resources, compareObjectsEmptiness);
|
||||||
|
|
||||||
const highlighted = useShopStore((state) => state.crates[crate_index].id === state.highlighted.crate && card_index === state.highlighted.card);
|
const highlighted = useShopStore((state) => state.crates[crate_index].id === state.highlighted.crate && card_index === state.highlighted.card);
|
||||||
const options_disabled = useShopStore((state) => !!state.crateParams(state.crates[crate_index].crate_mode).warnings_disabled);
|
const warnings_disabled = useShopStore((state) => !!state.crateParams(state.crates[crate_index].crate_mode).warnings_disabled);
|
||||||
|
const use_options = useShopStore((state) => state.crateParams(state.crates[crate_index].crate_mode).options);
|
||||||
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
||||||
const setHighlight = useShopStore((state) => state.highlightCard);
|
const setHighlight = useShopStore((state) => state.highlightCard);
|
||||||
const removeHighlight = useShopStore((state) => state.highlightReset);
|
const removeHighlight = useShopStore((state) => state.highlightReset);
|
||||||
|
@ -35,9 +36,9 @@ export function ProductCartItem({card_index, crate_index, first, last}) {
|
||||||
console.log("ProductCartItem renders: ", renderCount)
|
console.log("ProductCartItem renders: ", renderCount)
|
||||||
|
|
||||||
|
|
||||||
const options = !options_disabled && card && card.options && card.options.length > 0;
|
const options = use_options && card && card[use_options] && card[use_options].length > 0;
|
||||||
const warnings = !options_disabled && card_show_warnings && card_show_warnings.length > 0;
|
const warnings = !warnings_disabled && card_show_warnings && card_show_warnings.length > 0;
|
||||||
const resources = !options_disabled && card_counted_resources && card_counted_resources.length > 0;
|
const resources = !warnings_disabled && card_counted_resources && card_counted_resources.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable draggableId={card.id} index={card_index}>
|
<Draggable draggableId={card.id} index={card_index}>
|
||||||
|
@ -72,8 +73,6 @@ export function ProductCartItem({card_index, crate_index, first, last}) {
|
||||||
<OptionsDialogWrapper
|
<OptionsDialogWrapper
|
||||||
crate_index={crate_index}
|
crate_index={crate_index}
|
||||||
card_index={card_index}
|
card_index={card_index}
|
||||||
first={first}
|
|
||||||
last={last}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {Draggable} from "@hello-pangea/dnd";
|
||||||
|
import {compareObjectsEmptiness, productStyle} from "./utils";
|
||||||
|
import {Resources} from "./Resources";
|
||||||
|
import {CardWarnings} from "./CardWarnings";
|
||||||
|
import {useShopStore} from "./shop_store";
|
||||||
|
import {OptionsDialogWrapper} from "./OptionsWrapper";
|
||||||
|
|
||||||
|
// #!render_count
|
||||||
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component that renders a product.
|
||||||
|
* Used in the crate
|
||||||
|
*/
|
||||||
|
export function ProductCartItemHorizontal({card_index, crate_index}) {
|
||||||
|
// #!render_count
|
||||||
|
const renderCount = useRenderCount();
|
||||||
|
|
||||||
|
|
||||||
|
const card = useShopStore((state) => state.crates[crate_index].h_items[card_index],
|
||||||
|
(a, b) => a.id === b.id);
|
||||||
|
|
||||||
|
const card_show_warnings = useShopStore(state => state.crates[crate_index].h_items[card_index].show_warnings, compareObjectsEmptiness);
|
||||||
|
const card_counted_resources = useShopStore(state => state.crates[crate_index].h_items[card_index].counted_resources, compareObjectsEmptiness);
|
||||||
|
|
||||||
|
const highlighted = useShopStore((state) => state.crates[crate_index].id === state.highlighted.crate && card_index === state.highlighted.card);
|
||||||
|
const warnings_disabled = useShopStore((state) => !!state.crateParams(state.crates[crate_index].crate_mode).warnings_disabled);
|
||||||
|
const use_options = useShopStore((state) => state.crateParams(state.crates[crate_index].crate_mode).options);
|
||||||
|
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
||||||
|
const setHighlight = useShopStore((state) => state.highlightCard);
|
||||||
|
const removeHighlight = useShopStore((state) => state.highlightReset);
|
||||||
|
const onCardRemove = useShopStore((state) => state.deleteCard);
|
||||||
|
|
||||||
|
// #!render_count
|
||||||
|
console.log("ProductCartItem renders: ", renderCount)
|
||||||
|
|
||||||
|
|
||||||
|
const options = use_options && card && card[use_options] && card[use_options].length > 0;
|
||||||
|
const warnings = !warnings_disabled && card_show_warnings && card_show_warnings.length > 0;
|
||||||
|
const resources = !warnings_disabled && card_counted_resources && card_counted_resources.length > 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Draggable draggableId={card.id} index={card_index}>
|
||||||
|
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<div
|
||||||
|
ref={provided.innerRef}
|
||||||
|
{...provided.draggableProps}
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
style={{
|
||||||
|
...productStyle(
|
||||||
|
provided.draggableProps.style,
|
||||||
|
snapshot,
|
||||||
|
true,
|
||||||
|
!!highlighted,
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onMouseEnter={() => setHighlight(crate_id, card_index)}
|
||||||
|
onMouseLeave={removeHighlight}
|
||||||
|
>
|
||||||
|
|
||||||
|
{/* warning container */}
|
||||||
|
|
||||||
|
<div className="progress-container warning d-flex justify-content-evenly">
|
||||||
|
{warnings &&
|
||||||
|
(<CardWarnings crate_index={crate_index} card_index={card_index} />)
|
||||||
|
}
|
||||||
|
|
||||||
|
{options && (
|
||||||
|
<OptionsDialogWrapper
|
||||||
|
crate_index={crate_index}
|
||||||
|
card_index={card_index}
|
||||||
|
horizontal={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h6>{card.name_number}</h6>
|
||||||
|
|
||||||
|
<div
|
||||||
|
onMouseEnter={() => setHighlight(crate_id, card_index)}
|
||||||
|
onClick={() => setHighlight(crate_id, card_index)}
|
||||||
|
>
|
||||||
|
|
||||||
|
{card.name}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* remove container */}
|
||||||
|
{/*<div
|
||||||
|
style={{'display': highlighted ? 'flex' : 'none'}}
|
||||||
|
className="overlayRemove"
|
||||||
|
onClick={() => onCardRemove(crate_id, card_index)}>
|
||||||
|
|
||||||
|
<img src="/images/shop/icon-remove.svg" alt="rm"/>
|
||||||
|
|
||||||
|
<p>Remove</p>
|
||||||
|
</div>*/}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</Draggable>
|
||||||
|
);
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ import {OptionsSummaryWrapper} from "./OptionsWrapper";
|
||||||
import {useRenderCount} from "@uidotdev/usehooks";
|
import {useRenderCount} from "@uidotdev/usehooks";
|
||||||
|
|
||||||
|
|
||||||
export function SummaryCrateCard({crate_index, card_index}) {
|
export function SummaryCrateCard({crate_index, card_index, horizontal}) {
|
||||||
// #!render_count
|
// #!render_count
|
||||||
const renderCount = useRenderCount();
|
const renderCount = useRenderCount();
|
||||||
|
|
||||||
|
@ -19,27 +19,33 @@ export function SummaryCrateCard({crate_index, card_index}) {
|
||||||
|
|
||||||
const highlighted = useShopStore((state) => state.crates[crate_index].id === state.highlighted.crate && card_index === state.highlighted.card);
|
const highlighted = useShopStore((state) => state.crates[crate_index].id === state.highlighted.crate && card_index === state.highlighted.card);
|
||||||
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
const crate_id = useShopStore((state) => state.crates[crate_index].id);
|
||||||
const card = useShopStore((state) => state.crates[crate_index].items[card_index],
|
const card = useShopStore((state) =>
|
||||||
|
horizontal ? state.crates[crate_index].h_items[card_index] : state.crates[crate_index].items[card_index],
|
||||||
(a, b) => a.id === b.id);
|
(a, b) => a.id === b.id);
|
||||||
const card_show_warnings = useShopStore(state => state.crates[crate_index].items[card_index].show_warnings, compareObjectsEmptiness);
|
// additional hooks for updating warning and options
|
||||||
const card_options_data = useShopStore(state => state.crates[crate_index].items[card_index].options_data, compareObjectsEmptiness);
|
const card_show_warnings = useShopStore(state =>
|
||||||
const options_disabled = useShopStore((state) => !!state.crateParams(state.crates[crate_index].crate_mode).warnings_disabled);
|
horizontal ? state.crates[crate_index].h_items[card_index].show_warnings : state.crates[crate_index].items[card_index].show_warnings,
|
||||||
|
compareObjectsEmptiness);
|
||||||
|
const card_options_data = useShopStore(state =>
|
||||||
|
horizontal ? state.crates[crate_index].h_items[card_index].options_data : state.crates[crate_index].items[card_index].options_data,
|
||||||
|
compareObjectsEmptiness);
|
||||||
|
const warnings_disabled = useShopStore((state) => !!state.crateParams(state.crates[crate_index].crate_mode).warnings_disabled);
|
||||||
|
const use_options = useShopStore((state) => state.crateParams(state.crates[crate_index].crate_mode).options);
|
||||||
|
|
||||||
// #!render_count
|
// #!render_count
|
||||||
console.log("SummaryCrateCard renders: ", renderCount)
|
console.log("SummaryCrateCard renders: ", renderCount)
|
||||||
|
|
||||||
|
|
||||||
const options = !options_disabled && card && card.options && card.options.length > 0;
|
const options = use_options && card && card[use_options] && card[use_options].length > 0;
|
||||||
const options_data = !options_disabled && card_options_data && Object.keys(card_options_data).length > 0;
|
const options_data = card_options_data && Object.keys(card_options_data).length > 0;
|
||||||
const warnings = !options_disabled && card_show_warnings && card_show_warnings.length > 0;
|
const warnings = !warnings_disabled && card_show_warnings && card_show_warnings.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={"summary_crate_" + crate_id + "_" + card_index}
|
key={"summary_crate_" + crate_id + "_" + card_index}
|
||||||
className={`hoverable ${highlighted ? 'selected' : ''}`}
|
className={`hoverable ${highlighted ? 'selected' : ''}`}
|
||||||
onClick={() => setHighlight(crate_id, card_index)}
|
onClick={() => setHighlight(crate_id, card_index, horizontal)}
|
||||||
onMouseEnter={() => setHighlight(crate_id, card_index)}
|
onMouseEnter={() => setHighlight(crate_id, card_index, horizontal)}
|
||||||
onMouseLeave={() => resetHighlight()}>
|
onMouseLeave={() => resetHighlight()}>
|
||||||
<td className="item-card-name tabbed">
|
<td className="item-card-name tabbed">
|
||||||
<div>{`${card.name_number} ${card.name} ${card.name_codename}`}</div>
|
<div>{`${card.name_number} ${card.name} ${card.name_codename}`}</div>
|
||||||
|
|
|
@ -21,10 +21,13 @@ export function validateJSON(description) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const crate of crates_raw) {
|
for (const crate of crates_raw) {
|
||||||
if (!crate.type || !crate.items || !crate.options || !(crate.type in crate_modes)) return false;
|
if (!crate.type || !crate.items || !crate.h_items || !crate.options || !(crate.type in crate_modes)) return false;
|
||||||
for (const card of crate.items) {
|
for (const card of crate.items) {
|
||||||
if (!(card.pn in pn_to_card) || card.options === undefined) return false;
|
if (!(card.pn in pn_to_card) || card.options === undefined) return false;
|
||||||
}
|
}
|
||||||
|
for (const card of crate.h_items) {
|
||||||
|
if (!(card.pn in pn_to_card) || card.options === undefined) return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -50,6 +53,11 @@ export function JSONToCrates(description) {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
options_data: card.options || {}
|
options_data: card.options || {}
|
||||||
}))),
|
}))),
|
||||||
|
h_items: Array.from(crate.h_items.map((card, _i) => ({
|
||||||
|
...pn_to_card(card.pn),
|
||||||
|
id: uuidv4(),
|
||||||
|
options_data: card.options || {}
|
||||||
|
}))),
|
||||||
warnings: [],
|
warnings: [],
|
||||||
occupiedHP: 0,
|
occupiedHP: 0,
|
||||||
})));
|
})));
|
||||||
|
@ -65,12 +73,17 @@ export function CratesToJSON(crates) {
|
||||||
const crateOptions = useShopStore.getState().crate_options;
|
const crateOptions = useShopStore.getState().crate_options;
|
||||||
const orderOptions = useShopStore.getState().order_options;
|
const orderOptions = useShopStore.getState().order_options;
|
||||||
const orderOptionsData = useShopStore.getState().order_options_data;
|
const orderOptionsData = useShopStore.getState().order_options_data;
|
||||||
|
const crateParams = useShopStore.getState().crateParams;
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
// additional fields can go here
|
// additional fields can go here
|
||||||
crates: Array.from(crates.map((crate, _i) => ({
|
crates: Array.from(crates.map((crate, _i) => ({
|
||||||
items: Array.from(crate.items.map((card, _) => ({
|
items: Array.from(crate.items.map((card, _) => ({
|
||||||
pn: card.name_number,
|
pn: card.name_number,
|
||||||
options: (card.options_data && card.options) ? FilterOptions(card.options, card.options_data) : null
|
options: (card.options_data && card[crateParams(crate.crate_mode).options]) ? FilterOptions(card[crateParams(crate.crate_mode).options], card.options_data) : null
|
||||||
|
}))),
|
||||||
|
h_items: Array.from(crate.h_items.map((card, _) => ({
|
||||||
|
pn: card.name_number,
|
||||||
|
options: (card.options_data && card[crateParams(crate.crate_mode).options]) ? FilterOptions(card[crateParams(crate.crate_mode).options], card.options_data) : null
|
||||||
}))),
|
}))),
|
||||||
type: crate.crate_mode,
|
type: crate.crate_mode,
|
||||||
options: FilterOptions(crateOptions, crate.options_data)
|
options: FilterOptions(crateOptions, crate.options_data)
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
import React, {useState} from "react";
|
import React, {useRef, useState} from "react";
|
||||||
import {useClickAway} from "./useClickAway";
|
|
||||||
import {ProcessOptions} from "./Options";
|
import {ProcessOptions} from "./Options";
|
||||||
import {Notification} from "./Notification";
|
import {Notification} from "./Notification";
|
||||||
|
import {Overlay} from "react-bootstrap";
|
||||||
|
|
||||||
export function DialogPopup({options, data, target, id, big, first, last, options_class,
|
export function DialogPopup({options, data, target, id, options_class,
|
||||||
sideMenuIsOpen, displayNotification, onHideNotification}) {
|
sideMenuIsOpen, displayNotification, onHideNotification, horizontal}) {
|
||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
const ref = useClickAway((e) => {
|
const ref = useRef(null);
|
||||||
if (e.type === "mousedown") // ignore touchstart
|
|
||||||
setShow(false)
|
let div_classes = `overlayVariant border rounded ${options_class || ""}`;
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let div_classes = `overlayVariant border rounded ${big ? "overlay-bigcard" : "overlay-smallcard"} ${(!big && first) ? "overlay-first" : ""} ${(!big && last && !first) ? "overlay-last" : ""} ${options_class || ""}`;
|
|
||||||
const handleClick = (_event) => {
|
const handleClick = (_event) => {
|
||||||
setShow(!show);
|
setShow(!show);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (<>
|
||||||
<div ref={ref}>
|
|
||||||
<Notification
|
<Notification
|
||||||
id={"processed_options_notification" + id}
|
id={"processed_options_notification" + id}
|
||||||
tip="Customization options available"
|
tip="Customization options available"
|
||||||
|
@ -26,12 +22,25 @@ export function DialogPopup({options, data, target, id, big, first, last, option
|
||||||
show={displayNotification}
|
show={displayNotification}
|
||||||
onHide={onHideNotification}
|
onHide={onHideNotification}
|
||||||
content={
|
content={
|
||||||
<img className="alert-info"
|
<img className="alert-info" ref={ref}
|
||||||
src={show ? "/images/shop/icon-close.svg" : "/images/shop/icon-customize.svg"}
|
src={show ? "/images/shop/icon-close.svg" : "/images/shop/icon-customize.svg"}
|
||||||
onClick={handleClick}/>
|
onClick={handleClick}/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div style={{'display': show ? 'flex' : 'none'}} className={div_classes}>
|
<Overlay target={ref.current}
|
||||||
|
show={show}
|
||||||
|
placement={horizontal ? "right" : "bottom"}
|
||||||
|
onHide={() => setShow(false)}
|
||||||
|
rootClose={true}>
|
||||||
|
{({
|
||||||
|
placement: _placement,
|
||||||
|
arrowProps: _arrowProps,
|
||||||
|
show: _show,
|
||||||
|
popper: _popper,
|
||||||
|
hasDoneInitialMeasure: _hasDoneInitialMeasure,
|
||||||
|
...props
|
||||||
|
}) => (
|
||||||
|
<div style={{'display': show ? 'flex' : 'none', ...props.style}} {...props} className={div_classes}>
|
||||||
<ProcessOptions
|
<ProcessOptions
|
||||||
options={options}
|
options={options}
|
||||||
data={data}
|
data={data}
|
||||||
|
@ -40,7 +49,8 @@ export function DialogPopup({options, data, target, id, big, first, last, option
|
||||||
target={target}
|
target={target}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
);
|
</Overlay>
|
||||||
|
</>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,35 @@ const ipv6 = (params) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hostname = (params) => {
|
||||||
|
const maxHostnameLength = 253;
|
||||||
|
const maxLabelLength = 63;
|
||||||
|
const labelRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$/;
|
||||||
|
|
||||||
|
return (text) => {
|
||||||
|
if (text.length > maxHostnameLength) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const labels = text.split('.');
|
||||||
|
for (const label of labels) {
|
||||||
|
if (label.length < 1
|
||||||
|
|| label.length > maxLabelLength
|
||||||
|
|| !labelRegex.test(label)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ipv4OrHost = (params) => {
|
||||||
|
const hostnameLocal = hostname(params);
|
||||||
|
const ipv4Local = ipv4(params);
|
||||||
|
return (text) => {
|
||||||
|
return ipv4Local(text) || hostnameLocal(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const ipv4or6 = (params) => {
|
const ipv4or6 = (params) => {
|
||||||
const ipv4Local = ipv4(params);
|
const ipv4Local = ipv4(params);
|
||||||
const ipv6Local = ipv6(params);
|
const ipv6Local = ipv6(params);
|
||||||
|
@ -47,5 +76,7 @@ export const Validation = {
|
||||||
ipv4: ipv4,
|
ipv4: ipv4,
|
||||||
ipv6: ipv6,
|
ipv6: ipv6,
|
||||||
ipv4or6: ipv4or6,
|
ipv4or6: ipv4or6,
|
||||||
|
hostname: hostname,
|
||||||
|
ipv4OrHost: ipv4OrHost,
|
||||||
frequency: frequency
|
frequency: frequency
|
||||||
};
|
};
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import {createWithEqualityFn} from "zustand/traditional";
|
import {createWithEqualityFn} from "zustand/traditional";
|
||||||
import {DATA as shared_data, itemsUnfoldedList, API_RFQ} from "./utils";
|
import {DATA as shared_data, itemsUnfoldedList, API_RFQ} from "./utils";
|
||||||
import {FillExtCrateData, FillExtOrderData, true_type_of} from "./options/utils";
|
import {FillExtCrateData, FillExtOrderData} from "./options/utils";
|
||||||
import {v4 as uuidv4} from "uuid";
|
import {v4 as uuidv4} from "uuid";
|
||||||
import {FillResources} from "./count_resources";
|
import {FillResources} from "./count_resources";
|
||||||
import {FillExtCardData} from "./options/utils";
|
import {FillExtCardData} from "./options/utils";
|
||||||
|
@ -13,12 +13,24 @@ import {ProcessOptionsToData} from "./options/Options";
|
||||||
import {DomainedRFQMessages} from "./Domained";
|
import {DomainedRFQMessages} from "./Domained";
|
||||||
|
|
||||||
|
|
||||||
|
export const HORIZONTAL_CART_MARKER = "_h";
|
||||||
|
|
||||||
const cards_to_pn_map = (cards) => {
|
const cards_to_pn_map = (cards) => {
|
||||||
let result = {};
|
let result = {};
|
||||||
Object.entries(cards).forEach(([key, card], _i) => { result[card.name_number] = key})
|
Object.entries(cards).forEach(([key, card], _i) => { result[card.name_number] = key})
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toArray = (arg) => {
|
||||||
|
return Array.isArray(arg) ? arg : [arg];
|
||||||
|
};
|
||||||
|
|
||||||
|
const unwrapCrateId = (crate_id= "") => {
|
||||||
|
return crate_id.endsWith(HORIZONTAL_CART_MARKER) ? [true, crate_id.substring(0, crate_id.length - HORIZONTAL_CART_MARKER.length)] : [false, crate_id]
|
||||||
|
}
|
||||||
|
|
||||||
|
const whichItems = (horizontal = false) => horizontal ? "h_items" : "items"
|
||||||
|
|
||||||
const useCatalog = ((set, get) => ({
|
const useCatalog = ((set, get) => ({
|
||||||
cards: shared_data.items,
|
cards: shared_data.items,
|
||||||
groups: shared_data.columns.catalog,
|
groups: shared_data.columns.catalog,
|
||||||
|
@ -33,21 +45,24 @@ const useCatalog = ((set, get) => ({
|
||||||
const useOptionsNotification = ((set, get) => ({
|
const useOptionsNotification = ((set, get) => ({
|
||||||
notificationCrateId: null,
|
notificationCrateId: null,
|
||||||
notificationCardIndex: null,
|
notificationCardIndex: null,
|
||||||
|
notificationHorizontal: false,
|
||||||
notificationTimer: null,
|
notificationTimer: null,
|
||||||
_showNotification: (crate_id, card_index) => set(state => ({
|
_showNotification: (crate_id, card_index, horizontal) => set(state => ({
|
||||||
notificationCrateId: crate_id,
|
notificationCrateId: crate_id,
|
||||||
notificationCardIndex: card_index,
|
notificationCardIndex: card_index,
|
||||||
|
notificationHorizontal: horizontal,
|
||||||
notificationTimer: setTimeout(() => {
|
notificationTimer: setTimeout(() => {
|
||||||
state.hideNotification()
|
state.hideNotification()
|
||||||
}, 5000)
|
}, 5000)
|
||||||
})),
|
})),
|
||||||
showNotification: (crate_id, card_index) => {
|
showNotification: (crate_id, card_index, horizontal) => {
|
||||||
get().hideNotification()
|
get().hideNotification()
|
||||||
setTimeout(() => get()._showNotification(crate_id, card_index), 100);
|
setTimeout(() => get()._showNotification(crate_id, card_index, horizontal), 100);
|
||||||
},
|
},
|
||||||
hideNotification: () => set(state => ({
|
hideNotification: () => set(state => ({
|
||||||
notificationCrateId: null,
|
notificationCrateId: null,
|
||||||
notificationCardIndex: null,
|
notificationCardIndex: null,
|
||||||
|
notificationHorizontal: false,
|
||||||
notificationTimer: (state.notificationTimer && clearTimeout(state.notificationTimer)) || null,
|
notificationTimer: (state.notificationTimer && clearTimeout(state.notificationTimer)) || null,
|
||||||
}))
|
}))
|
||||||
}));
|
}));
|
||||||
|
@ -211,7 +226,7 @@ const useImportJSON = ((set, get) => ({
|
||||||
get().fillExtCrateData(crate.id);
|
get().fillExtCrateData(crate.id);
|
||||||
});
|
});
|
||||||
get()._updateTotalOrderPrice();
|
get()._updateTotalOrderPrice();
|
||||||
get().showNotification(get().active_crate, null);
|
get().showNotification(get().active_crate, null, false);
|
||||||
},
|
},
|
||||||
updateImportDescription: (new_description) => set(state => ({
|
updateImportDescription: (new_description) => set(state => ({
|
||||||
importValue: {
|
importValue: {
|
||||||
|
@ -328,15 +343,17 @@ const useSubmitForm = ((set, get) => ({
|
||||||
const useHighlighted = ((set, get) => ({
|
const useHighlighted = ((set, get) => ({
|
||||||
highlighted: {
|
highlighted: {
|
||||||
crate: "",
|
crate: "",
|
||||||
card: 0
|
card: 0,
|
||||||
|
horizontal: false
|
||||||
},
|
},
|
||||||
highlightedTimer: null,
|
highlightedTimer: null,
|
||||||
|
|
||||||
// #!if disable_card_highlight === false
|
// #!if disable_card_highlight === false
|
||||||
highlightCard: (crate_id, index) => set(state => ({
|
highlightCard: (crate_id, index, horizontal) => set(state => ({
|
||||||
highlighted: {
|
highlighted: {
|
||||||
crate: crate_id,
|
crate: crate_id,
|
||||||
card: index
|
card: index,
|
||||||
|
horizontal: horizontal
|
||||||
},
|
},
|
||||||
highlightedTimer: (!!state.highlightedTimer ? clearTimeout(state.highlightedTimer) : null) || (state.isTouch && setTimeout(() => {
|
highlightedTimer: (!!state.highlightedTimer ? clearTimeout(state.highlightedTimer) : null) || (state.isTouch && setTimeout(() => {
|
||||||
get().highlightReset()
|
get().highlightReset()
|
||||||
|
@ -345,7 +362,8 @@ const useHighlighted = ((set, get) => ({
|
||||||
highlightReset: () => set(state => ({
|
highlightReset: () => set(state => ({
|
||||||
highlighted: {
|
highlighted: {
|
||||||
crate: "",
|
crate: "",
|
||||||
card: 0
|
card: 0,
|
||||||
|
horizontal: false
|
||||||
},
|
},
|
||||||
highlightedTimer: !!state.highlightedTimer ? clearTimeout(state.highlightedTimer) : null
|
highlightedTimer: !!state.highlightedTimer ? clearTimeout(state.highlightedTimer) : null
|
||||||
})),
|
})),
|
||||||
|
@ -384,17 +402,18 @@ const useCart = ((set, get) => ({
|
||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
setActiveCrate: (id) => set(state => ({active_crate: id})),
|
setActiveCrate: (id) => set(state => ({active_crate: id})),
|
||||||
_addCardFromCatalog: (crate_to, index_from, index_to) => set(state => {
|
_addCardFromCatalog: (crate_to, index_from, index_to, horizontal) => set(state => {
|
||||||
const take_from = (true_type_of(index_from) === "array" ? index_from : [index_from]).map((item, _i) => (state.cards_list[item]));
|
const whichH = whichItems(horizontal)
|
||||||
|
const take_from = toArray(index_from).map((item, _i) => (state.cards_list[item]));
|
||||||
const dest = crate_to || state.active_crate;
|
const dest = crate_to || state.active_crate;
|
||||||
if (!dest) return {};
|
if (!dest) return {};
|
||||||
return {
|
return {
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
if (dest === crate.id) {
|
if (dest === crate.id) {
|
||||||
index_to = index_to != null ? index_to : crate.items.length;
|
index_to = index_to != null ? index_to : crate[whichH].length;
|
||||||
return {
|
return {
|
||||||
...crate,
|
...crate,
|
||||||
items: crate.items.toSpliced(index_to, 0, ...take_from.map((card_name, _) => {
|
[whichH]: crate[whichH].toSpliced(index_to, 0, ...take_from.map((card_name, _) => {
|
||||||
return {...state.cards[card_name], id: uuidv4()}
|
return {...state.cards[card_name], id: uuidv4()}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -402,39 +421,41 @@ const useCart = ((set, get) => ({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
_moveCard: (crate_from, index_from, crate_to, index_to) => set(state => {
|
_moveCard: (crate_from, index_from, crate_to, index_to, horizontal) => set(state => {
|
||||||
const the_card = state.crates.find((crate, _) => crate_from === crate.id ).items[index_from];
|
const whichH = whichItems(horizontal)
|
||||||
|
const the_card = state.crates.find((crate, _) => crate_from === crate.id )[whichH][index_from];
|
||||||
return {
|
return {
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
if (crate_to === crate_from && crate_to === crate.id) {
|
if (crate_to === crate_from && crate_to === crate.id) {
|
||||||
let items_copy = Array.from(crate.items);
|
let items_copy = Array.from(crate[whichH]);
|
||||||
let item = items_copy.splice(index_from, 1)[0]
|
let item = items_copy.splice(index_from, 1)[0]
|
||||||
items_copy.splice(index_to, 0, item).filter((item, _) => !!item)
|
items_copy.splice(index_to, 0, item).filter((item, _) => !!item)
|
||||||
return {
|
return {
|
||||||
...crate,
|
...crate,
|
||||||
items: items_copy
|
[whichH]: items_copy
|
||||||
}
|
}
|
||||||
} else if (crate_to === crate.id) {
|
} else if (crate_to === crate.id) {
|
||||||
return {
|
return {
|
||||||
...crate,
|
...crate,
|
||||||
items: crate.items.toSpliced(index_to, 0, the_card)
|
[whichH]: crate[whichH].toSpliced(index_to, 0, the_card)
|
||||||
}
|
}
|
||||||
} else if (crate_from === crate.id) {
|
} else if (crate_from === crate.id) {
|
||||||
return {
|
return {
|
||||||
...crate,
|
...crate,
|
||||||
items: crate.items.toSpliced(index_to, 1)
|
[whichH]: crate[whichH].toSpliced(index_to, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return crate;
|
else return crate;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
_deleteCard: (crate_id, index) => set(state => ({
|
_deleteCard: (crate_id, index, horizontal) => set(state => ({
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
if (crate_id === crate.id) {
|
if (crate_id === crate.id) {
|
||||||
|
const whichH = whichItems(horizontal)
|
||||||
return {
|
return {
|
||||||
...crate,
|
...crate,
|
||||||
items: crate.items.toSpliced(index, 1)
|
[whichH]: crate[whichH].toSpliced(index, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return crate;
|
else return crate;
|
||||||
|
@ -445,7 +466,8 @@ const useCart = ((set, get) => ({
|
||||||
if (id === crate.id) {
|
if (id === crate.id) {
|
||||||
return {
|
return {
|
||||||
...crate,
|
...crate,
|
||||||
items: []
|
items: [],
|
||||||
|
h_items: []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return crate;
|
else return crate;
|
||||||
|
@ -454,10 +476,11 @@ const useCart = ((set, get) => ({
|
||||||
clearAll: () => set(state => ({
|
clearAll: () => set(state => ({
|
||||||
crates: state._defaultCrates
|
crates: state._defaultCrates
|
||||||
})),
|
})),
|
||||||
_updateOptions: (crate_id, index, new_options) => set(state => ({
|
_updateOptions: (crate_id, index, new_options, horizontal) => set(state => ({
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
if (crate_id === crate.id) {
|
if (crate_id === crate.id) {
|
||||||
let itemsCopy = Array.from(crate.items);
|
const whichH = whichItems(horizontal)
|
||||||
|
let itemsCopy = Array.from(crate[whichH]);
|
||||||
itemsCopy[index] = {
|
itemsCopy[index] = {
|
||||||
...itemsCopy[index],
|
...itemsCopy[index],
|
||||||
options_data: {
|
options_data: {
|
||||||
|
@ -466,7 +489,7 @@ const useCart = ((set, get) => ({
|
||||||
}};
|
}};
|
||||||
return {
|
return {
|
||||||
...crate,
|
...crate,
|
||||||
items: itemsCopy
|
[whichH]: itemsCopy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else return crate;
|
else return crate;
|
||||||
|
@ -496,10 +519,11 @@ const useCart = ((set, get) => ({
|
||||||
fillExtData: (crate_id) => set(state => ({
|
fillExtData: (crate_id) => set(state => ({
|
||||||
crates: state.crates.map((crate, _i) => {
|
crates: state.crates.map((crate, _i) => {
|
||||||
if (crate_id === crate.id) {
|
if (crate_id === crate.id) {
|
||||||
|
const options_name = state.crateParams(crate.crate_mode).options;
|
||||||
let itemsCopy = Array.from(crate.items);
|
let itemsCopy = Array.from(crate.items);
|
||||||
|
|
||||||
itemsCopy = itemsCopy.map((item, index) => {
|
itemsCopy = itemsCopy.map((item, index) => {
|
||||||
if (!item.options) return item;
|
if (!item[options_name]) return item;
|
||||||
if (!item.options_data) item.options_data = {};
|
if (!item.options_data) item.options_data = {};
|
||||||
item.options_data.ext_data = FillExtCardData(itemsCopy, index);
|
item.options_data.ext_data = FillExtCardData(itemsCopy, index);
|
||||||
return item;
|
return item;
|
||||||
|
@ -519,7 +543,7 @@ const useCart = ((set, get) => ({
|
||||||
sum += get().crate_modes[crate.crate_mode].price;
|
sum += get().crate_modes[crate.crate_mode].price;
|
||||||
const crate_options = ProcessOptionsToData({options: get().crate_prices, data: crate.options_data || {}});
|
const crate_options = ProcessOptionsToData({options: get().crate_prices, data: crate.options_data || {}});
|
||||||
sum += crate_options ? crate_options.reduce((accumulator, currentValue) => accumulator+currentValue.price, 0) : 0;
|
sum += crate_options ? crate_options.reduce((accumulator, currentValue) => accumulator+currentValue.price, 0) : 0;
|
||||||
crate.items.forEach((item, _) => {
|
crate.items.concat(crate.h_items).forEach((item, _) => {
|
||||||
sum += item.price;
|
sum += item.price;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -557,13 +581,15 @@ const useCart = ((set, get) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
addCardFromCatalog: (crate_to, index_from, index_to, just_mounted) => {
|
addCardFromCatalog: (crate_to, index_from, index_to, just_mounted) => {
|
||||||
const dest = crate_to || get().active_crate;
|
const isCrateless = toArray(index_from).some(value => get().getCardDescription(value).crateless === true);
|
||||||
|
const isHorizontal = toArray(index_from).some(value => !get().getCardDescription(value).image);
|
||||||
|
const dest = isCrateless ? "spare" : crate_to || get().active_crate;
|
||||||
if (!dest) {
|
if (!dest) {
|
||||||
console.warn("No destination");
|
console.warn("No destination");
|
||||||
get().noDestinationWarning();
|
get().noDestinationWarning();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
get().showNotification(dest, index_to);
|
get().showNotification(dest, index_to, isHorizontal);
|
||||||
get()._addCardFromCatalog(dest, index_from, index_to)
|
get()._addCardFromCatalog(dest, index_from, index_to)
|
||||||
get().fillExtData(dest);
|
get().fillExtData(dest);
|
||||||
get().fillWarnings(dest);
|
get().fillWarnings(dest);
|
||||||
|
@ -575,22 +601,25 @@ const useCart = ((set, get) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
moveCard: (crate_from, index_from, crate_to, index_to) => {
|
moveCard: (crate_from, index_from, crate_to, index_to) => {
|
||||||
get()._moveCard(crate_from, index_from, crate_to, index_to);
|
const [isHorizontal, crateFrom] = unwrapCrateId(crate_from)
|
||||||
get().fillExtData(crate_to);
|
const [_, crateTo] = unwrapCrateId(crate_to)
|
||||||
get().fillWarnings(crate_to);
|
get()._moveCard(crateFrom, index_from, crateTo, index_to, isHorizontal);
|
||||||
get().setActiveCrate(crate_to);
|
get().fillExtData(crateTo);
|
||||||
|
get().fillWarnings(crateTo);
|
||||||
|
get().setActiveCrate(crateTo);
|
||||||
get()._updateTotalOrderPrice();
|
get()._updateTotalOrderPrice();
|
||||||
if (crate_from !== crate_to) {
|
if (crateFrom !== crate_to) {
|
||||||
get().fillExtData(crate_from);
|
get().fillExtData(crateFrom);
|
||||||
get().fillWarnings(crate_from);
|
get().fillWarnings(crateFrom);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteCard: (crate_id, index) => {
|
deleteCard: (crate_id, index) => {
|
||||||
get()._deleteCard(crate_id, index);
|
const [isHorizontal, crateId] = unwrapCrateId(crate_id);
|
||||||
get().fillExtData(crate_id);
|
get()._deleteCard(crateId, index, isHorizontal);
|
||||||
get().fillWarnings(crate_id);
|
get().fillExtData(crateId);
|
||||||
|
get().fillWarnings(crateId);
|
||||||
get()._updateTotalOrderPrice();
|
get()._updateTotalOrderPrice();
|
||||||
if (crate_id === get().highlighted.crate && index === get().highlighted.card) get().highlightReset()
|
if (crateId === get().highlighted.crate && index === get().highlighted.card) get().highlightReset()
|
||||||
},
|
},
|
||||||
clearCrate: (id) => {
|
clearCrate: (id) => {
|
||||||
get()._clearCrate(id);
|
get()._clearCrate(id);
|
||||||
|
@ -599,7 +628,8 @@ const useCart = ((set, get) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
updateOptions: (crate_id, index, new_options) => {
|
updateOptions: (crate_id, index, new_options) => {
|
||||||
get()._updateOptions(crate_id, index, new_options);
|
const [isHorizontal, crateId] = unwrapCrateId(crate_id);
|
||||||
|
get()._updateOptions(crate_id, index, new_options, isHorizontal);
|
||||||
get().fillExtData(crate_id);
|
get().fillExtData(crate_id);
|
||||||
get().fillWarnings(crate_id);
|
get().fillWarnings(crate_id);
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,20 +6,23 @@ const shop_data = {
|
||||||
id: 'rack',
|
id: 'rack',
|
||||||
name: 'Rack mountable crate',
|
name: 'Rack mountable crate',
|
||||||
price: 550,
|
price: 550,
|
||||||
hp: 84
|
hp: 84,
|
||||||
|
options: "options"
|
||||||
},
|
},
|
||||||
desktop: {
|
desktop: {
|
||||||
id: 'desktop',
|
id: 'desktop',
|
||||||
name: 'Desktop crate',
|
name: 'Desktop crate',
|
||||||
price: 500,
|
price: 500,
|
||||||
hp: 42
|
hp: 42,
|
||||||
|
options: "options"
|
||||||
},
|
},
|
||||||
no_crate: {
|
no_crate: {
|
||||||
id: 'no_crate',
|
id: 'no_crate',
|
||||||
name: 'Spare cards',
|
name: 'Spare items',
|
||||||
price: 0,
|
price: 0,
|
||||||
hp: -1,
|
hp: -1,
|
||||||
warnings_disabled: true
|
warnings_disabled: true,
|
||||||
|
options: "crateless_options"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
crateModeOrder: [
|
crateModeOrder: [
|
||||||
|
@ -51,8 +54,8 @@ const shop_data = {
|
||||||
title: "Optional pre-installed NUC mini-computer",
|
title: "Optional pre-installed NUC mini-computer",
|
||||||
outvar: "nuc",
|
outvar: "nuc",
|
||||||
tip: "Pre-installed NixOS desktop with ARTIQ and other scientific software. " +
|
tip: "Pre-installed NixOS desktop with ARTIQ and other scientific software. " +
|
||||||
"Hardware: Intel® NUC 13 Pro Kit NUC13ANKi7, i7-1360P CPU, " +
|
"Hardware: ASUS® NUC 14 Pro Kit, Intel® i7-155H CPU, " +
|
||||||
"32GB RAM, 1TB NVMe. Other options contact us.",
|
"32GB RAM, 1TB NVMe. For other options contact us.",
|
||||||
fallback: true,
|
fallback: true,
|
||||||
}},
|
}},
|
||||||
{
|
{
|
||||||
|
@ -1103,10 +1106,24 @@ const shop_data = {
|
||||||
validator: {name: "ipv4or6"},
|
validator: {name: "ipv4or6"},
|
||||||
fallback: {text: "DHCP", checked: false},
|
fallback: {text: "DHCP", checked: false},
|
||||||
tip: "Set up IP address used by the device"}},
|
tip: "Set up IP address used by the device"}},
|
||||||
|
{type: "SwitchLine", args: {title: "MQTT broker address", outvar: "broker",
|
||||||
|
validator: {name: "ipv4OrHost"},
|
||||||
|
fallback: {text: "mqtt", checked: false},
|
||||||
|
tip: "Set up domain name or IPv4 of the MQTT broker"}},
|
||||||
{type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}},
|
{type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}},
|
||||||
{type: "Switch", args: {title: "Term #0", outvar: "term_0", tip: "Enable termination on ADC channel #0"}},
|
{type: "Switch", args: {title: "Term #0", outvar: "term_0", tip: "Enable termination on ADC channel #0"}},
|
||||||
{type: "Switch", args: {title: "Term #1", outvar: "term_1", tip: "Enable termination on ADC channel #1"}}
|
{type: "Switch", args: {title: "Term #1", outvar: "term_1", tip: "Enable termination on ADC channel #1"}}
|
||||||
],
|
],
|
||||||
|
crateless_options: [
|
||||||
|
{type: "SwitchLine", args: {title: "IP", outvar: "ip",
|
||||||
|
validator: {name: "ipv4or6"},
|
||||||
|
fallback: {text: "DHCP", checked: false},
|
||||||
|
tip: "Set up IP address used by the device"}},
|
||||||
|
{type: "SwitchLine", args: {title: "MQTT broker address", outvar: "broker",
|
||||||
|
validator: {name: "ipv4OrHost"},
|
||||||
|
fallback: {text: "mqtt", checked: false},
|
||||||
|
tip: "Set up domain name or IPv4 of the MQTT broker"}},
|
||||||
|
],
|
||||||
options_class: "stabilizer",
|
options_class: "stabilizer",
|
||||||
size: 'small',
|
size: 'small',
|
||||||
warnings: [
|
warnings: [
|
||||||
|
@ -1137,10 +1154,24 @@ const shop_data = {
|
||||||
validator: {name: "ipv4or6"},
|
validator: {name: "ipv4or6"},
|
||||||
fallback: {text: "DHCP", checked: false},
|
fallback: {text: "DHCP", checked: false},
|
||||||
tip: "Set up IP address used by the device"}},
|
tip: "Set up IP address used by the device"}},
|
||||||
|
{type: "SwitchLine", args: {title: "MQTT broker address", outvar: "broker",
|
||||||
|
validator: {name: "ipv4OrHost"},
|
||||||
|
fallback: {text: "mqtt", checked: false},
|
||||||
|
tip: "Set up domain name or IPv4 of the MQTT broker"}},
|
||||||
{type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}},
|
{type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}},
|
||||||
{type: "Switch", args: {title: "Term #0", outvar: "term_0", tip: "Enable termination on ADC channel #0"}},
|
{type: "Switch", args: {title: "Term #0", outvar: "term_0", tip: "Enable termination on ADC channel #0"}},
|
||||||
{type: "Switch", args: {title: "Term #1", outvar: "term_1", tip: "Enable termination on ADC channel #1"}}
|
{type: "Switch", args: {title: "Term #1", outvar: "term_1", tip: "Enable termination on ADC channel #1"}}
|
||||||
],
|
],
|
||||||
|
crateless_options: [
|
||||||
|
{type: "SwitchLine", args: {title: "IP", outvar: "ip",
|
||||||
|
validator: {name: "ipv4or6"},
|
||||||
|
fallback: {text: "DHCP", checked: false},
|
||||||
|
tip: "Set up IP address used by the device"}},
|
||||||
|
{type: "SwitchLine", args: {title: "MQTT broker address", outvar: "broker",
|
||||||
|
validator: {name: "ipv4OrHost"},
|
||||||
|
fallback: {text: "mqtt", checked: false},
|
||||||
|
tip: "Set up domain name or IPv4 of the MQTT broker"}},
|
||||||
|
],
|
||||||
options_class: "stabilizer",
|
options_class: "stabilizer",
|
||||||
size: 'small',
|
size: 'small',
|
||||||
warnings: [
|
warnings: [
|
||||||
|
@ -1226,7 +1257,25 @@ const shop_data = {
|
||||||
'100Base-T Ethernet with PoE.'
|
'100Base-T Ethernet with PoE.'
|
||||||
],
|
],
|
||||||
options: [
|
options: [
|
||||||
{type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}}
|
{type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}},
|
||||||
|
{type: "SwitchLine", args: {title: "Static IPv4", outvar: "ip",
|
||||||
|
validator: {name: "ipv4"},
|
||||||
|
fallback: {text: "0.0.0.0", checked: false},
|
||||||
|
tip: "Set up static IPv4 address used by the device"}},
|
||||||
|
{type: "SwitchLine", args: {title: "MQTT broker address", outvar: "broker",
|
||||||
|
validator: {name: "ipv4OrHost"},
|
||||||
|
fallback: {text: "mqtt", checked: false},
|
||||||
|
tip: "Set up domain name or IPv4 of the MQTT broker"}},
|
||||||
|
],
|
||||||
|
crateless_options: [
|
||||||
|
{type: "SwitchLine", args: {title: "Static IPv4", outvar: "ip",
|
||||||
|
validator: {name: "ipv4"},
|
||||||
|
fallback: {text: "0.0.0.0", checked: false},
|
||||||
|
tip: "Set up static IPv4 address used by the device"}},
|
||||||
|
{type: "SwitchLine", args: {title: "MQTT broker address", outvar: "broker",
|
||||||
|
validator: {name: "ipv4OrHost"},
|
||||||
|
fallback: {text: "mqtt", checked: false},
|
||||||
|
tip: "Set up domain name or IPv4 of the MQTT broker"}},
|
||||||
],
|
],
|
||||||
size: 'small',
|
size: 'small',
|
||||||
warnings: [
|
warnings: [
|
||||||
|
@ -1251,6 +1300,12 @@ const shop_data = {
|
||||||
'100Base-T Ethernet with PoE.',
|
'100Base-T Ethernet with PoE.',
|
||||||
'Can stabilize temperature of Sinara 5432 DAC or external devices containing TEC and thermistor.'
|
'Can stabilize temperature of Sinara 5432 DAC or external devices containing TEC and thermistor.'
|
||||||
],
|
],
|
||||||
|
crateless_options: [
|
||||||
|
{type: "SwitchLine", args: {title: "IPv4", outvar: "ip",
|
||||||
|
validator: {name: "ipv4"},
|
||||||
|
fallback: {text: "192.168.1.26/24", checked: false},
|
||||||
|
tip: "Set up IP address used by the device"}},
|
||||||
|
],
|
||||||
size: 'small',
|
size: 'small',
|
||||||
consumes: {
|
consumes: {
|
||||||
hp: 4
|
hp: 4
|
||||||
|
@ -1302,12 +1357,26 @@ const shop_data = {
|
||||||
validator: {name: "ipv4or6"},
|
validator: {name: "ipv4or6"},
|
||||||
fallback: {text: "DHCP", checked: false},
|
fallback: {text: "DHCP", checked: false},
|
||||||
tip: "Set up IP address used by the device"}},
|
tip: "Set up IP address used by the device"}},
|
||||||
|
{type: "SwitchLine", args: {title: "MQTT broker address", outvar: "broker",
|
||||||
|
validator: {name: "ipv4OrHost"},
|
||||||
|
fallback: {text: "mqtt", checked: false},
|
||||||
|
tip: "Set up domain name or IPv4 of the MQTT broker"}},
|
||||||
{type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}},
|
{type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}},
|
||||||
{type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk",
|
{type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk",
|
||||||
fallback: {text: "125 MHz", checked: false}, validator: {name: "frequency", params: {min: 10e6, max: 1e9}}}},
|
fallback: {text: "125 MHz", checked: false}, validator: {name: "frequency", params: {min: 10e6, max: 1e9}}}},
|
||||||
{type: "Switch", args: {title: "Termination #0", outvar: "term_0", tip: "Enable termination on ADC channel #0"}},
|
{type: "Switch", args: {title: "Termination #0", outvar: "term_0", tip: "Enable termination on ADC channel #0"}},
|
||||||
{type: "Switch", args: {title: "Termination #1", outvar: "term_1", tip: "Enable termination on ADC channel #1"}}
|
{type: "Switch", args: {title: "Termination #1", outvar: "term_1", tip: "Enable termination on ADC channel #1"}}
|
||||||
],
|
],
|
||||||
|
crateless_options: [
|
||||||
|
{type: "SwitchLine", args: {title: "Static IPv4", outvar: "ip",
|
||||||
|
validator: {name: "ipv4"},
|
||||||
|
fallback: {text: "0.0.0.0", checked: false},
|
||||||
|
tip: "Set up static IPv4 address used by the device"}},
|
||||||
|
{type: "SwitchLine", args: {title: "MQTT broker address", outvar: "broker",
|
||||||
|
validator: {name: "ipv4OrHost"},
|
||||||
|
fallback: {text: "mqtt", checked: false},
|
||||||
|
tip: "Set up domain name or IPv4 of the MQTT broker"}},
|
||||||
|
],
|
||||||
size: 'big',
|
size: 'big',
|
||||||
warnings: [
|
warnings: [
|
||||||
"no_eem_source",
|
"no_eem_source",
|
||||||
|
@ -1374,6 +1443,26 @@ const shop_data = {
|
||||||
hp: 8,
|
hp: 8,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'afws': {
|
||||||
|
id: 'afws',
|
||||||
|
name: 'Subscription',
|
||||||
|
name_number: 'AFWS',
|
||||||
|
name_codename: '',
|
||||||
|
price: 800,
|
||||||
|
image: null,
|
||||||
|
specs: [
|
||||||
|
"Artiq Firmware Service for one variant for one year.",
|
||||||
|
"Includes support at helpdesk.",
|
||||||
|
"Included with purchase of any Carrier with no additional cost.",
|
||||||
|
],
|
||||||
|
crateless: true,
|
||||||
|
crateless_options: [
|
||||||
|
{type: "Line", args: {title: "Variant name", outvar: "variant_name", fallback: "",
|
||||||
|
tip: "Variant name can be found on the sticker on top of the crate. If you don't have one, leave the preferred name here."}},
|
||||||
|
],
|
||||||
|
size: 'big',
|
||||||
|
warnings: [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
columns: {
|
columns: {
|
||||||
|
@ -1431,6 +1520,7 @@ const shop_data = {
|
||||||
'koster',
|
'koster',
|
||||||
'eem_pwr_mod',
|
'eem_pwr_mod',
|
||||||
'kirdy',
|
'kirdy',
|
||||||
|
'afws',
|
||||||
]}
|
]}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -1440,14 +1530,16 @@ const shop_data = {
|
||||||
crate_mode: "rack",
|
crate_mode: "rack",
|
||||||
fan_tray: false,
|
fan_tray: false,
|
||||||
items: [],
|
items: [],
|
||||||
|
h_items: [],
|
||||||
warnings: [],
|
warnings: [],
|
||||||
occupiedHP: 0,
|
occupiedHP: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "spare",
|
id: "spare",
|
||||||
name: "Spare cards",
|
name: "Spare items",
|
||||||
crate_mode: "no_crate",
|
crate_mode: "no_crate",
|
||||||
items: [],
|
items: [],
|
||||||
|
h_items: [],
|
||||||
warnings: [],
|
warnings: [],
|
||||||
occupiedHP: 0,
|
occupiedHP: 0,
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,12 +53,29 @@
|
||||||
<a href="{{ get_url(path='@/experiment-control/place-order.md') }}" class="btn btn-primary btn-inversed btn-lg">Order hardware</a>
|
<a href="{{ get_url(path='@/experiment-control/place-order.md') }}" class="btn btn-primary btn-inversed btn-lg">Order hardware</a>
|
||||||
<a href="https://m-labs.hk/artiq/manual/" class="btn btn-primary btn-lg">Manual</a>
|
<a href="https://m-labs.hk/artiq/manual/" class="btn btn-primary btn-lg">Manual</a>
|
||||||
<a href="https://forum.m-labs.hk" class="btn btn-primary btn-lg">Forum</a>
|
<a href="https://forum.m-labs.hk" class="btn btn-primary btn-lg">Forum</a>
|
||||||
<a href="https://nixbld.m-labs.hk/job/artiq/extra/msys2-offline-installer/latest/download/1" class="btn btn-primary btn-lg d-inline-flex">
|
|
||||||
<img src="/images/icons/icon-download.svg" class="d-inline-block align-self-center mx-1" style="height: 1rem" alt="download">
|
|
||||||
Windows installer
|
|
||||||
</a>
|
|
||||||
<a href="{{ get_url(path='@/experiment-control/artiq.md') }}" class="btn btn-primary btn-lg">More...</a>
|
<a href="{{ get_url(path='@/experiment-control/artiq.md') }}" class="btn btn-primary btn-lg">More...</a>
|
||||||
|
<div class="btn-group download-selector">
|
||||||
|
<a class="btn btn-primary btn-lg d-inline-flex" href="https://nixbld.m-labs.hk/job/artiq/extra/msys2-offline-installer/latest/download/1">
|
||||||
|
<img src="/images/icons/icon-windows.svg" class="d-inline-block align-self-center mx-1" style="height: 1rem" alt="windows">
|
||||||
|
<span class="d-inline-block">Download <sup>.exe</sup></span>
|
||||||
|
</a>
|
||||||
|
<div class="divider"></div>
|
||||||
|
<button type="button" class="btn btn-primary btn-lg dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<span>stable</span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu shadow dropdown-menu-end">
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="https://nixbld.m-labs.hk/job/artiq/extra/msys2-offline-installer/latest/download/1">
|
||||||
|
ARTIQ-8 (stable) for Windows
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item" href="https://nixbld.m-labs.hk/job/artiq/extra-beta/msys2-offline-installer/latest/download/1">
|
||||||
|
ARTIQ-9 (beta) for Windows
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue