lodash#sumBy TypeScript Examples

The following examples show how to use lodash#sumBy. 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: yml-chart-utils.tsx    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
getNodePostion = (data: IData[][], chartConfig: IChartConfig, external: IExternal) => {
  const { PADDING, NODE, MARGIN } = chartConfig;
  const nodeData = [] as IData[][];
  const isEdit = external && external.editing;
  const boxSizeArr = map(data, (item) => {
    return {
      width:
        PADDING.X * 2 +
        (item.length - 1) * MARGIN.X +
        sumBy(
          item,
          (subItem: IData) => (get(NODE, `${subItem[externalKey].nodeType}.WIDTH`) as unknown as number) || 0,
        ),
      height: get(NODE, `${get(item, `[0].${externalKey}.nodeType`)}.HEIGHT`) as unknown as number,
      itemWidth: get(NODE, `${get(item, `[0].${externalKey}.nodeType`)}.WIDTH`) as unknown as number,
    };
  });
  const maxWidthBox = (maxBy(boxSizeArr, (item) => item.width) as Obj) || { width: 0, height: 0 };
  const dataLen = data.length;
  let chartHeight = PADDING.Y;
  map(data, (item, index) => {
    const curBoxSize = boxSizeArr[index];
    const curData = [] as any[];
    let xDis = (curBoxSize.width < maxWidthBox.width ? (maxWidthBox.width - curBoxSize.width) / 2 : 0) + PADDING.X;
    map(item, (subItem, subIndex) => {
      const curNode = NODE[subItem[externalKey].nodeType] as any;
      curData.push({
        ...subItem,
        [externalKey]: {
          ...(subItem[externalKey] || {}),
          x: xDis + curNode.WIDTH / 2,
          y: chartHeight + curNode.HEIGHT / 2,
          nodeId: `node-${index}-${subIndex}`,
          width: curNode.WIDTH,
          height: curNode.HEIGHT,
        },
      });
      xDis += curNode.WIDTH + MARGIN.X;
    });
    chartHeight += curBoxSize.height + (dataLen === index + 1 ? 0 : MARGIN.Y);
    nodeData.push(curData);
  });
  chartHeight += PADDING.Y;
  return {
    chartHeight,
    chartWidth: isEdit ? maxWidthBox.width + maxWidthBox.itemWidth + MARGIN.X : maxWidthBox.width,
    nodeData,
  } as {
    chartHeight: number;
    chartWidth: number;
    nodeData: IExternalData[][];
  };
}
Example #2
Source File: linear-distribution.tsx    From erda-ui with GNU Affero General Public License v3.0 6 votes vote down vote up
CP_LINEAR_DISTRIBUTION = (props: CP_LINEAR_DISTRIBUTION.Props) => {
  const { props: configProps, data } = props;
  const { size = 'normal' } = configProps || {};
  const { list, total: _total } = data || {};
  const total = _total ?? sumBy(list, 'value');

  const labelArr: JSX.Element[] = [];
  const linearArr: JSX.Element[] = [];
  list?.forEach((item, idx) => {
    const { tip, label, color, value, status } = item;
    const _color = colorMap[color] || statusColorMap[status] || color;
    labelArr.push(
      <div key={`${idx}`} className="cp-linear-distribution-label flex justify-items-center items-center">
        <span className="label-dot rounded-full" style={{ backgroundColor: _color }} />
        <span>{label}</span>
      </div>,
    );
    linearArr.push(
      <Tooltip title={tip} key={`${idx}`}>
        <div className={'h-full cp-linear-distribution-item bg-white'} style={{ width: `${(value / total) * 100}%` }}>
          <span className="block h-full w-full" style={{ backgroundColor: _color }} />
        </div>
      </Tooltip>,
    );
  });

  return (
    <div className="my-4">
      <div className="mb-2 flex">{labelArr}</div>
      <div className={`w-full cp-linear-distribution size-${size}`}>{linearArr}</div>
    </div>
  );
}
Example #3
Source File: surveys.ts    From aqualink-app with MIT License 6 votes vote down vote up
findImagesAtSurveyPoint = (
  surveyList: SurveyListItem[],
  point: number
) => {
  const imagesAtPoint = surveyList.map(
    (survey) => survey.surveyPointImage?.[point]
  );
  if (imagesAtPoint.length > 0) {
    return sumBy(imagesAtPoint, "length");
  }
  return 0;
}
Example #4
Source File: file.utils.ts    From WowUp with GNU General Public License v3.0 6 votes vote down vote up
export async function getDirTree(sourcePath: string, opts?: GetDirectoryTreeOptions): Promise<TreeNode> {
  let hardPath = sourcePath;

  // Check if a symlink was passed in, if so get the actual path
  let dirStats = await fsp.lstat(sourcePath);
  if (dirStats.isSymbolicLink()) {
    hardPath = await fsp.readlink(sourcePath);
  }

  // Verify that a directory was passed in
  dirStats = await fsp.lstat(hardPath);
  if (!dirStats.isDirectory()) {
    throw new Error(`getDirTree path was not a directory: ${hardPath}`);
  }

  const files = await fsp.readdir(hardPath, { withFileTypes: true });

  const node: TreeNode = {
    name: path.basename(hardPath),
    path: hardPath,
    children: [],
    isDirectory: true,
    size: 0,
  };

  for (const file of files) {
    const filePath = path.join(hardPath, file.name);
    if (file.isDirectory()) {
      const nestedNode = await getDirTree(filePath, opts);
      node.children.push(nestedNode);
      node.size = sumBy(node.children, (n) => n.size);
      if (opts?.includeHash) {
        node.hash = hashString(node.children.map((n) => n.hash).join(""), "sha256");
      }
    } else {
      let hash = "";
      if (opts?.includeHash) {
        hash = await hashFile(filePath, "sha256");
      }

      const stats = await fsp.stat(filePath);
      node.size += stats.size;
      node.children.push({
        name: file.name,
        path: filePath,
        children: [],
        isDirectory: false,
        size: stats.size,
        hash,
      });
    }
  }

  if (opts?.includeHash) {
    node.hash = hashString(node.children.map((n) => n.hash).join(""), "sha256");
  }

  return node;
}
Example #5
Source File: ClaimPointsCallout .tsx    From vvs-ui with GNU General Public License v3.0 5 votes vote down vote up
ClaimPointsCallout = () => {
  const [claimableAchievements, setClaimableAchievement] = useState<Achievement[]>([])
  const { t } = useTranslation()
  const dispatch = useAppDispatch()
  const { profile } = useProfile()
  const { account } = useWeb3React()

  useEffect(() => {
    const fetchIfoClaims = async () => {
      const ifoData = await getClaimableIfoData(account)
      setClaimableAchievement(ifoData)
    }

    if (account) {
      fetchIfoClaims()
    }
  }, [account, dispatch, setClaimableAchievement])

  const handleCollectSuccess = (achievement: Achievement) => {
    dispatch(addAchievement(achievement))
    dispatch(addPoints(achievement.points))

    setClaimableAchievement((prevClaimableAchievements) =>
      prevClaimableAchievements.filter((prevClaimableAchievement) => prevClaimableAchievement.id !== achievement.id),
    )
  }

  if (!profile?.isActive) {
    return null
  }

  if (claimableAchievements.length === 0) {
    return null
  }

  const totalPointsToCollect = sumBy(claimableAchievements, 'points')

  return (
    <Card isActive mb="32px">
      <CardHeader>
        <Flex flexDirection={['column', null, 'row']} justifyContent={['start', null, 'space-between']}>
          <Flex alignItems="center" mb={['16px', null, 0]}>
            <PrizeIcon width="32px" mr="8px" />
            <Heading scale="lg">{t('%num% Points to Collect', { num: totalPointsToCollect })}</Heading>
          </Flex>
        </Flex>
      </CardHeader>
      <CardBody>
        {claimableAchievements.map((achievement) => (
          <AchievementRow key={achievement.address} achievement={achievement} onCollectSuccess={handleCollectSuccess} />
        ))}
      </CardBody>
    </Card>
  )
}
Example #6
Source File: bitrise_analyzer.ts    From CIAnalyzer with MIT License 5 votes vote down vote up
createWorkflowReport(app: App, build: BuildResponse, buildLog: BuildLogResponse | null): WorkflowReport {
    const { workflowId, workflowRunId, buildNumber, workflowName }
      = this.createWorkflowParams(app, build)
    const createdAt = new Date(build.triggered_at)
    const startedAt = new Date(build.started_on_worker_at ?? build.triggered_at)
    const completedAt = new Date(build.finished_at)
    const status = this.normalizeStatus(build.status)
    const steps = this.createStepReports(startedAt, buildLog)
    const sumStepsDurationSec = secRound(sumBy(steps, 'stepDurationSec'))
    const url = `https://app.bitrise.io/build/${build.slug}`
    return {
      service: 'bitrise',
      workflowId,
      workflowRunId,
      buildNumber,
      workflowName,
      createdAt: new Date(build.triggered_at),
      trigger: build.triggered_by ?? '',
      status,
      repository: app.repo,
      headSha: build.commit_hash ?? '',
      branch: build.branch,
      tag: build.tag ?? '',
      jobs: [{
        workflowRunId,
        buildNumber,
        jobId: build.slug,
        jobName: workflowName,
        status: status,
        startedAt: startedAt,
        completedAt: completedAt,
        jobDurationSec: diffSec(startedAt, completedAt),
        sumStepsDurationSec,
        steps: steps,
        url,
        executorClass: build.machine_type_id,
        executorType: build.stack_identifier,
        executorName: '',
      }],
      startedAt,
      completedAt,
      workflowDurationSec: diffSec(startedAt, completedAt),
      sumJobsDurationSec: sumStepsDurationSec,
      successCount: (status === 'SUCCESS') ? 1 : 0,
      parameters: [],
      queuedDurationSec: diffSec(createdAt, startedAt),
      commitMessage: build.commit_message ?? '',
      actor: build.triggered_by ?? '',
      url,
    }
  }
Example #7
Source File: groupAdjacentAminoacidChanges.ts    From nextclade with MIT License 5 votes vote down vote up
private updateCounts() {
    this.numSubstitutions = sumBy(this.changes, (change) => Number(change.type === 'substitution'))
    this.numDeletions = sumBy(this.changes, (change) => Number(change.type === 'deletion'))
  }
Example #8
Source File: ClaimPointsCallout .tsx    From glide-frontend with GNU General Public License v3.0 5 votes vote down vote up
ClaimPointsCallout = () => {
  const [claimableAchievements, setClaimableAchievement] = useState<Achievement[]>([])
  const { t } = useTranslation()
  const dispatch = useAppDispatch()
  const { profile } = useProfile()
  const { account } = useWeb3React()

  useEffect(() => {
    const fetchIfoClaims = async () => {
      const ifoData = await getClaimableIfoData(account)
      setClaimableAchievement(ifoData)
    }

    if (account) {
      fetchIfoClaims()
    }
  }, [account, dispatch, setClaimableAchievement])

  const handleCollectSuccess = (achievement: Achievement) => {
    dispatch(addAchievement(achievement))
    dispatch(addPoints(achievement.points))

    setClaimableAchievement((prevClaimableAchievements) =>
      prevClaimableAchievements.filter((prevClaimableAchievement) => prevClaimableAchievement.id !== achievement.id),
    )
  }

  if (!profile?.isActive) {
    return null
  }

  if (claimableAchievements.length === 0) {
    return null
  }

  const totalPointsToCollect = sumBy(claimableAchievements, 'points')

  return (
    <Card isActive mb="32px">
      <CardHeader>
        <Flex flexDirection={['column', null, 'row']} justifyContent={['start', null, 'space-between']}>
          <Flex alignItems="center" mb={['16px', null, 0]}>
            <PrizeIcon width="32px" mr="8px" />
            <Heading scale="lg">{t('%num% Points to Collect', { num: totalPointsToCollect })}</Heading>
          </Flex>
        </Flex>
      </CardHeader>
      <CardBody>
        {claimableAchievements.map((achievement) => (
          <AchievementRow key={achievement.address} achievement={achievement} onCollectSuccess={handleCollectSuccess} />
        ))}
      </CardBody>
    </Card>
  )
}
Example #9
Source File: jenkins_analyzer.ts    From CIAnalyzer with MIT License 5 votes vote down vote up
createWorkflowReport(jobName: string, run: WfapiRunResponse, build: BuildResponse): WorkflowReport {
    const { workflowName, workflowId, buildNumber, workflowRunId }
      = this.createWorkflowParams(jobName, run.id)

    const jobReports: JobReport[] = run.stages.map((stage) => {
      const stepReports: StepReport[] = stage.stageFlowNodes.map((node) => {
        // step
        return {
          name: node.parameterDescription ?? node.name,
          status: this.normalizeStatus(node.status),
          number: Number(node.id),
          startedAt: new Date(node.startTimeMillis),
          completedAt: new Date(node.startTimeMillis + node.durationMillis),
          stepDurationSec: node.durationMillis / 1000,
        }
      })

      // job
      return {
        workflowRunId,
        buildNumber,
        jobId: stage.id,
        jobName: stage.name,
        status: this.normalizeStatus(stage.status),
        startedAt: new Date(stage.startTimeMillis),
        completedAt: new Date(stage.startTimeMillis + stage.durationMillis),
        jobDurationSec: stage.durationMillis / 1000,
        sumStepsDurationSec: secRound(sumBy(stepReports, 'stepDurationSec')),
        steps: stepReports,
        url: '',
        executorClass: '',
        executorType: '',
        executorName: '',
      }
    })

    const status = this.normalizeStatus(run.status)
    const url = new URL(`job/${workflowName}/${buildNumber}`, this.htmlBaseUrl)
    // workflow
    return {
      service: 'jenkins',
      workflowId,
      workflowRunId,
      buildNumber,
      workflowName,
      createdAt: new Date(run.startTimeMillis),
      trigger: this.detectTrigger(build),
      status,
      repository: this.detectRepository(build),
      headSha: this.detectHeadSha(build),
      branch: this.detectBranch(build),
      tag: '',
      jobs: jobReports,
      startedAt: new Date(run.startTimeMillis),
      completedAt: new Date(run.startTimeMillis + run.durationMillis),
      workflowDurationSec: run.durationMillis / 1000,
      sumJobsDurationSec: secRound(sumBy(jobReports, 'sumStepsDurationSec')),
      successCount: (status === 'SUCCESS') ? 1 : 0,
      parameters: this.detectParameters(build),
      queuedDurationSec: secRound(this.estimateQueuedDuration(build) / 1000),
      commitMessage: '',
      actor: '',
      url: url.toString(),
    }
  }
Example #10
Source File: github_analyzer.ts    From CIAnalyzer with MIT License 5 votes vote down vote up
createWorkflowReport(workflowName: string, workflow: WorkflowRunsItem, jobs: JobsItem, tagMap: RepositoryTagMap): WorkflowReport {
    const { workflowId, buildNumber, workflowRunId }
      = this.createWorkflowParams(workflowName, workflow)

    const jobReports: JobReport[] = jobs.map((job) => {
      const stepReports: StepReport[] = job.steps!.map((step) => {
        const startedAt = new Date(step.started_at!)
        const completedAt = new Date(step.completed_at!)
        // step
        return {
          name: step.name,
          status: this.normalizeStatus(step.conclusion),
          number: step.number,
          startedAt,
          completedAt,
          stepDurationSec: diffSec(startedAt, completedAt)
        }
      })

      const startedAt = new Date(job.started_at)
      const completedAt = new Date(job.completed_at!)
      // job
      return {
        workflowRunId: workflowRunId,
        buildNumber: buildNumber, // Github Actions job does not have buildNumber
        jobId: String(job.id),
        jobName: job.name,
        status: this.normalizeStatus(job.conclusion),
        startedAt,
        completedAt,
        jobDurationSec: diffSec(startedAt, completedAt),
        sumStepsDurationSec: sumBy(stepReports, 'stepDurationSec'),
        steps: stepReports,
        url: job.html_url ?? '',
        executorClass: '',
        executorType: '',
        executorName: job.runner_name ?? '',
      }
    })

    const createdAt = new Date(workflow.created_at)
    const startedAt = min(jobReports.map((job) => job.startedAt )) || createdAt
    const completedAt = max(jobReports.map((job) => job.completedAt )) || createdAt
    const status = this.normalizeStatus(workflow.conclusion as unknown as string)
    // workflow
    return {
      service: 'github',
      workflowId,
      buildNumber,
      workflowRunId,
      workflowName,
      createdAt,
      trigger: workflow.event,
      status,
      repository: workflow.repository.full_name,
      headSha: workflow.head_sha,
      branch: workflow.head_branch ?? '',
      tag: tagMap.get(workflow.head_sha) ?? '',
      jobs: jobReports,
      startedAt,
      completedAt,
      workflowDurationSec: diffSec(startedAt, completedAt),
      sumJobsDurationSec: sumBy(jobReports, 'sumStepsDurationSec'),
      successCount: (status === 'SUCCESS') ? 1 : 0,
      parameters: [],
      queuedDurationSec: diffSec(createdAt, startedAt),
      commitMessage: workflow.head_commit?.message ?? '',
      actor: workflow.head_commit?.author?.name ?? '',
      url: workflow.html_url,
    }
  }
Example #11
Source File: circleci_analyzer_v2.ts    From CIAnalyzer with MIT License 5 votes vote down vote up
async createTestReports( workflowReports: WorkflowReport[], tests: JobTest[]): Promise<TestReport[]> {
    const testReports: TestReport[] = []
    for (const workflowReport of workflowReports) {
      // Filter tests that related to workflow jobs
      const jobAndJobTests = workflowReport.jobs.map((job) => {
        return {
          job,
          jobTest: tests.find((test) => test.jobNumber === job.buildNumber)
        }
      })
      const testSuiteList: TestSuite[] = jobAndJobTests
        .filter(({ jobTest }) => jobTest && jobTest.tests.length > 0 )
        .map(({ job, jobTest }) => {
          // TestCases = CircleCI tests
          const testCases: TestCase[] = jobTest!.tests.map((test) => {
            return {
              classname: test.classname,
              name: test.name,
              time: test.run_time,
              failure: (test.result === 'failure') ? [{ inner: test.message ?? '' }] : undefined,
              skipped: (test.result === 'skipped') ? [{ message: test.message ?? '' }] : undefined,
            }
          })
          // TestSuite = CircleCI Job
          return {
            name: job.jobName,
            time: secRound(sumBy(testCases, 'time')),
            tests: testCases.length,
            failures: testCases.filter((testcase) => testcase.failure !== undefined).length,
            skipped: testCases.filter((testcase) => testcase.skipped !== undefined).length,
            timestamp: job.startedAt.toISOString(),
            testcase: testCases,
          }
        })

      if (testSuiteList.length === 0 ) continue

      // TestSuiets = CircleCI Workflow
      const testSuites = {
        name: workflowReport.workflowName,
        time: secRound(sumBy(testSuiteList, 'time')),
        tests: sumBy(testSuiteList, 'tests'),
        failures: sumBy(testSuiteList, 'failures'),
        testsuite: testSuiteList,
      }
      testReports.push({
        workflowId: workflowReport.workflowId,
        workflowRunId: workflowReport.workflowRunId,
        buildNumber: workflowReport.buildNumber,
        workflowName: workflowReport.workflowName,
        createdAt: workflowReport.createdAt,
        branch: workflowReport.branch,
        service: workflowReport.service,
        testSuites: convertToReportTestSuites(testSuites),
        status: (testSuites.failures > 0) ? 'FAILURE' : 'SUCCESS',
        successCount: (testSuites.failures > 0) ? 0 : 1,
      })
    }
    return testReports
  }
Example #12
Source File: circleci_analyzer.ts    From CIAnalyzer with MIT License 5 votes vote down vote up
async createTestReports( workflowReport: WorkflowReport, jobs: SingleBuildResponse[], tests: TestResponse[]): Promise<TestReport[]> {
    const testSuiteList: TestSuite[] = tests
      .filter((test) => test.tests.length > 0)
      .map((test) => {
        const testCases: TestCase[] = test.tests.map((test) => {
          return {
            classname: test.classname,
            name: test.name,
            time: test.run_time,
            failure: (test.result === 'failure') ? [{ inner: test.message }] : undefined,
            skipped: (test.result === 'skipped') ? [{ message: test.message }] : undefined,
          }
        })
        const testJob = jobs.find((job) => job.build_num === test.run_id)
        return {
          name: testJob?.workflows.job_name ?? '',
          time: secRound(sumBy(testCases, 'time')),
          tests: testCases.length,
          failures: testCases.filter((testcase) => testcase.failure !== undefined).length,
          skipped: testCases.filter((testcase) => testcase.skipped !== undefined).length,
          timestamp: testJob?.start_time,
          testcase: testCases,
        }
      })

    if (testSuiteList.length === 0 ) return []

    const testSuites = {
      name: workflowReport.workflowName,
      time: secRound(sumBy(testSuiteList, 'time')),
      tests: sumBy(testSuiteList, 'tests'),
      failures: sumBy(testSuiteList, 'failures'),
      testsuite: testSuiteList,
    }
    return [{
      workflowId: workflowReport.workflowId,
      workflowRunId: workflowReport.workflowRunId,
      buildNumber: workflowReport.buildNumber,
      workflowName: workflowReport.workflowName,
      createdAt: workflowReport.createdAt,
      branch: workflowReport.branch,
      service: workflowReport.service,
      testSuites: convertToReportTestSuites(testSuites),
      status: (testSuites.failures > 0) ? 'FAILURE' : 'SUCCESS',
      successCount: (testSuites.failures > 0) ? 0 : 1,
    }]
  }
Example #13
Source File: pie-chart.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
ChartItem = (props: CP_PIE_CHART.Props) => {
  const { data: pData, props: configProps, operations, execOperation } = props;
  const {
    visible,
    style = {},
    chartStyle,
    textInfoStyle = {},
    size = 'normal',
    direction = 'row',
    title,
    tip,
    option,
    ...rest
  } = configProps;
  const { data, label } = pData;
  const styleMap = {
    small: {
      chartStyle: { width: 56, height: 56 },
      infoCls: { col: 'mt-3', row: 'ml-3' },
    },
    normal: {
      chartStyle: { width: 100, height: 100 },
      infoCls: { col: 'mt-3', row: 'ml-3' },
    },
    big: {
      chartStyle: { width: 180, height: 180 },
      infoCls: { col: 'mt-3', row: 'ml-3' },
    },
  };
  const styleObj = styleMap[size];
  const onEvents = {
    click: (params: any) => {
      const dataOp = get(params, 'data.operations.click') || operations?.click;
      if (dataOp) {
        execOperation(dataOp, {
          data: params.data,
          seriesIndex: params.seriesIndex,
          dataIndex: params.dataIndex,
        });
      }
    },
  };

  const reChartStyle = chartStyle || styleObj?.chartStyle;
  const chartSetting = reChartStyle?.chartSetting || 'center';
  const cls = classnames({
    'items-center': chartSetting === 'center',
    'items-start': chartSetting === 'start',
  });

  const color = map(data, 'color');
  const presetColor = map(colorMap);
  const reColor = color ? uniq(map(color, (cItem) => colorMap[cItem] || cItem).concat(presetColor)) : presetColor;

  const { option: reOption, isEmpty } = getOption(data, option, configProps, label);
  const finalColor = reOption.color || reColor;
  const ChartComp = (
    <EChart onEvents={onEvents} option={{ color: reColor, ...reOption }} notMerge style={reChartStyle} {...rest} />
  );

  const total = data?.[0].total || sumBy(data, 'value') || 1;
  const Comp = (
    <div className={`flex ${cls}`}>
      {ChartComp}
      <div className={`flex-1 flex justify-between ${styleObj?.infoCls?.[direction]}`} style={{ minWidth: 100 }}>
        {data?.map((item: CP_PIE_CHART.IList, idx: number) => {
          if (item.info?.length) {
            return (
              <div className="flex items-center w-full justify-around">
                {item.info.map((infoItem) => (
                  <TextBlockInfo {...infoItem} size="small" style={textInfoStyle} />
                ))}
              </div>
            );
          }

          return (
            <TextBlockInfo
              size="small"
              key={item.name}
              className="flex-1"
              style={textInfoStyle}
              main={`${item.formatter ? getFormatterString(item.formatter, { v: item.value }) : item.value}`}
              sub={total ? `${((item.value * 100) / total).toFixed(1)}%` : '-'}
              extra={
                <div className="flex items-center">
                  <span className="rounded" style={{ width: 4, height: 10, backgroundColor: finalColor[idx] }} />
                  <span className="ml-1 text-desc text-xs leading-5">{item.name}</span>
                </div>
              }
            />
          );
        })}
      </div>
    </div>
  );
  return isEmpty ? <EmptyHolder relative /> : Comp;
}
Example #14
Source File: table.tsx    From erda-ui with GNU Affero General Public License v3.0 4 votes vote down vote up
Iteration = () => {
  const [status, setStatus] = React.useState('unarchive');
  const [list, paging] = iterationStore.useStore((s) => [s.iterationList, s.iterationPaging]);

  const projectId = routeInfoStore.useStore((s) => s.params.projectId);
  const { getIterations, deleteIteration, editIteration: handleFiledIteration } = iterationStore.effects;
  const [isFetching] = useLoading(iterationStore, ['getIterations']);
  const { total, pageNo, pageSize } = paging;
  const [state, updater] = useUpdate({
    modalVisible: false,
    curDetail: null,
  });

  const query = React.useMemo(() => {
    const iterationStateMap = {
      archived: 'FILED',
      unarchive: 'UNFILED',
    };
    return { state: iterationStateMap[status], pageNo: 1 };
  }, [status]);

  const getList = React.useCallback(
    (q: Obj = {}) => {
      return getIterations({ ...query, ...q, projectID: +projectId });
    },
    [getIterations, query, projectId],
  );

  React.useEffect(() => {
    getList();
  }, [getList]);

  const onDelete = (id: number) => {
    deleteIteration(id).then(() => {
      getList({ pageNo: 1 });
    });
  };

  const onEdit = (item: ITERATION.Detail) => {
    updater.curDetail(item);
    updater.modalVisible(true);
  };

  const onFiled = (record: ITERATION.Detail, operation: string) => {
    const { id, startedAt, finishedAt, title, content } = record;
    handleFiledIteration({
      id,
      startedAt,
      finishedAt,
      title,
      content,
      state: operation,
    }).then(() => {
      getList({ pageNo: 1 });
    });
  };

  const onCreate = () => {
    updater.modalVisible(true);
  };

  const handleClose = (isSave: boolean) => {
    updater.modalVisible(false);
    updater.curDetail(null);
    isSave && getList({ pageNo });
  };

  const [operationAuth, handleFiledAuth] = usePerm((s) => [
    s.project.iteration.operation.pass,
    s.project.iteration.handleFiled.pass,
  ]);

  const columns = [
    {
      title: i18n.t('dop:Name'),
      dataIndex: 'title',
      width: 200,
      render: (val: string) => (
        <Ellipsis className="fake-link nowrap" title={val}>
          {val}
        </Ellipsis>
      ),
    },
    {
      title: i18n.t('dop:Goal'),
      dataIndex: 'content',
      // width: 300,
    },
    {
      title: i18n.t('Period'),
      width: 230,
      dataIndex: 'startedAt',
      render: (startedAt: string, record: ITERATION.Detail) =>
        `${moment(startedAt).format('YYYY/MM/DD')} - ${moment(record.finishedAt).format('YYYY/MM/DD')}`,
    },
    {
      title: i18n.t('dop:Progress'),
      width: 120,
      dataIndex: 'issueSummary',
      render: (_k, record: ITERATION.Detail) => {
        const doneTotal = sumBy(map(record.issueSummary || {}), 'done') || 0;
        const totalCount = (sumBy(map(record.issueSummary || {}), 'undone') || 0) + doneTotal;
        const percent = ((totalCount ? doneTotal / totalCount : 0) * 100).toFixed(1);
        return (
          <div className="mr-2">
            <Progress percent={+percent} />
          </div>
        );
      },
    },
  ];

  const actions = {
    render: (record: ITERATION.Detail) => {
      if (record.state === 'FILED') {
        return [
          {
            title: (
              <WithAuth pass={handleFiledAuth}>
                <span>{i18n.t('dop:Unarchive')}</span>
              </WithAuth>
            ),
            onClick: () => onFiled(record, 'UNFILED'),
          },
        ];
      }

      return [
        {
          title: (
            <WithAuth pass={operationAuth}>
              <span>{i18n.t('Edit')}</span>
            </WithAuth>
          ),
          onClick: () => onEdit(record),
        },
        {
          title: (
            <WithAuth pass={handleFiledAuth}>
              <span>{i18n.t('Archive')}</span>
            </WithAuth>
          ),
          onClick: () => onFiled(record, 'FILED'),
        },
        {
          title: (
            <WithAuth pass={operationAuth}>
              <span>{i18n.t('Delete')}</span>
            </WithAuth>
          ),
          onClick: () => {
            Modal.confirm({
              title: `${i18n.t('common:confirm to delete')}?`,
              content: `${i18n.t('common:confirm this action')}?`,
              onOk() {
                onDelete(record.id);
              },
            });
          },
        },
      ];
    },
  };

  const addAuth = usePerm((s) => s.project.iteration.operation.pass);

  return (
    <div className="iteration">
      <TopButtonGroup>
        <WithAuth pass={addAuth} tipProps={{ placement: 'bottom' }}>
          <Button type="primary" onClick={onCreate}>
            {i18n.t('Add')}
          </Button>
        </WithAuth>
      </TopButtonGroup>
      <RadioTabs
        options={options}
        value={status}
        onChange={(v: string) => {
          setStatus(v);
        }}
        className="mb-2"
      />
      <ErdaTable
        tableKey="issue-iteration"
        rowKey="id"
        dataSource={list}
        columns={columns}
        loading={isFetching}
        actions={actions}
        pagination={{
          current: pageNo,
          pageSize,
          total,
          showSizeChanger: true,
          onChange: (no: number, size: number) => {
            getList({ pageNo: no, pageSize: size });
          },
        }}
        onRow={(record) => {
          return {
            onClick: () => {
              goTo(goTo.pages.iterationDetail, {
                projectId,
                iterationId: record.id,
                issueType: 'all',
              });
            },
          };
        }}
      />
      <IterationModal visible={state.modalVisible} data={state.curDetail as ITERATION.Detail} onClose={handleClose} />
    </div>
  );
}
Example #15
Source File: circleci_analyzer_v2.ts    From CIAnalyzer with MIT License 4 votes vote down vote up
createWorkflowReport( pipeline: Pipeline, workflow: Workflow): WorkflowReport {
    const repository = workflow.project_slug.split('/').slice(1).join('/')
    const { workflowName, workflowId, buildNumber, workflowRunId }
      = this.createWorkflowParams(workflow.name, repository, pipeline.number)

    const jobReports: JobReport[] = workflow.jobs.map((job) => {
      const stepReports: StepReport[] = job.steps
        .filter((step) => {
          const action = first(step.actions)!
          // NOTE: Ignore background step (ex. Setup service container image step)
          return action.background === false
        })
        .map((step) => {
          const action = first(step.actions)!
          const startedAt = new Date(action.start_time)
          // NOTE: Sometimes action.end_time will be broken, so it should be replaced when it's value is invalid.
          const validatedEndTime = action.end_time ?? action.start_time
          const completedAt = new Date(validatedEndTime)
          // step
          return {
            name: action.name,
            status: this.normalizeStatus(action.status),
            number: action.step,
            startedAt,
            completedAt,
            stepDurationSec: diffSec(startedAt, completedAt)
          }
        })

      const startedAt = new Date(job.started_at)
      const completedAt = new Date(job.stopped_at ?? job.started_at)
      const url = new URL(`pipelines/${workflow.project_slug}/${workflow.pipeline_number}/workflows/${workflow.id}`, this.htmlBaseUrl)
      // job
      return {
        workflowRunId,
        buildNumber: job.job_number,
        jobId: job.id,
        jobName: job.name,
        status: this.normalizeStatus(job.status as CircleciStatus),
        startedAt,
        completedAt,
        jobDurationSec: diffSec(startedAt, completedAt),
        sumStepsDurationSec: secRound(sumBy(stepReports, 'stepDurationSec')),
        steps: stepReports,
        url: url.toString(),
        executorClass: job.detail.executor.resource_class,
        executorType: job.detail.executor.type,
        executorName: '',
      }
    })

    const sortedJobs = sortBy(workflow.jobs, 'job_number')
    const firstJob = first(sortedJobs)
    const createdAt = new Date(workflow.created_at) 
    // Sometimes worklfow has invalid timestamps, so remediate it.
    const startedAt = new Date(firstJob?.started_at ?? workflow.created_at)
    const completedAt = new Date(workflow.stopped_at ?? startedAt)
    const status = this.normalizeWorkflowStatus(workflow.status)
    // workflow
    return {
      service: 'circleci',
      workflowId,
      buildNumber,
      workflowRunId,
      workflowName,
      createdAt,
      trigger: pipeline.trigger.type,
      status,
      repository,
      headSha: pipeline.vcs.revision,
      branch: pipeline.vcs.branch ?? '',
      tag: pipeline.vcs.tag ?? '',
      jobs: jobReports,
      startedAt,
      completedAt,
      workflowDurationSec: diffSec(startedAt, completedAt),
      sumJobsDurationSec: secRound(sumBy(jobReports, 'sumStepsDurationSec')),
      successCount: (status === 'SUCCESS') ? 1 : 0,
      parameters: [],
      queuedDurationSec: diffSec(createdAt, startedAt), // firstJob.started_at - workflow.created_at
      commitMessage: pipeline.vcs.commit?.subject ?? '',
      actor: pipeline.trigger.actor.login,
      url: '',
    }
  }
Example #16
Source File: DonationTab.tsx    From frontend with MIT License 4 votes vote down vote up
export default function DonationTab() {
  const router = useRouter()
  const { t } = useTranslation()
  const matches = useMediaQuery(theme.breakpoints.down('md'))

  const { data: user } = getCurrentPerson(!!router.query?.register)
  if (router.query?.register) {
    delete router.query.register
    router.replace({ pathname: router.pathname, query: router.query }, undefined, { shallow: true })
  }
  const { data: userDonations, isLoading: isUserDonationLoading } = useUserDonations()
  const { data: campaigns, isLoading: isCampaignLoading } = useCampaignList()
  return (
    <StyledProfileTab name={ProfileTabs.donations}>
      <Typography className={classes.h1}>{user?.user ? user.user.firstName + ',' : ''}</Typography>
      <Typography variant="h5" fontWeight={'medium'}>
        {t('profile:donations.helpThanks')} ❤️
      </Typography>
      <Grid
        container
        spacing={theme.spacing(2)}
        marginTop={theme.spacing(1)}
        alignItems={'flex-end'}>
        <Grid order={matches ? 3 : 1} item xs={12} md={4}>
          <Card>
            {!isCampaignLoading && campaigns ? (
              <CardActionArea>
                <CardMedia
                  component="img"
                  height="193"
                  image={campaignListPictureUrl(campaigns[0])}
                  alt={campaigns[0].title}
                />
                <CardContent>
                  <Typography gutterBottom variant="h5" component="div">
                    {campaigns[0].title}
                  </Typography>
                  <Typography variant="body2" color="text.secondary">
                    {truncate(campaigns[0].description, { length: 120 })}
                  </Typography>
                </CardContent>
              </CardActionArea>
            ) : (
              <CircularProgress />
            )}
            <CardActions>
              <Button variant="contained" size="medium" color="secondary">
                {t('profile:donations.donateNow')} ❤️
              </Button>
            </CardActions>
          </Card>
        </Grid>
        <Grid order={matches ? 1 : 2} item xs={12} md={8}>
          {!isUserDonationLoading && userDonations ? (
            <Card className={classes.donationsBox}>
              <Box className={classes.donationsBoxRow}>
                <Typography fontWeight="medium" variant="h5">
                  {t('profile:donations.totalDonations')}
                </Typography>
                <Typography fontWeight="medium" variant="h5">
                  {money(userDonations.total)}
                </Typography>
              </Box>
              <Box className={classes.donationsBoxRow}>
                <Box>
                  <Typography variant="h5">{t('profile:donations.recurringDonations')}</Typography>
                  {/* TODO: Use date-fns to format and localize the months,
                   that the user has recurring donations when that is possible */}
                  {/* <Typography>Я, Ф, М, А 2022</Typography> */}
                </Box>
                <Typography fontWeight="medium" variant="h5">
                  {money(sumBy(userDonations.donations, 'amount'))}
                </Typography>
              </Box>
              <Box className={classes.donationsBoxRow}>
                <Typography variant="h5">{t('profile:donations.cardDonations')}</Typography>
                <Typography fontWeight="medium" variant="h5">
                  {money(userDonations.total)}
                </Typography>
              </Box>
              <Box className={classes.donationsBoxRow}>
                <Typography variant="h5">{t('profile:donations.bankDonations')}</Typography>
                <Typography fontWeight="medium" variant="h5">
                  {money(userDonations.total)}
                </Typography>
              </Box>
            </Card>
          ) : (
            <CircularProgress />
          )}
        </Grid>
        <Grid order={matches ? 2 : 3} item xs={12}>
          <DonationTable donations={userDonations?.donations} />
        </Grid>
      </Grid>
    </StyledProfileTab>
  )
}
Example #17
Source File: circleci_analyzer.ts    From CIAnalyzer with MIT License 4 votes vote down vote up
createWorkflowReport( workflowRun: WorkflowRun, jobs: SingleBuildResponse[], tagMap: RepositoryTagMap): WorkflowReport {
    const sortedJobs = sortBy(jobs, 'build_num')
    const firstJob = first(sortedJobs)!
    const lastJob = last(sortedJobs)!
    const repository = `${firstJob.username}/${firstJob.reponame}`
    const { workflowName, workflowId, buildNumber, workflowRunId }
      = this.createWorkflowParams(workflowRun.workflow_name, repository, lastJob.build_num)

    const jobReports: JobReport[] = sortedJobs.map((job) => {
      const stepReports: StepReport[] = job.steps
        .filter((step) => {
          const action = first(step.actions)!
          // NOTE: Ignore background step (ex. Setup service container image step)
          return action.background === false
        })
        .map((step) => {
          const action = first(step.actions)!
          const startedAt = new Date(action.start_time)
          // NOTE: Sometimes action.end_time will be broken, so it should be replaced when it's value is invalid.
          const validatedEndTime = action.end_time ?? action.start_time
          const completedAt = new Date(validatedEndTime)
          // step
          return {
            name: action.name,
            status: this.normalizeStatus(action.status),
            number: action.step,
            startedAt,
            completedAt,
            stepDurationSec: diffSec(startedAt, completedAt)
          }
        })

      const startedAt = new Date(job.start_time)
      const completedAt = new Date(job.stop_time)
      // job
      return {
        workflowRunId,
        buildNumber: job.build_num,
        jobId: job.workflows.job_id,
        jobName: job.workflows.job_name,
        status: this.normalizeStatus(job.status),
        startedAt,
        completedAt,
        jobDurationSec: diffSec(startedAt, completedAt),
        sumStepsDurationSec: secRound(sumBy(stepReports, 'stepDurationSec')),
        steps: stepReports,
        url: '',
        executorClass: '',
        executorType: '',
        executorName: '',
      }
    })

    const startedAt = min(jobReports.map((job) => job.startedAt ))!
    const completedAt = max(jobReports.map((job) => job.completedAt ))!
    const status = this.estimateWorkflowStatus(jobReports)
    const createdAt = min(jobs.map((job) => new Date(job.queued_at)))!
    // workflow
    return {
      service: 'circleci',
      workflowId,
      buildNumber,
      workflowRunId,
      workflowName,
      createdAt,
      trigger: firstJob.why,
      status,
      repository,
      headSha: firstJob.vcs_revision,
      branch: firstJob.branch,
      tag: tagMap.get(firstJob.vcs_revision) ?? '',
      jobs: jobReports,
      startedAt,
      completedAt,
      workflowDurationSec: diffSec(startedAt, completedAt),
      sumJobsDurationSec: secRound(sumBy(jobReports, 'sumStepsDurationSec')),
      successCount: (status === 'SUCCESS') ? 1 : 0,
      parameters: [],
      queuedDurationSec: diffSec(createdAt, min(jobs.map((job) => new Date(job.start_time)))!),
      commitMessage: '',
      actor: '',
      url: '',
    }
  }