lodash#groupBy JavaScript Examples

The following examples show how to use lodash#groupBy. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.js    From hzero-front with Apache License 2.0 6 votes vote down vote up
/**
   * 渲染执行器
   * @param {array} data - 执行器数据
   * @param {string} type - 初始化类型
   */
  @Bind()
  renderProcessors(data, type) {
    if (data) {
      const levelData = groupBy(data, 'orderSeq');
      const processorsContent = [];
      Object.keys(levelData).forEach(key => {
        const processors = this.squareWrapper(levelData[key]);
        if (type === 'post') processorsContent.push(this.line());
        processorsContent.push(processors);
        if (type === 'pre') processorsContent.push(this.line());
      });
      return processorsContent;
    }
  }
Example #2
Source File: Chart.js    From covid19 with MIT License 6 votes vote down vote up
calculateDayOffsets = (sortedDailyCounts = [], benchmarkCountryISO) => {
  const countryBenchmark = benchmarkCountryISO
  const countryCounts = groupBy(sortedDailyCounts, 'country.iso')
  const benchmarkCounts = countryCounts[countryBenchmark] || []
  const revBenchmarkCounts = reverse(benchmarkCounts)

  let countries = {}

  revBenchmarkCounts.forEach((count, i) => {
    if (i == revBenchmarkCounts.length - 1) return

    const currentCount = count
    const previousCount = revBenchmarkCounts[i + 1]

    for (const country in countryCounts) {
      const counts = countryCounts[country]

      counts.forEach((count) => {
        if (countries[country]) return

        if (
          count.totalCases < currentCount.totalCases &&
          count.totalCases > previousCount.totalCases
        ) {
          countries[country] = daysBetween(
            new Date(currentCount.date.date),
            new Date(count.date.date)
          )
        }
      })
    }
  })

  return countries
}
Example #3
Source File: data.js    From covid19-dashboard with MIT License 6 votes vote down vote up
export function reportToGeoJSON(report, date) {
  const byCode = groupBy(report.history, 'code')
  return {
    type: 'FeatureCollection',
    features: Object.keys(byCode).filter(code => Boolean(geo[code].center)).map(code => {
      const selectedDateAvailable = byCode[code].find(r => r.date === date)
      const properties = selectedDateAvailable ? selectedDateAvailable : {code}

      return {
        type: 'Feature',
        geometry: {
          type: 'Point',
          coordinates: geo[code].center
        },
        properties: {
          ...properties,
          ...byCode[code].find(r => r.date === date),
          history: byCode[code].filter(r => date >= r.date)
        }
      }
    }).filter(i => Boolean(i))
  }
}
Example #4
Source File: node-details-table.js    From ThreatMapper with Apache License 2.0 6 votes vote down vote up
function getSortedNodes(nodes, sortedByHeader, sortedDesc) {
  const getValue = getValueForSortedBy(sortedByHeader);
  const withAndWithoutValues = groupBy(nodes, (n) => {
    if (!n || n.valueEmpty) {
      return 'withoutValues';
    }
    const v = getValue(n);
    return v !== null && v !== undefined ? 'withValues' : 'withoutValues';
  });
  const withValues = sortNodes(withAndWithoutValues.withValues, getValue, sortedDesc);
  const withoutValues = sortNodes(withAndWithoutValues.withoutValues, getValue, sortedDesc);

  return concat(withValues, withoutValues);
}
Example #5
Source File: workflows.js    From holo-schedule with MIT License 6 votes vote down vote up
syncHotnesses = async (lives = []) => {
  if (lives.length === 0) {
    return
  }

  const hotnessesByLiveId = groupBy(await getHotnessesOfLives(lives, { limit: 1000 }), 'live_id')

  await store.set({
    [ENDED_LIVES]: (getCachedEndedLives() ?? []).map(live => {
      if (live['id'] in hotnessesByLiveId) {
        return { ...live, hotnesses: hotnessesByLiveId[live['id']] }
      }

      return live
    }),
  })
}
Example #6
Source File: summary-charts.js    From website with Apache License 2.0 6 votes vote down vote up
generateAnnotationNumbers = annotations => {
  const splitAnnotations = groupBy(annotations, a => a.dataElement)
  let asciiCode = 'A'.charCodeAt(0)
  const generateForField = field => {
    if (splitAnnotations[field]) {
      splitAnnotations[field] = splitAnnotations[field].map(a => ({
        ...a,
        date: parseDate(a.date),
        annotationSymbol: String.fromCharCode(asciiCode++),
      }))
    }
  }
  ;['tests', 'cases', 'hospitalizations', 'death'].forEach(generateForField) // death is the only non-plural on contentful
  return splitAnnotations
}
Example #7
Source File: node-details-table-row.js    From ThreatMapper with Apache License 2.0 6 votes vote down vote up
function getValuesForNode(node) {
  let values = {};
  ['metrics', 'metadata'].forEach((collection) => {
    if (node[collection]) {
      node[collection].forEach((field) => {
        const result = Object.assign({}, field);
        result.valueType = collection;
        values[field.id] = result;
      });
    }
  });

  if (node.parents) {
    const byTopologyId = groupBy(node.parents, parent => parent.topologyId);
    const relativesByTopologyId = mapValues(byTopologyId, (relatives, topologyId) => ({
      id: topologyId,
      label: topologyId,
      relatives,
      value: relatives.map(relative => relative.label).join(', '),
      valueType: 'relatives',
    }));

    values = {
      ...values,
      ...relativesByTopologyId,
    };
  }

  return values;
}
Example #8
Source File: node-details-table.js    From ThreatMapper with Apache License 2.0 6 votes vote down vote up
function getSortedNodes(nodes, sortedByHeader, sortedDesc) {
  const getValue = getValueForSortedBy(sortedByHeader);
  const withAndWithoutValues = groupBy(nodes, (n) => {
    if (!n || n.valueEmpty) {
      return 'withoutValues';
    }
    const v = getValue(n);
    return v !== null && v !== undefined ? 'withValues' : 'withoutValues';
  });
  const withValues = sortNodes(withAndWithoutValues.withValues, getValue, sortedDesc);
  const withoutValues = sortNodes(withAndWithoutValues.withoutValues, getValue, sortedDesc);

  return concat(withValues, withoutValues);
}
Example #9
Source File: index.js    From hzero-front with Apache License 2.0 5 votes vote down vote up
render() {
    const {
      tenantInitLog: { logList, pagination, enumMap, picData },
      listLoading,
      picLoading = false,
    } = this.props;
    const { currentLog, isShowImg } = this.state;
    let imgData = {};
    if (!isEmpty(picData)) {
      imgData = groupBy(orderBy(picData, 'orderSeq'), 'processorType');
    }
    const filterProps = {
      onSearch: this.handleSearch,
      onRef: this.handleBindRef,
      enumMap,
    };
    const listProps = {
      isShowImg,
      dataSource: logList,
      pagination,
      picProps: {
        dataSource: imgData,
        loading: picLoading,
        type: !isEmpty(currentLog) && currentLog.initType.toLowerCase(),
      },
      loading: listLoading,
      onChange: this.handleSearch,
      onSearchPic: this.handleSearchPic,
      onOpenPic: this.handleOpenImgModal,
      onClosePic: this.handleCloseImgModal,
    };
    return (
      <>
        <Header title={intl.get(`${viewTitle}.tenant.init.log`).d('租户初始化处理日志')} />
        <Content>
          <FilterForm {...filterProps} />
          <ListTable {...listProps} />
        </Content>
      </>
    );
  }
Example #10
Source File: dragAndDrop.js    From OctoFarm with GNU Affero General Public License v3.0 5 votes vote down vote up
export function dragAndDropGroupEnable(printers) {
  const groupedPrinters = mapValues(groupBy(printers, "group"));
  for (const key in groupedPrinters) {
    if (groupedPrinters.hasOwnProperty(key)) {
      if (key !== "") {
        const currentGroupEncoded = encodeURIComponent(key);
        const dropArea = document.getElementById(
          `dropPanel-${currentGroupEncoded}`
        );

        // Prevent default drag behaviors
        ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
          dropArea.addEventListener(eventName, preventDefaults, false);
          document.body.addEventListener(eventName, preventDefaults, false);
        });

        // Highlight drop area when item is dragged over it
        ["dragenter", "dragover"].forEach((eventName) => {
          dropArea.addEventListener(
            eventName,
            (event) => {
              activeFile = true;
              highlight(event, dropArea);
            },
            false
          );
        });
        ["dragleave", "drop"].forEach((eventName) => {
          dropArea.addEventListener(
            eventName,
            (event) => {
              activeFile = false;
              unhighlight(event, dropArea);
            },
            false
          );
        });
        dropArea.addEventListener(
          "drop",
          (event) => {
            handleMassDrop(event, groupedPrinters[key]);
          },
          false
        );
      }
    }
  }
}
Example #11
Source File: ChartData.js    From powir with GNU General Public License v3.0 5 votes vote down vote up
function getGroupedPowerUsageInfoData(info) {
    let formattedData = info.data.reduce((data, item, index) => {
        function getDuration(pastItem, currentItem, futureItem) {
            function getDateObject(dateString) {
                return new Date(dateString)
            }
            function getMidnightDateTime(date) {
                return new Date(date.toUTCString()).setHours(0, 0, 0, 0)
            }
            function getReturnItem(item, duration) {
                return [
                    item[0].split(" ")[0],
                    item[0].split(" ")[1],
                    duration / 1000 / 60,
                    item[1],
                    item[2]
                ]
            }
            let past = getDateObject(pastItem[0])
            let current = getDateObject(currentItem[0])
            let future = getDateObject(futureItem[0])
            if (past.getDate() === current.getDate()) {
                if (future.getDate() === current.getDate()) {
                    return [getReturnItem(currentItem, (future - current))]
                }
                return [getReturnItem(currentItem, (getMidnightDateTime(future) - current))]
            }
            else {
                if (future.getDate() === current.getDate()) {
                    return [[
                        currentItem[0].split(" ")[0],
                        "0:00:00",
                        (current - getMidnightDateTime(current)) / 1000 / 60,
                        'suspended',
                        null
                    ],
                        getReturnItem(currentItem, (future - current))
                    ]
                }
                return [[
                    currentItem[0].split(" ")[0],
                    "0:00:00",
                    (current - getMidnightDateTime(current)) / 1000 / 60,
                    'suspended',
                    null
                ],
                    getReturnItem(currentItem, (getMidnightDateTime(future) - current))
                ]
            }
        }
        switch (index) {
            case info.data.length-1:
                return data
            case 0:
                return data
            default:
                let durations = getDuration(
                    info.data[index-1],
                    item,
                    info.data[index+1]
                )
                durations.map(duration => data.push(duration))
                return data
        }
    }, [])
    return groupBy(formattedData, 0)
}
Example #12
Source File: index.js    From datapass with GNU Affero General Public License v3.0 5 votes vote down vote up
UserEnrollmentList = () => {
  const [isLoading, setIsLoading] = useState(true);
  const [enrollmentsByOrganization, setEnrollmentsByOrganization] = useState();

  const { goToItem } = useListItemNavigation();

  useEffect(() => {
    const onFetchData = async () => {
      setIsLoading(true);
      const enrollments = await getUserEnrollments();

      const enrollmentsByOrganization = groupBy(enrollments, (e) => e.siret);

      setEnrollmentsByOrganization(enrollmentsByOrganization);
      setIsLoading(false);
    };

    onFetchData();
  }, []);

  return (
    <main className="list-page">
      <ListHeader title="Toutes mes habilitations">
        <NewEnrollmentButton />
      </ListHeader>

      {isLoading && (
        <div className="full-page">
          <Loader />
        </div>
      )}

      {!isLoading && isEmpty(enrollmentsByOrganization) && (
        <div className="full-page">
          <Alert title="Vous n’avez aucune habilitation" />
        </div>
      )}

      {!isLoading && !isEmpty(enrollmentsByOrganization) && (
        <div className="page-container list-container">
          {Object.keys(enrollmentsByOrganization).map((group) => (
            <React.Fragment key={group}>
              <div className="list-title fr-text--lead">
                {enrollmentsByOrganization[group][0].nom_raison_sociale}
              </div>
              {enrollmentsByOrganization[group].map((enrollment) => (
                <Enrollment
                  key={enrollment.id}
                  {...enrollment}
                  onSelect={goToItem}
                />
              ))}
            </React.Fragment>
          ))}
        </div>
      )}
    </main>
  );
}
Example #13
Source File: node-details-table-row.js    From ThreatMapper with Apache License 2.0 5 votes vote down vote up
function getValuesForNode(node) {
  let values = {};
  ['metrics', 'metadata'].forEach(collection => {
    if (node[collection]) {
      node[collection].forEach(field => {
        const result = { ...field };
        result.valueType = collection;
        if (field.id === 'captureStatus') {
          const interfaceList =
            node[collection].filter(row => row.id === 'interfaceNames') || [];
          const { value = '' } = result;
          const match = value.match(/--input-raw ([^\s]+)/gm);
          let interfaceName = '';
          if (match && match.length >= 1) {
            const tempInterfaceName = match[0].split(' ')[1];
            const interfaceListArr = interfaceList[0].value || '';
            if (
              tempInterfaceName.trim().toLowerCase() === 'any' ||
              interfaceListArr.split(';').includes(tempInterfaceName)
            ) {
              interfaceName = tempInterfaceName;
            }
          }

          let captureStatusValue = 'Inactive';
          if (interfaceName) {
            captureStatusValue =
              interfaceName.trim().toLowerCase() !== 'any'
                ? `Active on ${interfaceName} interface`
                : 'Active on all interfaces';
          }
          values[field.id] = { ...result, value: captureStatusValue };
        } else if (field.id === 'user_defined_tags') {
          values[field.id] = {
            ...result,
            value: <TagModalTrigger value={result.value} node={node} />,
          };
        } else if (field.id === 'cloud_provider') {
          values[field.id] = {
            ...result,
            value: result.value || 'Private/On Prem',
          };
        } else {
          values[field.id] = result;
        }
      });
    }
  });

  if (node.parents) {
    const byTopologyId = groupBy(node.parents, parent => parent.topologyId);
    const relativesByTopologyId = mapValues(
      byTopologyId,
      (relatives, topologyId) => ({
        id: topologyId,
        label: topologyId,
        value: relatives.map(relative => relative.label).join(', '),
        valueType: 'relatives',
        relatives,
      })
    );

    values = {
      ...values,
      ...relativesByTopologyId,
    };
  }

  return values;
}
Example #14
Source File: index.js    From datapass with GNU Affero General Public License v3.0 4 votes vote down vote up
DonneesSection = ({
  DonneesDescription,
  availableScopes = [],
  AvailableScopesDescription,
  accessModes,
  enableFileSubmissionForScopeSelection = false,
}) => {
  const {
    disabled,
    onChange,
    enrollment: {
      scopes = {},
      data_recipients = '',
      data_retention_period = '',
      data_retention_comment = '',
      additional_content = {},
      documents = [],
      documents_attributes = [],
    },
  } = useContext(FormContext);

  useEffect(() => {
    if (!isEmpty(availableScopes) && isEmpty(scopes)) {
      onChange({
        target: {
          name: 'scopes',
          value: zipObject(
            availableScopes.map(({ value }) => value),
            availableScopes.map(
              ({ required, checkedByDefault }) =>
                !!required || !!checkedByDefault
            )
          ),
        },
      });
    }
  });

  const groupTitleScopesGroup = groupBy(
    availableScopes,
    (e) => e.groupTitle || 'default'
  );

  // {'a': true, 'b': false, 'c': true} becomes ['a', 'c']
  const scopesAsArray = chain(scopes)
    .omitBy((e) => !e)
    .keys()
    .value();
  const availableScopesAsArray = availableScopes.map(({ value }) => value);
  const outdatedScopes = difference(scopesAsArray, availableScopesAsArray);

  const [isFileInputExpanded, setFileInputExpanded] = useState(
    enableFileSubmissionForScopeSelection &&
      !isEmpty(
        documents.filter(
          ({ type }) => type === 'Document::ExpressionBesoinSpecifique'
        )
      )
  );

  useEffect(() => {
    const hasDocument = !isEmpty(
      documents.filter(
        ({ type }) => type === 'Document::ExpressionBesoinSpecifique'
      )
    );
    if (
      enableFileSubmissionForScopeSelection &&
      !isFileInputExpanded &&
      hasDocument
    ) {
      setFileInputExpanded(true);
    }
  }, [enableFileSubmissionForScopeSelection, isFileInputExpanded, documents]);

  return (
    <ScrollablePanel scrollableId={SECTION_ID}>
      <h2>Les données nécessaires</h2>
      {DonneesDescription && (
        <ExpandableQuote title="Comment choisir les données ?">
          <DonneesDescription />
        </ExpandableQuote>
      )}
      {AvailableScopesDescription && <AvailableScopesDescription />}
      {!isEmpty(availableScopes) && (
        <>
          <h3>À quelles données souhaitez-vous avoir accès ?</h3>
          {Object.keys(groupTitleScopesGroup).map((group) => (
            <Scopes
              key={group}
              title={group === 'default' ? null : group}
              scopes={groupTitleScopesGroup[group]}
              selectedScopes={scopes}
              disabledApplication={disabled}
              handleChange={onChange}
            />
          ))}
          {disabled && !isEmpty(outdatedScopes) && (
            <Scopes
              title="Les données suivantes ont été sélectionnées mais ne sont plus disponibles :"
              scopes={outdatedScopes.map((value) => ({ value, label: value }))}
              selectedScopes={zipObject(
                outdatedScopes,
                Array(outdatedScopes.length).fill(true)
              )}
              disabledApplication
              handleChange={() => null}
            />
          )}
        </>
      )}
      {enableFileSubmissionForScopeSelection && (
        <>
          <ExpandableQuote title="J’ai une expression de besoin spécifique ?">
            <p>
              Les partenaires ayant convenu avec la DGFiP un périmètre de
              données particulier peuvent rattacher leur expression de besoin
              listant l’ensemble des données strictement nécessaires à leur cas
              d’usage. Si vous n'avez pas encore contacté la DGFiP, vous pouvez
              les joindre à l'adresse{' '}
              <Link
                inline
                href="mailto:[email protected]?subject=Expression%20de%20besoin%20spécifique"
              >
                [email protected]
              </Link>
            </p>
            <CheckboxInput
              label="J’ai une expression de besoin spécifique"
              value={isFileInputExpanded}
              onChange={() => setFileInputExpanded(!isFileInputExpanded)}
              disabled={disabled}
            />
          </ExpandableQuote>
          {isFileInputExpanded && (
            <>
              <FileInput
                label="Joindre l’expression de besoin"
                meta={
                  'Attention : seule l’expression de besoin en données ayant déjà été partagée avec la DGFiP peut être rattachée à votre habilitation.'
                }
                mimeTypes="*"
                disabled={disabled}
                uploadedDocuments={documents}
                documentsToUpload={documents_attributes}
                documentType={'Document::ExpressionBesoinSpecifique'}
                onChange={onChange}
              />
            </>
          )}
        </>
      )}
      {!isEmpty(accessModes) && (
        <>
          <h3>Comment souhaitez-vous y accéder ?</h3>
          {accessModes.map(({ id, label }) => (
            <CheckboxInput
              key={id}
              label={label}
              name={`additional_content.${id}`}
              value={additional_content[id] || false}
              disabled={disabled}
              onChange={onChange}
            />
          ))}
        </>
      )}
      <h3>Comment seront traitées ces données personnelles ?</h3>
      <TextInput
        label="Destinataires des données"
        placeholder={
          '« agents instructeurs des demandes d’aides », « usagers des ' +
          'services publics de la ville », etc.'
        }
        meta={
          <Link
            inline
            newTab
            href="https://www.cnil.fr/fr/definition/destinataire"
            aria-label="Voir la définition CNIL du destinataire des données"
          >
            Plus d’infos
          </Link>
        }
        name="data_recipients"
        value={data_recipients}
        disabled={disabled}
        onChange={onChange}
        required
      />
      <NumberInput
        label="Durée de conservation des données en mois"
        meta={
          <Link
            inline
            newTab
            href="https://www.cnil.fr/fr/les-durees-de-conservation-des-donnees"
            aria-label="Voir l’explication CNIL sur les durées de conservation des données"
          >
            Plus d’infos
          </Link>
        }
        name="data_retention_period"
        value={data_retention_period}
        disabled={disabled}
        onChange={onChange}
        required
      />
      {data_retention_period > 36 && (
        <>
          <Alert type="warning" title="Attention">
            Cette durée excède la durée communément constatée (36 mois).
          </Alert>
          <TextInput
            label="Veuillez justifier cette durée dans le champ ci-après :"
            name="data_retention_comment"
            value={data_retention_comment}
            disabled={disabled}
            onChange={onChange}
          />
        </>
      )}
    </ScrollablePanel>
  );
}
Example #15
Source File: Chart.js    From covid19 with MIT License 4 votes vote down vote up
Chart = ({
  dailyCounts = [],
  countries = [],
  enabledCountries,
  defaultCountry
  // log
}) => {
  // sort dailyCounts for all later operations
  const sortedDailyCounts = orderBy(dailyCounts, 'date.date')
  const offsets = calculateDayOffsets(sortedDailyCounts, defaultCountry)

  const offsetDailyCounts = sortedDailyCounts.map((origCount) => {
    // deep clone
    let count = JSON.parse(JSON.stringify(origCount))

    let offset = offsets[count.country.iso]
    if (!offset) {
      return count
    } // in case of benchmark

    let newDate = addDays(new Date(count.date.date), offset)

    // round date to the nearest day
    let offsetForRounded = new Date(newDate.getTime() + 12 * 60 * 60)
    let roundedDate = new Date(
      offsetForRounded.getFullYear(),
      offsetForRounded.getMonth(),
      offsetForRounded.getDate()
    )

    // extract the YYYY-DD-MM portion
    count.date.date = new Date(
      roundedDate.toISOString().substring(0, 10)
    ).toISOString()

    return count
  })
  const sortedOffsetDailyCounts = orderBy(offsetDailyCounts, 'date.date')

  // Assemble chart display
  let days = {}

  sortedOffsetDailyCounts.forEach((count) => {
    days[count.date.date] = days[count.date.date] || {}

    days[count.date.date][`${count.country.iso}TotalCases`] = count.totalCases
    days[count.date.date][`${count.country.iso}TotalDeaths`] = count.totalDeaths
  })

  const countryCounts = groupBy(sortedDailyCounts, 'country.iso')
  // Highest date in benchmark country
  const maxBenchmarkDate = last(countryCounts[defaultCountry]).date.date

  // Calculate X axis numbers to show how many days ahead / behind a country is
  for (const day in days) {
    const daysBehind = daysBetween(new Date(day), new Date(maxBenchmarkDate))
    days[day]['daysBehind'] = daysBehind
  }

  const behindOrAhead =
    (last(Object.values(days))?.daysBehind || -1) > 0 ? 'ahead of' : 'behind'
  let updated = new Date(last(countryCounts[defaultCountry]).date.createdAt)
  updated.setDate(updated.getDate() + 1) // JS dates suck
  updated = updated
    .toLocaleDateString()
    .replace('/2020', '')
    .replace('2020-', '')

  // Prepare chart data
  const [chartData, setChartData] = useState([])
  useEffect(() => {
    setChartData(
      Object.keys(days).map((day) => ({
        date: day,
        ...days[day]
      }))
    )
  }, [dailyCounts])
  // Sorting
  useEffect(() => {
    setChartData((chartData) => orderBy(chartData, 'date'))
  }, [dailyCounts])

  return (
    <ResponsiveContainer height={512} id="primary">
      <LineChart
        data={chartData}
        margin={{ top: 0, right: 10, bottom: 25, left: 15 }}
      >
        <XAxis
          dataKey="daysBehind"
          label={{
            value: `Days ${behindOrAhead} ${countryFromKey(
              defaultCountry,
              countries
            )} (last updated: ${updated})`,
            position: 'bottom'
          }}
        />
        <YAxis
          tickFormatter={yAxisFormatter}
          label={{
            value: 'Total COVID-19 Cases',
            angle: -90,
            position: 'left'
          }}
        />
        <Tooltip
          separator=": "
          formatter={(value, key) => [
            commaNumber(value),
            countryFromKey(key, countries)
          ]}
        />
        <CartesianGrid stroke={theme.colors.snow} strokeDasharray="8 8" />
        {enabledCountries.map((iso) => (
          <Line
            key={iso}
            type="monotone"
            dataKey={`${iso}TotalCases`}
            stroke={theme.colors[iso]}
            strokeWidth={defaultCountry === iso ? 6 : 3}
            dot={false}
            activeDot={{ r: 8 }}
            connectNulls
          />
        ))}
        <style>{`
          .recharts-label {
            fill: ${theme.colors.muted};
          }
          .recharts-default-tooltip {
            border-radius: 0.375rem;
          }
          .recharts-tooltip-label {
            color: ${theme.colors.muted};
            font-family: ${theme.fonts.sans};
            font-size: 2rem;
            line-height: 1.5;
          }
          #primary .recharts-tooltip-label:after {
            content: ' days';
          }
          #primary .recharts-tooltip-item {
            font-family: ${theme.fonts.serif};
            font-size: 1rem;
          }
          @media (prefers-color-scheme: dark) {
            .recharts-default-tooltip {
              background-color: #1e1e1e !important;
            }
            .recharts-label {
              fill: ${theme.colors.snow};
            }
            .recharts-tooltip-label {
              color: ${theme.colors.snow};
            }
            .recharts-layer:not(.recharts-active-dot) .recharts-dot {
              fill: #1e1e1e !important;
            }
            line.recharts-cartesian-axis-line,
            line.recharts-cartesian-axis-tick-line,
            .recharts-cartesian-grid line {
              opacity: 0.25 !important;
            }
          }
        `}</style>
      </LineChart>
    </ResponsiveContainer>
  )
}
Example #16
Source File: ChartData.js    From powir with GNU General Public License v3.0 4 votes vote down vote up
function createBatteryLifeHistoryData(info) {
    function getDaysInMonth(date) {
        return new Date(date.getFullYear(), date.getMonth()+1, 0).getDate()
    }

    function chooseDate(date) {
        let [start_date, end_date] = date.split(" - ")
        if (getDaysInMonth(new Date(start_date)) - new Date(start_date).getDate() > new Date(end_date).getDate()) {
            return start_date.split("-").slice(0, 2).join("")
        }
        return end_date.split("-").slice(0, 2).join("")
    }

    function filterOutliers(array) {
        /*
        * Reference: https://www.mathworks.com/matlabcentral/cody/problems/42485-eliminate-outliers-using-interquartile-range
        * Following this approach except we aren't repeating the IQR and elimination process after every step.
        * */
        // Then sort
        // noinspection JSValidateTypes
        if (array.length < 4) {
            return {
                data: array,
                indexes: []
            }
        }
        // noinspection JSValidateTypes
        let values = sortBy(array)

        /* Then find a generous IQR. This is generous because if (values.length / 4)
         * is not an int, then really you should average the two elements on either
         * side to find q1.
         */
        let q1 = values[Math.floor((values.length / 4))]
        // Likewise for q3.
        let q3 = values[Math.ceil((values.length * (3 / 4)))]
        let iqr = q3 - q1;

        // Then find min and max values
        let maxValue = q3 + iqr*1.5;

        // Then reduce anything beyond or beneath these values.
        return array.reduce((data, item, index) => {
            if (item <= maxValue) {
                data.indexes.push(index)
                data.data.push(item)
                return data
            }
            return data
        }, {
            data: [],
            indexes: []
        })
    }

    function averageDatasetByMonth(value, index) {
        return value.reduce((data, element) => {
            data += element[index]
            return data
        }, 0) / value.length
    }

    let formattedInfo = groupBy(info.data.reduce((data, item) => {
        if (item[1] === "0:00:00" || item[3] === "0:00:00") {
            return data
        }
        data.push([
            chooseDate(item[0]),
            Number(item[1].split(":")[0])*60 + Number(item[1].split(":")[1]),
            Number(item[3].split(":")[0])*60 + Number(item[3].split(":")[1]),
        ])
        return data
    }, []), 0)

    let activeDataset = []
    let designDataset = []

    for (let [, value] of Object.entries(formattedInfo)) {
        activeDataset.push(averageDatasetByMonth(value, 1))
        designDataset.push(averageDatasetByMonth(value, 2))
    }
    let filteredDataset = filterOutliers(activeDataset)
    let filteredActiveDataset = filterOutliers(activeDataset).data
    let filteredDesignDataset = designDataset.filter((item, index) => filteredDataset.indexes.includes(index))
    let labelsDataset = Object.keys(formattedInfo).reduce((data, item, index) => {
        if (filteredDataset.indexes.includes(index)) {
            data.push(item.slice(0, 4) + "/" + item.slice(4, 6))
            return data
        }
        return data
    }, [])

    return {
        labels: labelsDataset,
        datasets: [{
            label: info.keys[1],
            backgroundColor: 'red',
            borderColor: 'red',
            data: filteredActiveDataset,
            fill: false,
        }, {
            label: info.keys[3],
            backgroundColor: 'blue',
            borderColor: 'blue',
            data: filteredDesignDataset,
            fill: false,
        }]
    }
}
Example #17
Source File: FederatedResults.js    From sampo-ui with MIT License 4 votes vote down vote up
FederatedResults = props => {
  const { rootUrl, perspective, screenSize, clientFSState, layoutConfig, portalConfig } = props
  const { searchMode } = perspective
  const perspectiveID = perspective.id
  const { maps } = clientFSState
  const { mapClusters, mapMarkers } = maps
  const layerControlExpanded = screenSize === 'md' ||
    screenSize === 'lg' ||
    screenSize === 'xl'
  let groupedResults = []
  if (props.location.pathname.endsWith('statistics')) {
    const grouped = groupBy(props.clientFSResults, clientFSState.groupBy)
    for (const key in grouped) {
      groupedResults.push({
        category: key,
        prefLabel: key,
        instanceCount: grouped[key].length
      })
    }
    groupedResults = orderBy(groupedResults, 'instanceCount', 'desc')
  }
  return (
    <>
      <PerspectiveTabs
        tabs={perspective.tabs}
        screenSize={props.screenSize}
        layoutConfig={layoutConfig}
      />
      <Route
        exact path={`${rootUrl}/${perspectiveID}/${searchMode}`}
        render={() => <Redirect to={`${rootUrl}/${perspectiveID}/${searchMode}/table`} />}
      />
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/table`}>
        <VirtualizedTable
          portalConfig={portalConfig}
          list={Immutable.List(props.clientFSResults)}
          clientFSState={props.clientFSState}
          clientFSSortResults={props.clientFSSortResults}
          perspectiveID={perspectiveID}
          layoutConfig={layoutConfig}
        />
      </Route>
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/map_clusters`}>
        <LeafletMap
          portalConfig={portalConfig}
          perspectiveConfig={perspective}
          center={mapClusters.center}
          zoom={mapClusters.zoom}
          results={props.clientFSResults}
          leafletMapState={props.leafletMapState}
          resultClass='mapClusters'
          pageType='clientFSResults'
          mapMode='cluster'
          createPopUpContent={props.leafletConfig.createPopUpContentNameSampo}
          fetchResults={props.fetchResults}
          fetchGeoJSONLayers={props.fetchGeoJSONLayers}
          clearGeoJSONLayers={props.clearGeoJSONLayers}
          fetchByURI={props.fetchByURI}
          fetching={false}
          showInstanceCountInClusters={false}
          updateFacetOption={props.updateFacetOption}
          showError={props.showError}
          showExternalLayers
          layerControlExpanded={layerControlExpanded}
          layerConfigs={props.leafletConfig.layerConfigs}
          updateMapBounds={props.updateMapBounds}
          layoutConfig={layoutConfig}
        />
      </Route>
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/map_markers`}>
        {props.clientFSResults.length < 500
          ? (
            <LeafletMap
              portalConfig={portalConfig}
              perspectiveConfig={perspective}
              center={mapMarkers.center}
              zoom={mapMarkers.zoom}
              results={props.clientFSResults}
              leafletMapState={props.leafletMapState}
              resultClass='mapMarkers'
              pageType='clientFSResults'
              mapMode='marker'
              createPopUpContent={props.leafletConfig.createPopUpContentNameSampo}
              fetchResults={props.fetchResults}
              fetchGeoJSONLayers={props.fetchGeoJSONLayers}
              clearGeoJSONLayers={props.clearGeoJSONLayers}
              fetchByURI={props.fetchByURI}
              fetching={false}
              showInstanceCountInClusters={false}
              updateFacetOption={props.updateFacetOption}
              showError={props.showError}
              showExternalLayers
              layerControlExpanded={layerControlExpanded}
              layerConfigs={props.leafletConfig.layerConfigs}
              updateMapBounds={props.updateMapBounds}
              layoutConfig={layoutConfig}
            />
            )
          : <ResultInfo message={intl.get('leafletMap.tooManyResults')} />}
      </Route>
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/statistics`}>
        <ApexCharts
          portalConfig={portalConfig}
          layoutConfig={layoutConfig}
          perspectiveConfig={props.perspectiveConfig}
          apexChartsConfig={props.apexChartsConfig}
          results={groupedResults}
          pageType='clientFSResults'
          facetUpdateID={props.clientFSState.facetUpdateID}
          resultClassConfig={{
            createChartData: 'createApexPieChartData',
            property: props.clientFSState.groupBy,
            title: {
              text: props.clientFSState.groupByLabel,
              align: 'left'
            }
          }}
        />
      </Route>
      <Route path={`${rootUrl}/${perspectiveID}/${searchMode}/download`}>
        <CSVButton
          results={props.clientFSResults}
          layoutConfig={layoutConfig}
          portalConfig={portalConfig}
        />
      </Route>

    </>
  )
}
Example #18
Source File: App.jsx    From course-plus with Apache License 2.0 4 votes vote down vote up
function App() {
  const [filterFormState, setFilterFormState] = useReducer(
    (state, newState) => ({ ...state, ...newState }),
    {
      checkedNj: new Set(),
      checkedLx: new Set(),
      checkedYx: new Set(),
      checkedTy: new Set(),
      scheduleKey: '',
      lecturerKey: '',
      placeKey: '',
      keywordType: 'kcmc',
      keyword: '',
      composition: '',
      notes: '',
    }
  )

  const [starLesson, setStarLesson] = useLocalStorageSet(
    'starLesson',
    new Set([])
  )
  const [selectedLesson, setSelectedLesson] = useLocalStorageSet(
    'selectedLesson',
    new Set([])
  )
  const [sjtuLesson, setSjtuLesson] = useLocalStorageSet(
    'sjtuLesson',
    new Set([])
  )
  const [sjtuLessonLoading, setSjtuLessonLoading] = useState(false)

  const [loginDialog, setLoginDialog] = useState(false)

  const removeStarLesson = (value) => {
    const set = new Set(starLesson)
    set.delete(value)
    setStarLesson(set)
    const set2 = new Set(selectedLesson)
    set2.delete(value)
    setSelectedLesson(set2)
  }

  const syncFromISJTU = (semester) => {
    setSjtuLessonLoading(true)
    axios
      .get(`/api/course/lesson?term=${semester.replace('_', '-')}`)
      .then((resp) => {
        if (resp?.data?.error === 'success') {
          setSjtuLesson(new Set(resp.data.entities.map((x) => x.code)))
          setSjtuLessonLoading(false)
        } else {
          setSjtuLessonLoading(false)
          setLoginDialog(true)
        }
      })
      .catch((e) => {
        setLoginDialog(true)
        setSjtuLessonLoading(false)
      })
  }

  const handleLogin = (result) => {
    if (result) {
      window.location.href = '/login?app=course_plus'
    }
    setLoginDialog(false)
  }

  const colorize = (starLesson) => {
    const colorScale = chroma.scale('Spectral').gamma(0.5)
    // const colorScale = chroma.scale(['yellow', 'navy']).mode('lch');
    const starLessonArray = [...starLesson]
    const result = {}
    forEach(
      groupBy(starLessonArray, (lesson) =>
        lesson.split('-').slice(0, 3).join('-')
      ),
      (v) => {
        const colors = colorScale.colors(v.length)
        sortedBy(v).forEach((val, idx) => (result[val] = colors[idx]))
      }
    )
    return result
  }

  return (
    <Router>
      <LoginModal show={loginDialog} nextStep={handleLogin}></LoginModal>

      <div className='container-fluid h-100'>
        <div className='row h-100'>
          <div className='col-md-3 d-none d-md-block h-100 bg-light overflow-auto'>
            <Switch>
              <Route exact path='/'>
                <Navbar />
              </Route>
              <Route path='/:semester'>
                <Navbar />
              </Route>
            </Switch>

            <div className='container'>
              <Switch>
                <Route exact path='/'>
                  <SemesterNav />
                </Route>
                <Route path='/:semester/:path'>
                  <SemesterNav />
                  <hr />
                </Route>
              </Switch>
              <Switch>
                <Route path='/:semester/browse'>
                  <FilterForm
                    state={filterFormState}
                    setState={setFilterFormState}
                  />
                </Route>
                <Route path='/:semester/plan'>
                  <PlanForm
                    starLesson={starLesson}
                    removeStarLesson={removeStarLesson}
                    state={selectedLesson}
                    setState={setSelectedLesson}
                    colorMapping={colorize(starLesson)}
                  />
                </Route>
                <Route path='/:semester/classtable'>
                  <ClassTableForm
                    sjtuLesson={sjtuLesson}
                    starLesson={starLesson}
                    setStarLesson={setStarLesson}
                    dataLoading={sjtuLessonLoading}
                    syncFromISJTU={syncFromISJTU}
                    colorMapping={colorize(sjtuLesson)}
                  />
                </Route>
              </Switch>

              <p className='text-muted my-3 small'>
                免责声明:本网站课程相关数据来自上海交通大学教学信息服务网。具体开课情况以教务网为准。
              </p>
              <p className='text-muted my-3 small'>
                隐私政策:访问本网站,即代表您同意本网站使用“站长统计”收集您的访问信息。根据相关法律法规,本站不对欧盟用户提供服务。
              </p>
              <div className='row'>
                <div className='col d-flex d-row align-items-center'>
                  <p className='text-muted my-3 small'>
                    <a href='https://github.com/SJTU-Plus/course-plus'>
                      本项目
                    </a>{' '}
                    由 <a href='https://plus.sjtu.edu.cn/'>SJTU-Plus</a> 维护。
                  </p>
                </div>
                <div className='col-auto m-0 p-0 d-flex d-row align-items-center'>
                  <GitHubButton
                    href='https://github.com/sjtu-plus/course-plus'
                    data-show-count
                    data-size='large'
                  >
                    Star
                  </GitHubButton>
                </div>
              </div>
            </div>
          </div>
          <div className='col-md-9 h-100 classtable-wrapper'>
            <div className='mb-3'>
              <Switch>
                <Route path='/:semester/browse'>
                  <ShowClassTable></ShowClassTable>
                </Route>
                <Route path='/:semester/plan'>
                  <ShowClassTable></ShowClassTable>
                </Route>
                <Route path='/:semester/classtable'>
                  <SyncButton
                    syncFromISJTU={syncFromISJTU}
                    dataLoading={sjtuLessonLoading}
                  ></SyncButton>
                </Route>
              </Switch>
            </div>
            <div className='classtable-frame w-100'>
              <Switch>
                <Route path='/:semester/browse'>
                  <LessonList
                    filterData={filterFormState}
                    state={starLesson}
                    setState={setStarLesson}
                  />
                </Route>
                <Route path='/:semester/plan'>
                  <ClassTable
                    selectedLesson={selectedLesson}
                    colorMapping={colorize(starLesson)}
                  />
                </Route>
                <Route path='/:semester/classtable'>
                  <ClassTable
                    selectedLesson={sjtuLesson}
                    colorMapping={colorize(sjtuLesson)}
                  />
                </Route>
              </Switch>
            </div>
          </div>
        </div>
      </div>
    </Router>
  )
}
Example #19
Source File: FilterChips.js    From edge-frontend with Apache License 2.0 4 votes vote down vote up
FilterChips = ({
  filterValues,
  setFilterValues,
  chipsArray,
  setChipsArray,
  setPage,
}) => {
  const buildChipsArray = () => {
    filterValues.forEach((filter) => {
      if (filter.type === 'checkbox') {
        filter.value.forEach((filterOption) => {
          if (
            filterOption.isChecked === true &&
            !chipsArray.find((chip) => chip.label === filterOption.option)
          ) {
            setChipsArray((prevState) => [
              ...prevState,
              {
                label: filterOption.option,
                value: filterOption.value || filterOption.option,
                apiName: filterOption.optionApiName,
                key: filter.label,
              },
            ]);
          } else if (
            filterOption.isChecked === false &&
            chipsArray.find((chip) => chip.label === filterOption.option)
          ) {
            setChipsArray((prevState) => {
              const index = prevState.findIndex(
                (state) => state.label === filterOption.option
              );
              return [
                ...prevState.slice(0, index),
                ...prevState.slice(index + 1, prevState.length),
              ];
            });
          }
        });
      }
      if (filter.type === 'text' && filter.value.length > 0) {
        const addTextFilter = { label: filter.value, key: filter.label };
        if (chipsArray.find((chip) => chip.key === filter.label)) {
          setChipsArray((prevState) =>
            prevState.map((f) => {
              return f.key === filter.label ? addTextFilter : f;
            })
          );
        } else {
          setChipsArray((prevState) => [...prevState, addTextFilter]);
        }
      } else if (
        filter.type === 'text' &&
        chipsArray.find((chip) => chip.key === filter.label)
      ) {
        setChipsArray((prevState) => {
          const index = prevState.findIndex(
            (state) => state.key === filter.label
          );
          return [
            ...prevState.slice(0, index),
            ...prevState.slice(index + 1, prevState.length),
          ];
        });
      }
    });
  };

  useEffect(() => {
    buildChipsArray();
    setPage(1);
  }, [filterValues]);

  const handleResetFilters = () => {
    setFilterValues((prevState) => {
      const removedValues = prevState.map((filter) => {
        if (filter.type === 'text') {
          return { ...filter, value: '' };
        }
        if (filter.type === 'checkbox') {
          const setFalse = filter.value.map((checkbox) => {
            checkbox.isChecked = false;
            return { ...checkbox, isChecked: false };
          });
          return { ...filter, value: setFalse };
        }
      });
      return removedValues;
    });
    setChipsArray([]);
  };

  const handleDeleteFilter = (filter) => {
    const filterLabelIndex = filterValues.findIndex(
      (value) => value.label === filter.key
    );
    setFilterValues((prevState) => {
      const changedValue = prevState[filterLabelIndex];
      if (changedValue.type === 'text') {
        return [
          ...prevState.slice(0, filterLabelIndex),
          { ...prevState[filterLabelIndex], value: '' },
          ...prevState.slice(filterLabelIndex + 1, prevState.length),
        ];
      }
      if (changedValue.type === 'checkbox') {
        const changeFalse = changedValue.value.map((option) =>
          option.option === filter.label
            ? { ...option, isChecked: false }
            : option
        );
        setChipsArray((prevState) => {
          const removeIndex = prevState.findIndex((state) => state === filter);
          return [
            ...prevState.slice(0, removeIndex),
            ...prevState.slice(removeIndex + 1, prevState.length),
          ];
        });
        return [
          ...prevState.slice(0, filterLabelIndex),
          { ...prevState[filterLabelIndex], value: changeFalse },
          ...prevState.slice(filterLabelIndex + 1, prevState.length),
        ];
      }
      return prevState;
    });
  };

  return (
    <>
      {chipsArray.length > 0
        ? Object.entries(groupBy(chipsArray, 'key')).map(([key, value]) => (
            <ChipGroup
              data-testid="filter-chip"
              className="pf-u-mr-xs"
              categoryName={key}
              key={key}
            >
              {value.map((filter) => (
                <Chip onClick={() => handleDeleteFilter(filter)} key={key}>
                  {filter.label}
                </Chip>
              ))}
            </ChipGroup>
          ))
        : null}
      {chipsArray.length > 0 ? (
        <Button variant="link" onClick={handleResetFilters}>
          Clear filters
        </Button>
      ) : null}
    </>
  );
}
Example #20
Source File: monitoring.updater.js    From OctoFarm with GNU Affero General Public License v3.0 4 votes vote down vote up
async function updateGroupState(printers, clientSettings, view) {
  const uniqueGroupList = [
    ...new Set(printers.map((printer) => printer.group)),
  ];
  uniqueGroupList.forEach((group) => {
    const cleanGroup = encodeURIComponent(group);
    const filteredGroupPrinterList = printers.filter((printer) => {
      if (encodeURIComponent(printer.group) === cleanGroup){
        return printer;
      }
    });
    checkGroupQuickConnectState(filteredGroupPrinterList, cleanGroup);
  })
  printers.forEach((printer, index) => {
    if (printer.group !== "" || !printer.disabled) {
      const elements = grabElements(printer);
      if (!elements?.row) return;
      elements.row.style.order = index;
      if (printer.display) {
        if (elements.row.style.display === "none") {
          switch (view) {
            case "list":
              elements.row.style.display = "table";
              break;
            case "panel":
              elements.row.style.display = "block";
              break;
            case "camera":
              elements.row.style.display = "block";
              break;
            case "group":
              elements.row.style.display = "flex";
              break;
            case "combined":
              elements.row.style.display = "flex";
              break;
          }
        }
      } else {
        if (elements.row.style.display !== "none") {
          elements.row.style.display = "none";
        }
        return;
      }

      let hideOffline = "";
      let hideClosed = "";

      if (!clientSettings?.views?.showDisconnected) {
        hideClosed = "hidden";
      }
      if (!clientSettings?.views?.showOffline) {
        hideOffline = "hidden";
      }

      if (printer.printerState.colour.category === "Active") {
        // Set the state
        if (elements.row.classList.contains(hideClosed)) {
          elements.row.classList.remove(hideClosed);
        }
        if (elements.row.classList.contains(hideOffline)) {
          elements.row.classList.remove(hideOffline);
        }
      } else if (
        printer.printerState.colour.category === "Idle" ||
        printer.printerState.colour.category === "Complete"
      ) {
        if (elements.row.classList.contains(hideClosed)) {
          elements.row.classList.remove(hideClosed);
        }
        if (elements.row.classList.contains(hideOffline)) {
          elements.row.classList.remove(hideOffline);
        }
      } else if (printer.printerState.state === "Disconnected") {
        if (hideClosed !== "") {
          elements.row.classList.add(hideClosed);
        }
      } else if (printer.printerState.colour.category === "Offline") {
        if (hideOffline !== "") {
          elements.row.classList.add(hideOffline);
        }
      }
      UI.doesElementNeedUpdating(
        printer.printerName,
        elements.name,
        "innerHTML"
      );
      UI.doesElementNeedUpdating(
        printer.printerState.state,
        elements.state,
        "innerHTML"
      );
      UI.doesElementNeedUpdating(
        `w-100 badge ${printer.printerState.colour.category}`,
        elements.state,
        "classList"
      );
    }
  });
  const groupedPrinters = mapValues(groupBy(printers, "group"));
  for (const key in groupedPrinters) {
    if (groupedPrinters.hasOwnProperty(key)) {
      if (key !== "") {
        const currentGroupEncoded = encodeURIComponent(key);
        const elements = grabGroupElements(currentGroupEncoded);
        const offlinePrinters = groupedPrinters[key].filter(
          (obj) => obj.printerState.colour.category === "Offline"
        ).length;
        const disconnectedPrinters = groupedPrinters[key].filter(
          (obj) => obj.printerState.state === "Disconnected"
        ).length;
        const idlePrinters = groupedPrinters[key].filter(
          (obj) => obj.printerState.colour.category === "Idle"
        ).length;
        const completePrinters = groupedPrinters[key].filter(
          (obj) => obj.printerState.colour.category === "Complete"
        ).length;
        const activePrinters = groupedPrinters[key].filter(
          (obj) => obj.printerState.colour.category === "Active"
        ).length;
        const pausedPrinters = groupedPrinters[key].filter(
          (obj) => obj.printerState.state === "Paused"
        ).length;
        const pausingPrinters = groupedPrinters[key].filter(
          (obj) =>
            obj.printerState.state === "Pausing" ||
            obj.printerState.state === "Cancelling"
        ).length;
        const filesSelected = groupedPrinters[key].filter(
          (obj) => obj?.currentJob?.fileName !== "No File Selected"
        ).length;

        let combinedProgress = groupedPrinters[key].reduce(function (a, b) {
          return a + b?.["currentJob"]?.["progress"];
        }, 0);

        const actualProgress = combinedProgress / groupedPrinters[key].length;
        UI.doesElementNeedUpdating(
          actualProgress.toFixed(0) + "%",
          elements.progress,
          "innerHTML"
        );
        elements.progress.style.width = actualProgress + "%";

        if (actualProgress < 100) {
          UI.doesElementNeedUpdating(
            "progress-bar progress-bar-striped bg-warning",
            elements.progress,
            "classList"
          );
        } else if (actualProgress === 100) {
          UI.doesElementNeedUpdating(
            "progress-bar progress-bar-striped bg-success",
            elements.progress,
            "classList"
          );
        }

        if (activePrinters === groupedPrinters[key].length) {
          //Set the buttons
          if (elements.start) {
            elements.start.disabled = true;
          }
          if (elements.stop) {
            elements.stop.disabled = false;
          }

          if (pausingPrinters === groupedPrinters[key].length) {
            if (elements.start) {
              elements.start.classList.remove("hidden");
            }
            if (elements.stop) {
              elements.stop.disabled = false;
            }
            if (elements.resume) {
              elements.resume.classList.add("hidden");
            }
            if (elements.pause) {
              elements.pause.disabled = true;
              elements.pause.classList.remove("hidden");
            }
            if (elements.restart) {
              elements.restart.disabled = true;
              elements.restart.classList.add("hidden");
            }
          } else if (pausedPrinters === groupedPrinters[key].length) {
            if (elements.start) {
              elements.start.classList.add("hidden");
            }
            if (elements.resume) {
              elements.resume.disabled = false;
              elements.resume.classList.remove("hidden");
            }
            if (elements.pause) {
              elements.pause.disabled = true;
              elements.pause.classList.add("hidden");
            }
            if (elements.restart) {
              elements.restart.disabled = false;

              elements.restart.classList.remove("hidden");
            }
          } else {
            if (elements.start) {
              elements.start.classList.remove("hidden");
            }

            if (elements.resume) {
              elements.resume.disabled = true;
              elements.resume.classList.add("hidden");
            }
            if (elements.pause) {
              elements.pause.disabled = false;
              elements.pause.classList.remove("hidden");
            }
            if (elements.restart) {
              elements.restart.disabled = true;
              elements.restart.classList.add("hidden");
            }
          }
        } else if (
          idlePrinters === groupedPrinters[key].length ||
          completePrinters === groupedPrinters[key].length
        ) {
          if (filesSelected === groupedPrinters[key].length) {
            if (elements.start) {
              elements.start.disabled = false;
            }
            if (elements.stop) {
              elements.stop.disabled = true;
            }
            if (elements.resume) {
              elements.resume.disabled = true;
            }
            if (elements.pause) {
              elements.pause.disabled = true;
            }
            if (elements.restart) {
              elements.restart.disabled = true;
            }
          } else {
            if (elements.start) {
              elements.start.disabled = true;
            }
            if (elements.stop) {
              elements.stop.disabled = true;
            }
            if (elements.resume) {
              elements.resume.disabled = true;
            }
            if (elements.pause) {
              elements.pause.disabled = true;
            }
            if (elements.restart) {
              elements.restart.disabled = true;
            }
          }
          if (pausedPrinters === groupedPrinters[key].length) {
            if (elements.start) {
              elements.start.classList.add("hidden");
            }
            if (elements.stop) {
              elements.stop.disabled = false;
            }
            if (elements.resume) {
              elements.resume.disabled = false;
              elements.resume.classList.remove("hidden");
            }
            if (elements.pause) {
              elements.pause.disabled = true;
              elements.pause.classList.add("hidden");
            }
            if (elements.restart) {
              elements.restart.disabled = false;
              elements.restart.classList.remove("hidden");
            }
          } else {
            if (elements.start) {
              elements.start.classList.remove("hidden");
            }
            if (elements.resume) {
              elements.resume.disabled = true;
              elements.resume.classList.add("hidden");
            }
            if (elements.pause) {
              elements.pause.disabled = true;
              elements.pause.classList.remove("hidden");
            }
            if (elements.restart) {
              elements.restart.disabled = true;
              elements.restart.classList.add("hidden");
            }
          }
        } else if (disconnectedPrinters === groupedPrinters[key].length) {
          if (elements.start) {
            elements.start.disabled = true;
            elements.start.classList.remove("hidden");
          }
          if (elements.stop) {
            elements.stop.disabled = true;
          }
          if (elements.resume) {
            elements.resume.disabled = true;
            elements.resume.classList.add("hidden");
          }
          if (elements.pause) {
            elements.pause.disabled = true;
            elements.pause.classList.remove("hidden");
          }
          if (elements.restart) {
            elements.restart.disabled = true;
            elements.restart.classList.add("hidden");
          }
        } else if (offlinePrinters === groupedPrinters[key].length) {
          if (elements.start) {
            elements.start.disabled = true;
            elements.start.classList.remove("hidden");
          }
          if (elements.stop) {
            elements.stop.disabled = true;
          }
          if (elements.resume) {
            elements.resume.disabled = true;
            elements.resume.classList.add("hidden");
          }
          if (elements.pause) {
            elements.pause.disabled = true;
            elements.pause.classList.remove("hidden");
          }
          if (elements.restart) {
            elements.restart.disabled = true;
            elements.restart.classList.add("hidden");
          }
        }
      }
    }
  }
}
Example #21
Source File: monitoring.updater.js    From OctoFarm with GNU Affero General Public License v3.0 4 votes vote down vote up
function addGroupListeners(printers) {
  const groupedPrinters = mapValues(groupBy(printers, "group"));
  for (const key in groupedPrinters) {
    if (groupedPrinters.hasOwnProperty(key)) {
      const currentGroupEncoded = encodeURIComponent(key);
      //Play button listeners
      let playBtn = document.getElementById("play-" + currentGroupEncoded);
      if (playBtn) {
        playBtn.addEventListener("click", async (e) => {
          e.target.disabled = true;
          for (const printer of groupedPrinters[key]) {
            const opts = {
              command: "start",
            };
            const print = returnPrinterInfo(printer._id);
            const { status } = await OctoPrintClient.jobAction(print, opts, e);
            printActionStatusResponse(status, "print");
          }
        });
      }
      let cancelBtn = document.getElementById("cancel-" + currentGroupEncoded);
      if (cancelBtn) {
        cancelBtn.addEventListener("click", (e) => {
          bootbox.confirm({
            message: "Are you sure you want to cancel the ongoing prints?",
            buttons: {
              cancel: {
                label: "<i class=\"fa fa-times\"></i> Cancel",
              },
              confirm: {
                label: "<i class=\"fa fa-check\"></i> Confirm",
              },
            },
            async callback(result) {
              if (result) {
                e.target.disabled = true;
                for (const printer of groupedPrinters[key]) {
                  const print = returnPrinterInfo(printer._id);
                  const opts = {
                    command: "cancel",
                  };
                  const { status } = await OctoPrintClient.jobAction(
                    print,
                    opts,
                    e
                  );
                  printActionStatusResponse(status, "cancel");
                }
              }
            },
          });
        });
      }
      let restartBtn = document.getElementById(
        "restart-" + currentGroupEncoded
      );
      if (restartBtn) {
        restartBtn.addEventListener("click", async (e) => {
          e.target.disabled = true;
          for (const printer of groupedPrinters[key]) {
            const opts = {
              command: "restart",
            };
            const print = returnPrinterInfo(printer._id);
            const { status } = await OctoPrintClient.jobAction(print, opts, e);
            printActionStatusResponse(status, "restart");
          }
        });
      }
      let pauseBtn = document.getElementById("pause-" + currentGroupEncoded);
      if (pauseBtn) {
        pauseBtn.addEventListener("click", async (e) => {
          e.target.disabled = true;
          for (const printer of groupedPrinters[key]) {
            const opts = {
              command: "pause",
              action: "pause",
            };
            const print = returnPrinterInfo(printer._id);
            const { status } = await OctoPrintClient.jobAction(print, opts, e);
            printActionStatusResponse(status, "pause");
          }
        });
      }
      let resumeBtn = document.getElementById("resume-" + currentGroupEncoded);
      if (resumeBtn) {
        resumeBtn.addEventListener("click", async (e) => {
          e.target.disabled = true;
          for (const printer of groupedPrinters[key]) {
            const opts = {
              command: "pause",
              action: "resume",
            };
            const print = returnPrinterInfo(printer._id);
            const { status } = await OctoPrintClient.jobAction(print, opts, e);
            printActionStatusResponse(status, "resume");
          }
        });
      }
      let filesBtn = document.getElementById(
        "unifiedFiles-" + currentGroupEncoded
      );
      if (filesBtn) {
        filesBtn.addEventListener("click", async () => {
          const idList = [];
          for (const printer of groupedPrinters[key]) {
            idList.push(printer._id);
          }
          const fileList = await OctoFarmClient.get(
            "printers/listUnifiedFiles/" + JSON.stringify(idList)
          );
          drawGroupFiles(fileList);
        });
      }
    }
  }

  return "done";
}