From ae497645631d6ec13a6df8e5eab35b85257ebcc7 Mon Sep 17 00:00:00 2001 From: Zoltan Szabo Date: Thu, 20 Jun 2024 15:49:18 +0200 Subject: [PATCH 1/8] feat: implement StepDrawer components --- .../components/StepDrawer/StepDrawer.mocks.ts | 108 ++++++++++++++++++ .../StepDrawer/StepDrawer.stories.tsx | 14 +++ .../components/StepDrawer/StepDrawer.tsx | 37 ++++++ .../components/StepDrawer/StepDrawer.types.ts | 17 +++ .../components/StepDrawer/StepDrawer.utils.ts | 3 + .../StepDrawer/components/StepCard.tsx | 57 +++++++++ .../StepDrawer/components/StepFilter.tsx | 31 +++++ .../StepDrawer/components/StepList.tsx | 46 ++++++++ .../components/StepDrawer/hooks/useSteps.ts | 37 ++++++ 9 files changed, 350 insertions(+) create mode 100644 source/javascripts/components/StepDrawer/StepDrawer.mocks.ts create mode 100644 source/javascripts/components/StepDrawer/StepDrawer.stories.tsx create mode 100644 source/javascripts/components/StepDrawer/StepDrawer.tsx create mode 100644 source/javascripts/components/StepDrawer/StepDrawer.types.ts create mode 100644 source/javascripts/components/StepDrawer/StepDrawer.utils.ts create mode 100644 source/javascripts/components/StepDrawer/components/StepCard.tsx create mode 100644 source/javascripts/components/StepDrawer/components/StepFilter.tsx create mode 100644 source/javascripts/components/StepDrawer/components/StepList.tsx create mode 100644 source/javascripts/components/StepDrawer/hooks/useSteps.ts diff --git a/source/javascripts/components/StepDrawer/StepDrawer.mocks.ts b/source/javascripts/components/StepDrawer/StepDrawer.mocks.ts new file mode 100644 index 000000000..995facee6 --- /dev/null +++ b/source/javascripts/components/StepDrawer/StepDrawer.mocks.ts @@ -0,0 +1,108 @@ +import { Step } from './StepDrawer.types'; + +export const MockSteps: Step[] = [ + { + id: 'activate-ssh-key', + title: 'Activate SSH key', + icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/activate-ssh-key/assets/icon.svg', + version: '1.1.6', + description: + 'Add your SSH key to the build machine to access private repositories\n' + + '\n' + + 'This Step makes sure Bitrise has access to your repository when cloning SSH URLs. The Step saves the provided private key of your SSH keypair to a file and then loads it into the SSH agent.', + categories: ['access-control'], + isOfficial: true, + isVerified: false, + isDeprecated: false, + }, + { + id: 'clone', + title: 'Git Clone', + description: + 'Checks out the repository, updates submodules and exports git metadata as Step outputs.\n' + + '\n' + + 'The checkout process depends on the Step settings and the build trigger parameters (coming from your git server).', + version: '8.3.1', + icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/git-clone/assets/icon.svg', + categories: ['utility'], + isOfficial: true, + isVerified: false, + isDeprecated: false, + }, + { + id: 'npm', + title: 'Run npm command', + icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/npm/assets/icon.svg', + version: '1.1.6', + description: + "The Step runs npm with the command and arguments you provide, for example, to install missing packages or run a package's test.", + categories: ['build', 'test', 'utility'], + isOfficial: true, + isVerified: false, + isDeprecated: false, + }, + { + id: 'test', + title: 'Xcode Test for iOS', + description: "Runs your project's pre-defined Xcode tests on every build.", + version: '5.1.1', + icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/xcode-test/assets/icon.svg', + categories: ['test'], + isOfficial: true, + isVerified: false, + isDeprecated: false, + }, + { + id: 'xcode-archive', + title: 'Xcode Archive & Export for iOS', + description: + 'Archive and export an Xcode project.\n' + + '\n' + + 'This Step will archive your Xcode project and export it as an .ipa file. You can also export the archive as a .xcarchive file.', + version: '5.1.2', + icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/xcode-archive/assets/icon.svg', + categories: ['test', 'build', 'deploy'], + isOfficial: true, + isVerified: false, + isDeprecated: false, + }, + { + id: 'codecov', + title: 'Codecov', + description: + 'Upload your code coverage files to Codecov.io\n' + + '\n' + + 'Reduce technical debt with visualized test performance, faster code reviews and workflow enhancements. Now you can upload your code coverage files to Codecov every time you kick off a build!', + version: '3.3.3', + icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/codecov/assets/icon.svg', + categories: ['test'], + isOfficial: false, + isVerified: true, + isDeprecated: false, + }, + { + id: 'deploy-to-bitrise-io', + title: 'Deploy to Bitrise.io', + description: + "Deploys build artifacts to make them available for the user on the build's Artifacts tab.\n" + + "Sends test results to the Test Reports add-on (build's Tests tab). Uploads Pipeline intermediate files to make them available in subsequent Stages and also uploads Bitrise and user generated html reports.", + version: '2.8.1', + icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/deploy-to-bitrise-io/assets/icon.svg', + categories: ['test', 'deploy'], + isOfficial: true, + isVerified: false, + isDeprecated: false, + }, + { + id: 'azure-devops-status', + title: 'Azure DevOps Status', + description: + 'Update commit status for Azure DevOps repositories. This step always runs, no matter if build succeeded or failed.', + version: '1.0.1', + icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/azure-devops-status/assets/icon.svg', + categories: ['test'], + isOfficial: false, + isVerified: false, + isDeprecated: true, + }, +]; diff --git a/source/javascripts/components/StepDrawer/StepDrawer.stories.tsx b/source/javascripts/components/StepDrawer/StepDrawer.stories.tsx new file mode 100644 index 000000000..572a54386 --- /dev/null +++ b/source/javascripts/components/StepDrawer/StepDrawer.stories.tsx @@ -0,0 +1,14 @@ +import { Meta, StoryObj } from '@storybook/react'; +import StepDrawer from './StepDrawer'; + +export default { + component: StepDrawer, + argTypes: { + isOpen: { control: 'boolean' }, + }, + args: { + isOpen: true, + }, +} as Meta; + +export const Default: StoryObj = {}; diff --git a/source/javascripts/components/StepDrawer/StepDrawer.tsx b/source/javascripts/components/StepDrawer/StepDrawer.tsx new file mode 100644 index 000000000..e72f7460e --- /dev/null +++ b/source/javascripts/components/StepDrawer/StepDrawer.tsx @@ -0,0 +1,37 @@ +import { Box, Drawer, Text, useDisclosure } from '@bitrise/bitkit'; +import { FormProvider, useForm } from 'react-hook-form'; +import { FilterFormValues } from './StepDrawer.types'; +import StepFilter from './components/StepFilter'; +import StepList from './components/StepList'; +import { useCategories, useFilter } from './hooks/useSteps'; + +type Props = { + isOpen: boolean; +}; + +const StepDrawer = ({ isOpen: isInitialOpen }: Props) => { + const { isOpen, onClose } = useDisclosure({ defaultIsOpen: isInitialOpen }); + const { categories } = useCategories(); + const form = useForm({ + defaultValues: { + search: '', + categories: [], + }, + }); + + const { steps } = useFilter(form.watch()); + + return ( + + + + Add Step + + + + + + ); +}; + +export default StepDrawer; diff --git a/source/javascripts/components/StepDrawer/StepDrawer.types.ts b/source/javascripts/components/StepDrawer/StepDrawer.types.ts new file mode 100644 index 000000000..35a07f36c --- /dev/null +++ b/source/javascripts/components/StepDrawer/StepDrawer.types.ts @@ -0,0 +1,17 @@ +export type FilterFormValues = { + search: string; + projectType: string; + categories: string[]; +}; + +export type Step = { + id: string; + icon: string; + title: string; + description: string; + version: string; + categories: string[]; + isOfficial: boolean; + isVerified: boolean; + isDeprecated: boolean; +}; diff --git a/source/javascripts/components/StepDrawer/StepDrawer.utils.ts b/source/javascripts/components/StepDrawer/StepDrawer.utils.ts new file mode 100644 index 000000000..66bf743ff --- /dev/null +++ b/source/javascripts/components/StepDrawer/StepDrawer.utils.ts @@ -0,0 +1,3 @@ +import capitalize from 'lodash/capitalize'; + +export const displayCategoryName = (category: string) => capitalize(category).replace('-', ' '); diff --git a/source/javascripts/components/StepDrawer/components/StepCard.tsx b/source/javascripts/components/StepDrawer/components/StepCard.tsx new file mode 100644 index 000000000..bd47afdd2 --- /dev/null +++ b/source/javascripts/components/StepDrawer/components/StepCard.tsx @@ -0,0 +1,57 @@ +import { Box, Card, Icon, Text } from '@bitrise/bitkit'; +import { LazyLoadImage } from 'react-lazy-load-image-component'; +import { useBoolean } from 'usehooks-ts'; +import { Step } from '../StepDrawer.types'; +import defaultStepIcon from '../../../../images/step/icon-default.svg'; +import StepBadge from '../../StepBadge/StepBadge'; + +type Props = Step; + +const StepCard = ({ icon, title, description, version, isOfficial, isVerified, isDeprecated }: Props) => { + const { value: hovered, setTrue, setFalse } = useBoolean(false); + + return ( + + + + + + + + {title} + + {version} + + + + + {description} + + {hovered && } + + ); +}; + +export default StepCard; diff --git a/source/javascripts/components/StepDrawer/components/StepFilter.tsx b/source/javascripts/components/StepDrawer/components/StepFilter.tsx new file mode 100644 index 000000000..a455941b4 --- /dev/null +++ b/source/javascripts/components/StepDrawer/components/StepFilter.tsx @@ -0,0 +1,31 @@ +import { Box, SearchInput, Tag } from '@bitrise/bitkit'; +import { Controller } from 'react-hook-form'; + +type Props = { + categories?: string[]; +}; + +const StepFilter = ({ categories = [] }: Props) => { + return ( + + ( + onChange({ target: { value } })} + {...rest} + /> + )} + /> + + {categories.map((category) => ( + {category} + ))} + + + ); +}; + +export default StepFilter; diff --git a/source/javascripts/components/StepDrawer/components/StepList.tsx b/source/javascripts/components/StepDrawer/components/StepList.tsx new file mode 100644 index 000000000..ff1d3f51a --- /dev/null +++ b/source/javascripts/components/StepDrawer/components/StepList.tsx @@ -0,0 +1,46 @@ +import { useMemo } from 'react'; +import { Box, Text } from '@bitrise/bitkit'; +import { SimpleGrid } from '@chakra-ui/react'; +import { Step } from '../StepDrawer.types'; +import { displayCategoryName } from '../StepDrawer.utils'; +import StepCard from './StepCard'; + +type Props = { + categories: string[]; + steps: Step[]; +}; + +const StepList = ({ categories = [], steps = [] }: Props) => { + const stepByCategories = useMemo( + () => + steps.reduce( + (acc, step) => { + step.categories.forEach((category) => { + acc[category] ||= []; + acc[category].push(step); + }); + + return acc; + }, + {} as Record, + ), + [steps], + ); + + return ( + + {categories?.map((category) => ( + + + {displayCategoryName(category)} + + + {stepByCategories[category]?.map((step) => )} + + + ))} + + ); +}; + +export default StepList; diff --git a/source/javascripts/components/StepDrawer/hooks/useSteps.ts b/source/javascripts/components/StepDrawer/hooks/useSteps.ts new file mode 100644 index 000000000..0c7ca22aa --- /dev/null +++ b/source/javascripts/components/StepDrawer/hooks/useSteps.ts @@ -0,0 +1,37 @@ +import { useMemo } from 'react'; +import uniq from 'lodash/uniq'; +import { MockSteps } from '../StepDrawer.mocks'; +import { FilterFormValues } from '../StepDrawer.types'; + +export const useSteps = () => { + const steps = useMemo(() => MockSteps, []); + return { steps }; +}; + +export const useCategories = () => { + const { steps } = useSteps(); + const categories = useMemo(() => { + return uniq(steps.flatMap((step) => step.categories)); + }, [steps]); + return { categories }; +}; + +export const useFilter = ({ categories, search }: FilterFormValues) => { + const { steps } = useSteps(); + const searchValue = search.toLowerCase(); + let filteredSteps = steps; + + if (categories.length > 0) { + filteredSteps = steps.filter((step) => step.categories.some((category) => categories.includes(category))); + } + + if (searchValue) { + filteredSteps = steps.filter((step) => { + const name = step.title.toLowerCase(); + const description = step.description.toLowerCase(); + return name.includes(searchValue) || description.includes(searchValue); + }); + } + + return { steps: filteredSteps }; +}; From 82086c7af43ad3fe493efe90a6ef0319f6eac89e Mon Sep 17 00:00:00 2001 From: Zoltan Szabo Date: Thu, 20 Jun 2024 15:49:45 +0200 Subject: [PATCH 2/8] fix: rename and move reusable step badge --- source/javascripts/_componentRegister.js | 27 +++++++--- .../components/StepBadge/StepBadge.tsx | 52 +++++++++++++++++++ .../StepConfigPanel/StepConfigPanel.tsx | 4 +- .../components/StepItem/AddStepItem.tsx | 8 +-- .../components/StepItem/StepItem.tsx | 8 +-- .../components/StepItem/StepItemBadge.tsx | 37 ------------- 6 files changed, 79 insertions(+), 57 deletions(-) create mode 100644 source/javascripts/components/StepBadge/StepBadge.tsx delete mode 100644 source/javascripts/components/StepItem/StepItemBadge.tsx diff --git a/source/javascripts/_componentRegister.js b/source/javascripts/_componentRegister.js index a7684f37b..90f444cf7 100644 --- a/source/javascripts/_componentRegister.js +++ b/source/javascripts/_componentRegister.js @@ -6,7 +6,7 @@ import InfoTooltip from "./components/InfoTooltip"; import Toggle from "./components/Toggle"; import NotificationMessageWithLink from "./components/NotificationMessageWithLink"; import { AddStepItem, StepItem } from "./components/StepItem"; -import StepItemBadge from "./components/StepItem/StepItemBadge"; +import StepBadge from "./components/StepItem/StepBadge"; import YmlStorageSettings from "./components/YmlStorageSettings/YmlStorageSettings"; import UpdateYmlInRepositoryModal from "./components/UpdateYmlInRepositoryModal/UpdateYmlInRepositoryModal"; import WorkflowSelector from "./components/WorkflowSelector/WorkflowSelector"; @@ -62,7 +62,7 @@ angular "rAddStepItem", register(AddStepItem, ["step", "disabled", "onSelected"]), ) - .component("rStepItemBadge", register(StepItemBadge, ["step"])) + .component("rStepItemBadge", register(StepBadge, ["step"])) .component( "rYmlStorageSettings", register(YmlStorageSettings, [ @@ -175,7 +175,7 @@ angular "onCreateEnvVar", "onLoadEnvVars", "appSlug", - "secretsWriteNew" + "secretsWriteNew", ]), ) .component( @@ -201,6 +201,21 @@ angular "integrationsUrl", ]), ) - .component('rSecretsPage', register(SecretsPage, ['secrets', 'secretsWriteNew', 'onSecretsChange', 'getSecretValue', 'appSlug', 'secretSettingsUrl', 'sharedSecretsAvailable', 'planSelectorPageUrl'])) - .component('rPipelinesPage', register(PipelinesPage, ['yml', 'defaultMeta'])) - .component('rWorkflowConfigPanel', register(WorkflowConfigPanel, ['appSlug', 'defaultValues', 'onChange'])); + .component( + "rSecretsPage", + register(SecretsPage, [ + "secrets", + "secretsWriteNew", + "onSecretsChange", + "getSecretValue", + "appSlug", + "secretSettingsUrl", + "sharedSecretsAvailable", + "planSelectorPageUrl", + ]), + ) + .component("rPipelinesPage", register(PipelinesPage, ["yml", "defaultMeta"])) + .component( + "rWorkflowConfigPanel", + register(WorkflowConfigPanel, ["appSlug", "defaultValues", "onChange"]), + ); diff --git a/source/javascripts/components/StepBadge/StepBadge.tsx b/source/javascripts/components/StepBadge/StepBadge.tsx new file mode 100644 index 000000000..6d84cc581 --- /dev/null +++ b/source/javascripts/components/StepBadge/StepBadge.tsx @@ -0,0 +1,52 @@ +import { Box, BoxProps, Icon, Tooltip } from '@bitrise/bitkit'; + +import deprecatedIcon from '../../../images/step/badge-deprecated.svg'; + +type StepItemBadgeProps = BoxProps & { + isOfficial?: boolean; + isVerified?: boolean; + isDeprecated?: boolean; +}; + +const StepBadge = ({ isOfficial, isVerified, isDeprecated, ...rest }: StepItemBadgeProps) => { + if (isOfficial) { + return ( + + + + + + ); + } + + if (isVerified) { + return ( + + + + + + ); + } + + if (isDeprecated) { + return ( + + + Deprecated + + + ); + } + + return null; +}; + +export default StepBadge; diff --git a/source/javascripts/components/StepConfigPanel/StepConfigPanel.tsx b/source/javascripts/components/StepConfigPanel/StepConfigPanel.tsx index 5446ecc80..da1a38cac 100644 --- a/source/javascripts/components/StepConfigPanel/StepConfigPanel.tsx +++ b/source/javascripts/components/StepConfigPanel/StepConfigPanel.tsx @@ -4,7 +4,7 @@ import { TabPanel, TabPanels } from '@chakra-ui/react'; import { useMutation } from '@tanstack/react-query'; import { monolith } from '../../hooks/api/client'; import { InputCategory, OnStepChange, Step, StepOutputVariable, StepVersionWithRemark } from '../../models'; -import StepItemBadge from '../StepItem/StepItemBadge'; +import StepBadge from '../StepItem/StepBadge'; import { EnvironmentVariable } from '../InsertEnvVarPopover/types'; import EnvVarProvider from '../InsertEnvVarPopover/EnvVarProvider'; import { Secret } from '../InsertSecretPopover/types'; @@ -94,7 +94,7 @@ const StepConfigPanel = ({ {step.displayName()} - - + diff --git a/source/javascripts/components/StepItem/StepItem.tsx b/source/javascripts/components/StepItem/StepItem.tsx index 85ac0d871..f12e61507 100644 --- a/source/javascripts/components/StepItem/StepItem.tsx +++ b/source/javascripts/components/StepItem/StepItem.tsx @@ -2,7 +2,7 @@ import './StepItem.scss'; import 'react-lazy-load-image-component/src/effects/blur.css'; import { Step } from '../../models'; -import StepItemBadge from './StepItemBadge'; +import StepBadge from '../StepBadge/StepBadge'; import StepItemIcon from './StepItemIcon'; import StepItemTitle from './StepItemTitle'; import StepItemVersion from './StepItemVersion'; @@ -41,11 +41,7 @@ const StepItem = ({ - + ( - <> - {isOfficial && ( - - - - )} - {isVerified && ( - - - - )} - {isDeprecated && ( - - Deprecated - - )} - -); - -export default StepItemBadge; From 125c785416ad0465e322051f2d1da2271af10552 Mon Sep 17 00:00:00 2001 From: Zoltan Szabo Date: Thu, 20 Jun 2024 16:03:09 +0200 Subject: [PATCH 3/8] fix: display tags --- source/javascripts/components/StepDrawer/StepDrawer.tsx | 2 +- .../components/StepDrawer/components/StepFilter.tsx | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/javascripts/components/StepDrawer/StepDrawer.tsx b/source/javascripts/components/StepDrawer/StepDrawer.tsx index e72f7460e..1c8277437 100644 --- a/source/javascripts/components/StepDrawer/StepDrawer.tsx +++ b/source/javascripts/components/StepDrawer/StepDrawer.tsx @@ -26,7 +26,7 @@ const StepDrawer = ({ isOpen: isInitialOpen }: Props) => { Add Step - + diff --git a/source/javascripts/components/StepDrawer/components/StepFilter.tsx b/source/javascripts/components/StepDrawer/components/StepFilter.tsx index a455941b4..1aeef168e 100644 --- a/source/javascripts/components/StepDrawer/components/StepFilter.tsx +++ b/source/javascripts/components/StepDrawer/components/StepFilter.tsx @@ -7,7 +7,7 @@ type Props = { const StepFilter = ({ categories = [] }: Props) => { return ( - + ( @@ -19,9 +19,9 @@ const StepFilter = ({ categories = [] }: Props) => { /> )} /> - + {categories.map((category) => ( - {category} + {category} ))} From 1bf9c0ca2015b46ec4fd4ffa3bde82263e3847ef Mon Sep 17 00:00:00 2001 From: Zoltan Szabo Date: Thu, 20 Jun 2024 16:25:43 +0200 Subject: [PATCH 4/8] fix: import in componentRegister --- source/javascripts/_componentRegister.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/javascripts/_componentRegister.js b/source/javascripts/_componentRegister.js index 90f444cf7..0a1818793 100644 --- a/source/javascripts/_componentRegister.js +++ b/source/javascripts/_componentRegister.js @@ -6,7 +6,7 @@ import InfoTooltip from "./components/InfoTooltip"; import Toggle from "./components/Toggle"; import NotificationMessageWithLink from "./components/NotificationMessageWithLink"; import { AddStepItem, StepItem } from "./components/StepItem"; -import StepBadge from "./components/StepItem/StepBadge"; +import StepBadge from "./components/StepBadge/StepBadge"; import YmlStorageSettings from "./components/YmlStorageSettings/YmlStorageSettings"; import UpdateYmlInRepositoryModal from "./components/UpdateYmlInRepositoryModal/UpdateYmlInRepositoryModal"; import WorkflowSelector from "./components/WorkflowSelector/WorkflowSelector"; From 7fd242a721eb1cf23c2e05af66a3eacf057662fd Mon Sep 17 00:00:00 2001 From: Zoltan Szabo Date: Thu, 20 Jun 2024 16:27:41 +0200 Subject: [PATCH 5/8] fix: sort categories --- source/javascripts/components/StepDrawer/hooks/useSteps.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/javascripts/components/StepDrawer/hooks/useSteps.ts b/source/javascripts/components/StepDrawer/hooks/useSteps.ts index 0c7ca22aa..e9c157b33 100644 --- a/source/javascripts/components/StepDrawer/hooks/useSteps.ts +++ b/source/javascripts/components/StepDrawer/hooks/useSteps.ts @@ -11,7 +11,7 @@ export const useSteps = () => { export const useCategories = () => { const { steps } = useSteps(); const categories = useMemo(() => { - return uniq(steps.flatMap((step) => step.categories)); + return uniq(steps.flatMap((step) => step.categories)).sort(); }, [steps]); return { categories }; }; From a9502dad0679b7898c4ec8986b7be9e3f69b42b5 Mon Sep 17 00:00:00 2001 From: Zoltan Szabo Date: Thu, 20 Jun 2024 16:32:31 +0200 Subject: [PATCH 6/8] fix: don't show empty categories --- .../StepDrawer/components/StepList.tsx | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/source/javascripts/components/StepDrawer/components/StepList.tsx b/source/javascripts/components/StepDrawer/components/StepList.tsx index ff1d3f51a..8f61fbd72 100644 --- a/source/javascripts/components/StepDrawer/components/StepList.tsx +++ b/source/javascripts/components/StepDrawer/components/StepList.tsx @@ -11,7 +11,7 @@ type Props = { }; const StepList = ({ categories = [], steps = [] }: Props) => { - const stepByCategories = useMemo( + const stepsByCategories = useMemo( () => steps.reduce( (acc, step) => { @@ -30,14 +30,18 @@ const StepList = ({ categories = [], steps = [] }: Props) => { return ( {categories?.map((category) => ( - - - {displayCategoryName(category)} - - - {stepByCategories[category]?.map((step) => )} - - + <> + {stepsByCategories[category]?.length > 0 && ( + + + {displayCategoryName(category)} + + + {stepsByCategories[category]?.map((step) => )} + + + )} + ))} ); From ea55e6c4d60fb91d0be56d8e540303c2531b5f08 Mon Sep 17 00:00:00 2001 From: Zoltan Szabo Date: Fri, 21 Jun 2024 13:52:08 +0200 Subject: [PATCH 7/8] refactor: extract algolia and yml types and hooks --- .../PipelinesPage/PipelinesPage.mocks.ts | 2 +- .../PipelinesPage/PipelinesPage.tsx | 5 +- .../PipelinesPage/components/StageNode.tsx | 2 +- .../PipelinesPage/components/StepCard.tsx | 4 +- .../PipelinesPage/hooks/useBitriseYmlStore.ts | 2 +- .../components/PipelinesPage/hooks/useMeta.ts | 2 +- .../hooks/usePipelineSelector.ts | 8 +- .../hooks/usePipelineStageNodes.ts | 2 +- .../PipelinesPage/hooks/usePipelineStages.ts | 2 +- ...{useStepCardData.ts => useStepListItem.ts} | 9 +- .../PipelinesPage/hooks/useWorkflow.ts | 2 +- .../PipelinesPage/hooks/useWorkflowChain.ts | 14 +- .../StepConfigPanel/StepConfigPanel.tsx | 2 +- .../components/StepItem/AddStepItem.tsx | 2 +- .../BitriseYmlProvider.tsx | 4 +- .../PipelinesPage => }/hooks/useAlgolia.ts | 0 .../useAlgoliaStep.ts} | 32 +- source/javascripts/hooks/useAlgoliaSteps.ts | 873 ++++++++++++++++++ source/javascripts/models/Algolia.ts | 23 + .../BitriseYml.ts} | 0 20 files changed, 936 insertions(+), 54 deletions(-) rename source/javascripts/components/PipelinesPage/hooks/{useStepCardData.ts => useStepListItem.ts} (87%) rename source/javascripts/{components/PipelinesPage/providers => contexts}/BitriseYmlProvider.tsx (86%) rename source/javascripts/{components/PipelinesPage => }/hooks/useAlgolia.ts (100%) rename source/javascripts/{components/PipelinesPage/hooks/useSearchStep.ts => hooks/useAlgoliaStep.ts} (51%) create mode 100644 source/javascripts/hooks/useAlgoliaSteps.ts create mode 100644 source/javascripts/models/Algolia.ts rename source/javascripts/{components/PipelinesPage/PipelinesPage.types.ts => models/BitriseYml.ts} (100%) diff --git a/source/javascripts/components/PipelinesPage/PipelinesPage.mocks.ts b/source/javascripts/components/PipelinesPage/PipelinesPage.mocks.ts index d298918c6..5cf41101b 100644 --- a/source/javascripts/components/PipelinesPage/PipelinesPage.mocks.ts +++ b/source/javascripts/components/PipelinesPage/PipelinesPage.mocks.ts @@ -1,4 +1,4 @@ -import { BitriseYml } from './PipelinesPage.types'; +import { BitriseYml } from '../../models/BitriseYml'; export const mockYml: BitriseYml = { format_version: '13', diff --git a/source/javascripts/components/PipelinesPage/PipelinesPage.tsx b/source/javascripts/components/PipelinesPage/PipelinesPage.tsx index d46645182..415dba2d7 100644 --- a/source/javascripts/components/PipelinesPage/PipelinesPage.tsx +++ b/source/javascripts/components/PipelinesPage/PipelinesPage.tsx @@ -1,12 +1,11 @@ import 'reactflow/dist/style.css'; - import { Box } from '@bitrise/bitkit'; import withQueryClientProvider from '../../utils/withQueryClientProvider'; -import { BitriseYml, Meta } from './PipelinesPage.types'; +import { BitriseYml, Meta } from '../../models/BitriseYml'; +import BitriseYmlProvider from '../../contexts/BitriseYmlProvider'; import PipelinesHeader from './components/PipelinesHeader'; import PipelinesCanvas from './components/PipelinesCanvas'; import PipelinesEmptyState from './components/PipelinesEmptyState'; -import BitriseYmlProvider from './providers/BitriseYmlProvider'; type Props = { yml: BitriseYml; diff --git a/source/javascripts/components/PipelinesPage/components/StageNode.tsx b/source/javascripts/components/PipelinesPage/components/StageNode.tsx index a3b2acdaa..79f7d9b77 100644 --- a/source/javascripts/components/PipelinesPage/components/StageNode.tsx +++ b/source/javascripts/components/PipelinesPage/components/StageNode.tsx @@ -1,7 +1,7 @@ import { Box, Text } from '@bitrise/bitkit'; import { NodeProps, Position } from 'reactflow'; -import { Stage } from '../PipelinesPage.types'; import { STAGE_WIDTH } from '../PipelinesPage.const'; +import { Stage } from '../../../models/BitriseYml'; import InvisibleHandle from './InvisibleHandle'; import WorkflowCard from './WorkflowCard'; diff --git a/source/javascripts/components/PipelinesPage/components/StepCard.tsx b/source/javascripts/components/PipelinesPage/components/StepCard.tsx index be959920d..541827ed3 100644 --- a/source/javascripts/components/PipelinesPage/components/StepCard.tsx +++ b/source/javascripts/components/PipelinesPage/components/StepCard.tsx @@ -1,5 +1,5 @@ import { Avatar, Box, Card, Skeleton, SkeletonBox, Text } from '@bitrise/bitkit'; -import useStepCardData from '../hooks/useStepCardData'; +import useStepListItem from '../hooks/useStepListItem'; type StepCardProps = { cvs: string; @@ -14,7 +14,7 @@ const StepCard = ({ cvs, title, icon, showSecondary = true }: StepCardProps) => icon: resolvedIcon, normalizedVersion, isLoading, - } = useStepCardData({ cvs, title, icon }); + } = useStepListItem({ cvs, title, icon }); if (isLoading) { return ( diff --git a/source/javascripts/components/PipelinesPage/hooks/useBitriseYmlStore.ts b/source/javascripts/components/PipelinesPage/hooks/useBitriseYmlStore.ts index 758bbbb5f..00ed732eb 100644 --- a/source/javascripts/components/PipelinesPage/hooks/useBitriseYmlStore.ts +++ b/source/javascripts/components/PipelinesPage/hooks/useBitriseYmlStore.ts @@ -1,6 +1,6 @@ import { useContext } from 'react'; import { useStore } from 'zustand'; -import { BitriseYmlContext, BitriseYmlProviderState } from '../providers/BitriseYmlProvider'; +import { BitriseYmlContext, BitriseYmlProviderState } from '../../../contexts/BitriseYmlProvider'; const useBitriseYmlStore = (selector: (state: BitriseYmlProviderState) => U) => { const store = useContext(BitriseYmlContext); diff --git a/source/javascripts/components/PipelinesPage/hooks/useMeta.ts b/source/javascripts/components/PipelinesPage/hooks/useMeta.ts index 36c0557ec..69d42d99b 100644 --- a/source/javascripts/components/PipelinesPage/hooks/useMeta.ts +++ b/source/javascripts/components/PipelinesPage/hooks/useMeta.ts @@ -1,6 +1,6 @@ import { useShallow } from 'zustand/react/shallow'; import merge from 'lodash/merge'; -import { Meta } from '../PipelinesPage.types'; +import { Meta } from '../../../models/BitriseYml'; import useBitriseYmlStore from './useBitriseYmlStore'; type Props = { diff --git a/source/javascripts/components/PipelinesPage/hooks/usePipelineSelector.ts b/source/javascripts/components/PipelinesPage/hooks/usePipelineSelector.ts index b1aa75e1f..2ec09f7a2 100644 --- a/source/javascripts/components/PipelinesPage/hooks/usePipelineSelector.ts +++ b/source/javascripts/components/PipelinesPage/hooks/usePipelineSelector.ts @@ -1,5 +1,6 @@ import { useCallback } from 'react'; import { useShallow } from 'zustand/react/shallow'; +import { Pipeline } from '../../../models/BitriseYml'; import useSearchParams from './useSearchParams'; import useBitriseYmlStore from './useBitriseYmlStore'; @@ -7,7 +8,7 @@ const usePipelineSelector = () => { const options = useBitriseYmlStore( useShallow(({ yml }) => { return Object.fromEntries( - Object.entries(yml.pipelines ?? {}).map(([pipelineKey, pipeline]) => { + Object.entries(yml.pipelines ?? {}).map(([pipelineKey, pipeline]) => { return [pipelineKey, pipeline.title || pipelineKey]; }), ); @@ -22,7 +23,10 @@ const usePipelineSelector = () => { const onSelectPipeline = useCallback( (key: string) => { - setSearchParams((prevSearchParams) => ({ ...prevSearchParams, pipeline: key })); + setSearchParams((prevSearchParams) => ({ + ...prevSearchParams, + pipeline: key, + })); }, [setSearchParams], ); diff --git a/source/javascripts/components/PipelinesPage/hooks/usePipelineStageNodes.ts b/source/javascripts/components/PipelinesPage/hooks/usePipelineStageNodes.ts index 8e363e5f2..e366fb68f 100644 --- a/source/javascripts/components/PipelinesPage/hooks/usePipelineStageNodes.ts +++ b/source/javascripts/components/PipelinesPage/hooks/usePipelineStageNodes.ts @@ -1,6 +1,6 @@ import { Node, Position } from 'reactflow'; -import { Stage } from '../PipelinesPage.types'; import { CANVAS_PADDING, ICON_STAGE_WIDTH, STAGE_GAP, STAGE_WIDTH } from '../PipelinesPage.const'; +import { Stage } from '../../../models/BitriseYml'; import usePipelineStages from './usePipelineStages'; const commonNodeProps: Partial = { diff --git a/source/javascripts/components/PipelinesPage/hooks/usePipelineStages.ts b/source/javascripts/components/PipelinesPage/hooks/usePipelineStages.ts index 393a0dea4..e345861c3 100644 --- a/source/javascripts/components/PipelinesPage/hooks/usePipelineStages.ts +++ b/source/javascripts/components/PipelinesPage/hooks/usePipelineStages.ts @@ -1,6 +1,6 @@ import { useShallow } from 'zustand/react/shallow'; import merge from 'lodash/merge'; -import { Stage } from '../PipelinesPage.types'; +import { Stage } from '../../../models/BitriseYml'; import useBitriseYmlStore from './useBitriseYmlStore'; import usePipelineSelector from './usePipelineSelector'; diff --git a/source/javascripts/components/PipelinesPage/hooks/useStepCardData.ts b/source/javascripts/components/PipelinesPage/hooks/useStepListItem.ts similarity index 87% rename from source/javascripts/components/PipelinesPage/hooks/useStepCardData.ts rename to source/javascripts/components/PipelinesPage/hooks/useStepListItem.ts index b6838f572..2ff7c2edd 100644 --- a/source/javascripts/components/PipelinesPage/hooks/useStepCardData.ts +++ b/source/javascripts/components/PipelinesPage/hooks/useStepListItem.ts @@ -1,7 +1,8 @@ import semver from 'semver'; + import defaultIcon from '../../../../images/step/icon-default.svg'; +import useAlgoliaStep from '../../../hooks/useAlgoliaStep'; import { isStepLib, normalizeVersion, parseCvs } from '../utils/steps'; -import useSearchStep from './useSearchStep'; type Props = { cvs: string; @@ -18,9 +19,9 @@ type StepCardData = { resolvedVersion: string; }; -const useStepCardData = ({ cvs, title, icon }: Props): StepCardData => { +const useStepListItem = ({ cvs, title, icon }: Props): StepCardData => { const [id = '', version = ''] = parseCvs(cvs); - const { data, isLoading } = useSearchStep({ + const { data, isLoading } = useAlgoliaStep({ id, enabled: isStepLib(cvs), attributesToRetrieve: ['id', 'version', 'cvs', 'step.title', 'info.asset_urls', 'step.asset_urls'], @@ -47,4 +48,4 @@ const useStepCardData = ({ cvs, title, icon }: Props): StepCardData => { }; }; -export default useStepCardData; +export default useStepListItem; diff --git a/source/javascripts/components/PipelinesPage/hooks/useWorkflow.ts b/source/javascripts/components/PipelinesPage/hooks/useWorkflow.ts index 9a28d2d7f..e1dcddd32 100644 --- a/source/javascripts/components/PipelinesPage/hooks/useWorkflow.ts +++ b/source/javascripts/components/PipelinesPage/hooks/useWorkflow.ts @@ -1,5 +1,5 @@ import { useShallow } from 'zustand/react/shallow'; -import { Workflow } from '../PipelinesPage.types'; +import { Workflow } from '../../../models/BitriseYml'; import useBitriseYmlStore from './useBitriseYmlStore'; type Props = { diff --git a/source/javascripts/components/PipelinesPage/hooks/useWorkflowChain.ts b/source/javascripts/components/PipelinesPage/hooks/useWorkflowChain.ts index 34d82f903..2f6c83df8 100644 --- a/source/javascripts/components/PipelinesPage/hooks/useWorkflowChain.ts +++ b/source/javascripts/components/PipelinesPage/hooks/useWorkflowChain.ts @@ -1,31 +1,31 @@ import { useShallow } from 'zustand/react/shallow'; -import { BitriseYml } from '../PipelinesPage.types'; +import { BitriseYml } from '../../../models/BitriseYml'; import useBitriseYmlStore from './useBitriseYmlStore'; type Props = { id: string; }; -const extracBeforeRunChain = (yml: BitriseYml, id: string): string[] => { +const extractBeforeRunChain = (yml: BitriseYml, id: string): string[] => { const ids = yml.workflows?.[id]?.before_run ?? []; return ids.reduce((mergedIds, currentId) => { - return [...mergedIds, ...extracBeforeRunChain(yml, currentId), currentId]; + return [...mergedIds, ...extractBeforeRunChain(yml, currentId), currentId]; }, []); }; -const extracAfterRunChain = (yml: BitriseYml, id: string): string[] => { +const extractAfterRunChain = (yml: BitriseYml, id: string): string[] => { const ids = yml.workflows?.[id]?.after_run ?? []; return ids.reduce((mergedIds, currentId) => { - return [...mergedIds, currentId, ...extracAfterRunChain(yml, currentId)]; + return [...mergedIds, currentId, ...extractAfterRunChain(yml, currentId)]; }, []); }; export const useBeforeRunWorkflows = ({ id }: Props) => { - return useBitriseYmlStore(useShallow(({ yml }) => extracBeforeRunChain(yml, id))); + return useBitriseYmlStore(useShallow(({ yml }) => extractBeforeRunChain(yml, id))); }; export const useAfterRunWorkflows = ({ id }: Props) => { - return useBitriseYmlStore(useShallow(({ yml }) => extracAfterRunChain(yml, id))); + return useBitriseYmlStore(useShallow(({ yml }) => extractAfterRunChain(yml, id))); }; diff --git a/source/javascripts/components/StepConfigPanel/StepConfigPanel.tsx b/source/javascripts/components/StepConfigPanel/StepConfigPanel.tsx index da1a38cac..2a3933661 100644 --- a/source/javascripts/components/StepConfigPanel/StepConfigPanel.tsx +++ b/source/javascripts/components/StepConfigPanel/StepConfigPanel.tsx @@ -4,11 +4,11 @@ import { TabPanel, TabPanels } from '@chakra-ui/react'; import { useMutation } from '@tanstack/react-query'; import { monolith } from '../../hooks/api/client'; import { InputCategory, OnStepChange, Step, StepOutputVariable, StepVersionWithRemark } from '../../models'; -import StepBadge from '../StepItem/StepBadge'; import { EnvironmentVariable } from '../InsertEnvVarPopover/types'; import EnvVarProvider from '../InsertEnvVarPopover/EnvVarProvider'; import { Secret } from '../InsertSecretPopover/types'; import SecretsProvider from '../InsertSecretPopover/SecretsProvider'; +import StepBadge from '../StepBadge/StepBadge'; import StepConfiguration from './StepConfiguration'; import StepOutputVariables from './StepOutputVariables'; import StepProperties from './StepProperties'; diff --git a/source/javascripts/components/StepItem/AddStepItem.tsx b/source/javascripts/components/StepItem/AddStepItem.tsx index 562494681..bb1453a15 100644 --- a/source/javascripts/components/StepItem/AddStepItem.tsx +++ b/source/javascripts/components/StepItem/AddStepItem.tsx @@ -2,7 +2,7 @@ import { Box, Icon } from '@bitrise/bitkit'; import { Step } from '../../models'; import MarkdownText from '../MarkdownText'; -import StepBadge from './StepBadge'; +import StepBadge from '../StepBadge/StepBadge'; import StepItemIcon from './StepItemIcon'; import StepItemTitle from './StepItemTitle'; diff --git a/source/javascripts/components/PipelinesPage/providers/BitriseYmlProvider.tsx b/source/javascripts/contexts/BitriseYmlProvider.tsx similarity index 86% rename from source/javascripts/components/PipelinesPage/providers/BitriseYmlProvider.tsx rename to source/javascripts/contexts/BitriseYmlProvider.tsx index b1e8da249..0f06181df 100644 --- a/source/javascripts/components/PipelinesPage/providers/BitriseYmlProvider.tsx +++ b/source/javascripts/contexts/BitriseYmlProvider.tsx @@ -1,6 +1,6 @@ -import { PropsWithChildren, createContext, useRef } from 'react'; +import { createContext, PropsWithChildren, useRef } from 'react'; import { createStore } from 'zustand'; -import { BitriseYml, Meta } from '../PipelinesPage.types'; +import { BitriseYml, Meta } from '../models/BitriseYml'; type BitriseYmlProviderProps = PropsWithChildren<{ yml: BitriseYml; diff --git a/source/javascripts/components/PipelinesPage/hooks/useAlgolia.ts b/source/javascripts/hooks/useAlgolia.ts similarity index 100% rename from source/javascripts/components/PipelinesPage/hooks/useAlgolia.ts rename to source/javascripts/hooks/useAlgolia.ts diff --git a/source/javascripts/components/PipelinesPage/hooks/useSearchStep.ts b/source/javascripts/hooks/useAlgoliaStep.ts similarity index 51% rename from source/javascripts/components/PipelinesPage/hooks/useSearchStep.ts rename to source/javascripts/hooks/useAlgoliaStep.ts index 0c73e8dec..3ba9beadf 100644 --- a/source/javascripts/components/PipelinesPage/hooks/useSearchStep.ts +++ b/source/javascripts/hooks/useAlgoliaStep.ts @@ -1,48 +1,30 @@ import { useQuery, UseQueryResult } from '@tanstack/react-query'; import { Paths } from 'type-fest'; -import { Step } from '../PipelinesPage.types'; +import { AlgoliaStepResponse } from '../models/Algolia'; import useAlgolia from './useAlgolia'; -type AlgoliaStepData = Partial<{ - readonly objectID: string; - cvs: string; - id: string; - version: string; - is_deprecated: boolean; - is_latest: boolean; - latest_version_number: string; - step: Partial; - info: { - maintainer?: string; - asset_urls?: Step['asset_urls'] & { - 'icon.svg'?: string; - 'icon.png'?: string; - }; - }; -}>; - type Props = { id: string; enabled?: boolean; latestOnly?: boolean; - attributesToRetrieve?: Paths[] | ['*']; + attributesToRetrieve?: Paths[] | ['*']; }; -const useSearchStep = ({ +const useAlgoliaStep = ({ id, enabled, latestOnly, attributesToRetrieve, -}: Props): UseQueryResult> => { +}: Props): UseQueryResult> => { const { algoliaStepsClient } = useAlgolia(); return useQuery({ enabled, queryKey: [id, latestOnly, attributesToRetrieve] as const, queryFn: async ({ queryKey: [_id, _latestOnly, _attributesToRetrieve = ['*']] }) => { - const results: Array = []; + const results: Array = []; - await algoliaStepsClient.browseObjects({ + await algoliaStepsClient.browseObjects({ batch: (batch) => results.push(...batch), attributesToRetrieve: _attributesToRetrieve, filters: _latestOnly ? `id:${_id} AND is_latest:true` : `id:${_id}`, @@ -53,4 +35,4 @@ const useSearchStep = ({ }); }; -export default useSearchStep; +export default useAlgoliaStep; diff --git a/source/javascripts/hooks/useAlgoliaSteps.ts b/source/javascripts/hooks/useAlgoliaSteps.ts new file mode 100644 index 000000000..bc89ff50e --- /dev/null +++ b/source/javascripts/hooks/useAlgoliaSteps.ts @@ -0,0 +1,873 @@ +import { useMemo } from 'react'; +import { AlgoliaStepResponse } from '../models/Algolia'; + +export const MockSteps: AlgoliaStepResponse[] = [ + { + info: { + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/activate-ssh-key/assets/icon.svg', + }, + maintainer: 'bitrise', + }, + latest_version_number: '4.1.1', + cvs: 'activate-ssh-key@4.1.1', + id: 'activate-ssh-key', + version: '4.1.1', + is_latest: true, + is_deprecated: false, + step: { + title: 'Activate SSH key (RSA private key)', + summary: 'Add your SSH key to the build machine to access private repositories', + description: + "This Step makes sure Bitrise has access to your repository when cloning SSH URLs. The Step saves the provided private key of your SSH keypair to a file and then loads it into the SSH agent.\n\n### Configuring the Step\n\nBy default, you do not have to change anything about the Step's configuration.\n\nThe step downloads the SSH key defined in your App Settings, so most of the time it's the only thing you need to configure ([more info](https://devcenter.bitrise.io/en/connectivity/configuring-ssh-keys).\n\n All you need to do is make sure that you registered your key pair on Bitrise and the public key at your Git provider. You can generate and register an SSH keypair in two ways.\n\n- Automatically during the [app creation process](https://devcenter.bitrise.io/getting-started/adding-a-new-app/#setting-up-ssh-keys).\n- Manually during the app creation process or at any other time. You [generate your own SSH keys](https://devcenter.bitrise.io/faq/how-to-generate-ssh-keypair/) and register them on Bitrise and at your Git provider. The SSH key should not have a passphrase!\n\nNote: if you configure to use HTTPS instead of SSH git access, you don't need to use this Step.\n\n### Troubleshooting\n\nIf the Step fails, check the public key registered to your Git repository and compare it to the public key registered on Bitrise. The most frequent issue is that someone deleted or revoked the key on your Git provider's website.\n\nYou can also set the **Enable verbose logging** input to `true`. This provides additional information in the log.\n\n### Useful links\n\n- [Setting up SSH keys](https://devcenter.bitrise.io/getting-started/adding-a-new-app/#setting-up-ssh-keys)\n- [How can I generate an SSH key pair?](https://devcenter.bitrise.io/faq/how-to-generate-ssh-keypair/)\n\n### Related Steps\n\n- [Git Clone Repository](https://www.bitrise.io/integrations/steps/git-clone)", + website: 'https://github.com/bitrise-steplib/steps-activate-ssh-key', + source_code_url: 'https://github.com/bitrise-steplib/steps-activate-ssh-key', + support_url: 'https://github.com/bitrise-steplib/steps-activate-ssh-key/issues', + published_at: '2024-02-15T10:28:29.203495657Z', + source: { + git: 'https://github.com/bitrise-steplib/steps-activate-ssh-key.git', + commit: '78dae4ddaa4a2c3eddb35a3fc620b5fdf29fc82c', + }, + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/activate-ssh-key/assets/icon.svg', + }, + type_tags: ['access-control'], + toolkit: { + go: { + package_name: 'github.com/bitrise-steplib/steps-activate-ssh-key', + }, + }, + deps: { + apt_get: [ + { + name: 'expect', + }, + { + name: 'git', + }, + ], + }, + is_requires_admin_user: false, + is_always_run: false, + is_skippable: false, + run_if: '.IsCI', + timeout: 0, + outputs: [ + { + SSH_AUTH_SOCK: null, + opts: { + category: '', + description: + 'If the `is_should_start_new_agent` option is enabled, and no accessible ssh-agent is found, the step will start a new ssh-agent.\n\nThis output contains the path of the socket created by ssh-agent, which can be used to access the started ssh-agent ([learn more](https://www.man7.org/linux/man-pages/man1/ssh-agent.1.html))', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'SSH agent socket path', + unset: false, + }, + }, + ], + }, + objectID: '41256190000', + }, + { + info: { + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/git-clone/assets/icon.svg', + }, + maintainer: 'bitrise', + }, + latest_version_number: '8.2.2', + cvs: 'git-clone@8.2.2', + id: 'git-clone', + version: '8.2.2', + is_latest: true, + is_deprecated: false, + step: { + title: 'Git Clone Repository', + summary: 'Checks out the repository, updates submodules and exports git metadata as Step outputs.', + description: + 'The checkout process depends on the Step settings and the build trigger parameters (coming from your git server).\n\nDepending on the conditions, the step can checkout:\n- the merged state of a Pull Request\n- the head of a Pull Request\n- a git tag\n- a specific commit on a branch\n- the head of a branch\n\nThe Step also supports more advanced features, such as updating submodules and sparse checkouts.\n\n### Configuring the Step\n\nThe step should work with its default configuration if build triggers and webhooks are set up correctly.\n\nBy default, the Step performs a shallow clone in most cases (fetching only the latest commit) to make the clone fast and efficient. If your workflow requires a deeper commit history, you can override this using the **Clone depth** input.\n\n### Useful links\n\n- [How to register a GitHub Enterprise repository](https://discuss.bitrise.io/t/how-to-register-a-github-enterprise-repository/218)\n- [Code security](https://devcenter.bitrise.io/getting-started/code-security/)\n\n### Related Steps\n\n- [Activate SSH key (RSA private key)](https://www.bitrise.io/integrations/steps/activate-ssh-key)\n- [Generate changelog](https://bitrise.io/integrations/steps/generate-changelog)\n', + website: 'https://github.com/bitrise-steplib/steps-git-clone', + source_code_url: 'https://github.com/bitrise-steplib/steps-git-clone', + support_url: 'https://github.com/bitrise-steplib/steps-git-clone/issues', + published_at: '2024-06-03T06:38:20.120933072Z', + source: { + git: 'https://github.com/bitrise-steplib/steps-git-clone.git', + commit: 'bed9fb1a27d3904197977a90c643f234deedad29', + }, + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/git-clone/assets/icon.svg', + }, + type_tags: ['utility'], + toolkit: { + go: { + package_name: 'github.com/bitrise-steplib/steps-git-clone', + }, + }, + is_requires_admin_user: false, + is_always_run: false, + is_skippable: false, + run_if: '.IsCI', + timeout: 0, + outputs: [ + { + GIT_CLONE_COMMIT_HASH: null, + opts: { + category: '', + description: 'SHA hash of the checked-out commit.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Commit hash', + unset: false, + }, + }, + { + GIT_CLONE_COMMIT_MESSAGE_SUBJECT: null, + opts: { + category: '', + description: 'Commit message of the checked-out commit.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Commit message subject', + unset: false, + }, + }, + { + GIT_CLONE_COMMIT_MESSAGE_BODY: null, + opts: { + category: '', + description: 'Commit message body of the checked-out commit.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Commit message body', + unset: false, + }, + }, + { + GIT_CLONE_COMMIT_COUNT: null, + opts: { + category: '', + description: + 'Commit count after checkout.\n\nCount will only work properly if no `--depth` option is set. If `--depth` is set then the history truncated to the specified number of commits. Count will **not** fail but will be the clone depth.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Commit count', + unset: false, + }, + }, + { + GIT_CLONE_COMMIT_AUTHOR_NAME: null, + opts: { + category: '', + description: 'Author of the checked-out commit.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Commit author name', + unset: false, + }, + }, + { + GIT_CLONE_COMMIT_AUTHOR_EMAIL: null, + opts: { + category: '', + description: 'Email of the checked-out commit.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Commit author email', + unset: false, + }, + }, + { + GIT_CLONE_COMMIT_COMMITTER_NAME: null, + opts: { + category: '', + description: 'Committer name of the checked-out commit.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Committer name', + unset: false, + }, + }, + { + GIT_CLONE_COMMIT_COMMITTER_EMAIL: null, + opts: { + category: '', + description: 'Email of the checked-out commit.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Committer email', + unset: false, + }, + }, + ], + }, + objectID: '11414446002', + }, + { + info: { + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/npm/assets/icon.svg', + }, + maintainer: 'bitrise', + }, + latest_version_number: '1.1.6', + cvs: 'npm@1.1.6', + id: 'npm', + version: '1.1.6', + is_latest: true, + is_deprecated: false, + step: { + title: 'Run npm command', + summary: + "The Step runs npm with the command and arguments you provide, for example, to install missing packages or run a package's test.", + description: + "You can install missing JS dependencies with this Step if you insert it before any build step and provide the `install` command.\nYou can also test certain packages with the `test` command.\nYou can do both in one Workflow, however, this requires one **Run npm command** Step for installation followed by another **Run npm command** Step for testing purposes.\n\n### Configuring the Step\n1. Add the **Run npm command** Step to your Workflow preceding any build Step.\n2. Set the **Working directory**.\n3. Set the command you want npm to execute, for example `install` to run `npm install` in the **The npm command with arguments to run** input.\n4. If you're looking for a particular npm version, you can set it in the **Version of npm to use** input.\n5. You can cache the content of the node modules directory if you select `true` in the drop-down.\nBy default this input is set to false.\n\n### Troubleshooting\nMake sure you insert the Step before any build Step so that every dependency is downloaded a build Step starts running.\n\n### Useful links\n- [Getting started Ionic/Cordova apps](https://devcenter.bitrise.io/getting-started/getting-started-with-ionic-cordova-apps/)\n- [About npm](https://www.npmjs.com/)", + website: 'https://github.com/bitrise-steplib/steps-npm', + source_code_url: 'https://github.com/bitrise-steplib/steps-npm', + support_url: 'https://github.com/bitrise-steplib/steps-npm/issues', + published_at: '2022-07-15T09:23:38.232730219Z', + source: { + git: 'https://github.com/bitrise-steplib/steps-npm.git', + commit: '15f3332c80aa12f4c83b37bd0cbe71a2bbf0a9ff', + }, + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/npm/assets/icon.svg', + }, + host_os_tags: ['osx-10.10'], + type_tags: ['utility'], + toolkit: { + go: { + package_name: 'github.com/bitrise-steplib/steps-npm', + }, + }, + deps: { + apt_get: [ + { + name: 'nodejs', + }, + ], + }, + is_requires_admin_user: false, + is_always_run: false, + is_skippable: false, + run_if: '', + timeout: 0, + }, + objectID: '33867475001', + }, + { + info: { + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/xcode-test/assets/icon.svg', + }, + maintainer: 'bitrise', + }, + latest_version_number: '5.1.1', + cvs: 'xcode-test@5.1.1', + id: 'xcode-test', + version: '5.1.1', + is_latest: true, + is_deprecated: false, + step: { + title: 'Xcode Test for iOS', + summary: "Runs your project's pre-defined Xcode tests on every build.", + description: + "This Steps runs all those Xcode tests that are included in your project.\nThe Step will work out of the box if your project has test targets and your Workflow has the **Deploy to Bitrise.io** Step which exports the test results and (code coverage files if needed) to the Test Reports page.\nThis Step does not need any code signing files since the Step deploys only the test results to [bitrise.io](https://www.bitrise.io).\n\n### Configuring the Step\nIf you click into the Step, there are some required input fields whose input must be set in accordance with the Xcode configuration of the project.\nThe **Scheme** input field must be marked as Shared in Xcode.\n\n### Troubleshooting\nIf the **Deploy to Bitrise.io** Step is missing from your Workflow, then the **Xcode Test for iOS** Step will not be able to export the test results on the Test Reports page and you won't be able to view them either.\nThe xcpretty output tool does not support parallel tests.\nIf parallel tests are enabled in your project, go to the Step's **xcodebuild log formatting** section and set the **Log formatter** input's value to `xcodebuild` or `xcbeautify`.\nIf the Xcode test fails with the error `Unable to find a destination matching the provided destination specifier`, then check our [system reports](https://stacks.bitrise.io) to see if the requested simulator is on the stack or not.\nIf it is not, then pick a simulator that is on the stack.\n\n### Useful links\n- [About Test Reports](https://devcenter.bitrise.io/testing/test-reports/)\n- [Running Xcode Tests for iOS](https://devcenter.bitrise.io/testing/running-xcode-tests/)\n\n### Related Steps\n- [Deploy to Bitrise.io](https://www.bitrise.io/integrations/steps/deploy-to-bitrise-io)\n- [iOS Device Testing](https://www.bitrise.io/integrations/steps/virtual-device-testing-for-ios)", + website: 'https://github.com/bitrise-steplib/steps-xcode-test', + source_code_url: 'https://github.com/bitrise-steplib/steps-xcode-test', + support_url: 'https://github.com/bitrise-steplib/steps-xcode-test/issues', + published_at: '2024-04-08T11:03:54.789032239Z', + source: { + git: 'https://github.com/bitrise-steplib/steps-xcode-test.git', + commit: '497f1110471c51c363331fd306a205e8a56bff64', + }, + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/xcode-test/assets/icon.svg', + }, + project_type_tags: ['ios', 'cordova', 'ionic', 'react-native', 'flutter'], + type_tags: ['test'], + toolkit: { + go: { + package_name: 'github.com/bitrise-steplib/steps-xcode-test', + }, + }, + is_requires_admin_user: false, + is_always_run: false, + is_skippable: false, + run_if: '', + timeout: 0, + outputs: [ + { + BITRISE_XCODE_TEST_RESULT: null, + opts: { + category: '', + description: "Result of the tests. 'succeeded' or 'failed'.", + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Test result', + unset: false, + value_options: ['succeeded', 'failed'], + }, + }, + { + BITRISE_XCRESULT_PATH: null, + opts: { + category: '', + description: 'The path of the generated `.xcresult`.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'The path of the generated `.xcresult`', + unset: false, + }, + }, + { + BITRISE_XCRESULT_ZIP_PATH: null, + opts: { + category: '', + description: 'The path of the zipped `.xcresult`.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'The path of the zipped `.xcresult`', + unset: false, + }, + }, + { + BITRISE_XCODE_TEST_ATTACHMENTS_PATH: null, + opts: { + category: '', + description: 'This is the path of the test attachments zip.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'The full, test attachments zip path', + unset: false, + }, + }, + { + BITRISE_XCODEBUILD_BUILD_LOG_PATH: null, + opts: { + category: '', + description: + 'If `single_build` is set to false, the step runs `xcodebuild build` before the test,\nand exports the raw xcodebuild log.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'xcodebuild build command log file path', + unset: false, + }, + }, + { + BITRISE_XCODEBUILD_TEST_LOG_PATH: null, + opts: { + category: '', + description: 'The step exports the `xcodebuild test` command output log.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'xcodebuild test command log file path', + unset: false, + }, + }, + ], + }, + objectID: '44270676001', + }, + { + info: { + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/xcode-archive/assets/icon.svg', + }, + maintainer: 'bitrise', + }, + latest_version_number: '5.1.1', + cvs: 'xcode-archive@5.1.1', + id: 'xcode-archive', + version: '5.1.1', + is_latest: true, + is_deprecated: false, + step: { + title: 'Xcode Archive & Export for iOS', + summary: 'Automatically manages your code signing assets, archives and exports an .ipa in one Step.', + description: + "The Step archives your Xcode project by running the `xcodebuild archive` command and then exports the archive into an .ipa file with the `xcodebuild -exportArchive` command.\nThis .ipa file can be shared, installed on test devices, or uploaded to the App Store Connect.\nWith this Step, you can use automatic code signing in a [CI environment without having to use Xcode](https://developer.apple.com/documentation/xcode-release-notes/xcode-13-release-notes).\nIn short, the Step:\n- Logs you into your Apple Developer account based on the [Apple service connection you provide on Bitrise](https://devcenter.bitrise.io/en/accounts/connecting-to-services/apple-services-connection.html).\n- Downloads any provisioning profiles needed for your project based on the **Distribution method**.\n- Runs your build. It archives your Xcode project by running the `xcodebuild archive` command and exports the archive into an .ipa file with the `xcodebuild -exportArchive` command.\nThis .ipa file can be shared and installed on test devices, or uploaded to App Store Connect.\n\n### Configuring the Step\nBefore you start:\n- Make sure you have connected your [Apple Service account to Bitrise](https://devcenter.bitrise.io/en/accounts/connecting-to-services/apple-services-connection.html).\nAlternatively, you can upload certificates and profiles to Bitrise manually, then use the Certificate and Profile installer step before Xcode Archive\n- Make sure certificates are uploaded to Bitrise's **Code Signing** tab. The right provisioning profiles are automatically downloaded from Apple as part of the automatic code signing process.\n\nTo configure the Step:\n1. **Project path**: Add the path where the Xcode Project or Workspace is located.\n2. **Scheme**: Add the scheme name you wish to archive your project later.\n3. **Distribution method**: Select the method Xcode should sign your project: development, app-store, ad-hoc, or enterprise.\n\nUnder **xcodebuild configuration**:\n1. **Build configuration**: Specify Xcode Build Configuration. The Step uses the provided Build Configuration's Build Settings to understand your project's code signing configuration. If not provided, the Archive action's default Build Configuration will be used.\n2. **Build settings (xcconfig)**: Build settings to override the project's build settings. Can be the contents, file path or empty.\n3. **Perform clean action**: If this input is set, a `clean` xcodebuild action will be performed besides the `archive` action.\n\nUnder **Xcode build log formatting**:\n1. **Log formatter**: Defines how `xcodebuild` command's log is formatted. Available options are `xcpretty`: The xcodebuild command's output will be prettified by xcpretty. `xcodebuild`: Only the last 20 lines of raw xcodebuild output will be visible in the build log.\nThe raw xcodebuild log is exported in both cases.\n\nUnder **Automatic code signing**:\n1. **Automatic code signing method**: Select the Apple service connection you want to use for code signing. Available options: `off` if you don't do automatic code signing, `api-key` [if you use API key authorization](https://devcenter.bitrise.io/en/accounts/connecting-to-services/connecting-to-an-apple-service-with-api-key.html), and `apple-id` [if you use Apple ID authorization](https://devcenter.bitrise.io/en/accounts/connecting-to-services/connecting-to-an-apple-service-with-apple-id.html).\n2. **Register test devices on the Apple Developer Portal**: If this input is set, the Step will register the known test devices on Bitrise from team members with the Apple Developer Portal. Note that setting this to `yes` may cause devices to be registered against your limited quantity of test devices in the Apple Developer Portal, which can only be removed once annually during your renewal window.\n3. **The minimum days the Provisioning Profile should be valid**: If this input is set to >0, the managed Provisioning Profile will be renewed if it expires within the configured number of days. Otherwise the Step renews the managed Provisioning Profile if it is expired.\n4. The **Code signing certificate URL**, the **Code signing certificate passphrase**, the **Keychain path**, and the **Keychain password** inputs are automatically populated if certificates are uploaded to Bitrise's **Code Signing** tab. If you store your files in a private repo, you can manually edit these fields.\n\nIf you want to set the Apple service connection credentials on the step-level (instead of using the one configured in the App Settings), use the Step inputs in the **App Store Connect connection override** category. Note that this only works if **Automatic code signing method** is set to `api-key`.\n\nUnder **IPA export configuration**:\n1. **Developer Portal team**: Add the Developer Portal team's name to use for this export. This input defaults to the team used to build the archive.\n2. **Rebuild from bitcode**: For non-App Store exports, should Xcode re-compile the app from bitcode?\n3. **Include bitcode**: For App Store exports, should the package include bitcode?\n4. **iCloud container environment**: If the app is using CloudKit, this input configures the `com.apple.developer.icloud-container-environment` entitlement. Available options vary depending on the type of provisioning profile used, but may include: `Development` and `Production`.\n5. **Export options plist content**: Specifies a `plist` file content that configures archive exporting. If not specified, the Step will auto-generate it.\n\nUnder **Step Output Export configuration**:\n1. **Output directory path**: This directory will contain the generated artifacts.\n2. **Export all dSYMs**: Export additional dSYM files besides the app dSYM file for Frameworks.\n3. **Override generated artifact names**: This name is used as basename for the generated Xcode archive, app, `.ipa` and dSYM files. If not specified, the Product Name (`PRODUCT_NAME`) Build settings value will be used. If Product Name is not specified, the Scheme will be used.\n\nUnder **Caching**:\n1. **Enable collecting cache content**: Defines what cache content should be automatically collected. Available options are `none`: Disable collecting cache content and `swift_packages`: Collect Swift PM packages added to the Xcode project\n\nUnder Debugging:\n1. **Verbose logging***: You can set this input to `yes` to produce more informative logs.", + website: 'https://github.com/bitrise-steplib/steps-xcode-archive', + source_code_url: 'https://github.com/bitrise-steplib/steps-xcode-archive', + support_url: 'https://github.com/bitrise-steplib/steps-xcode-archive/issues', + published_at: '2024-02-27T13:42:22.968743737Z', + source: { + git: 'https://github.com/bitrise-steplib/steps-xcode-archive.git', + commit: 'f7d8619ec543651ff9bd65eafcc69452f4158ea2', + }, + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/xcode-archive/assets/icon.svg', + }, + project_type_tags: ['ios', 'react-native', 'flutter'], + type_tags: ['build'], + toolkit: { + go: { + package_name: 'github.com/bitrise-steplib/steps-xcode-archive', + }, + }, + is_requires_admin_user: false, + is_always_run: false, + is_skippable: false, + run_if: '', + timeout: 0, + outputs: [ + { + BITRISE_IPA_PATH: null, + opts: { + category: '', + description: '', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: 'Local path of the created .ipa file', + title: '.ipa file path', + unset: false, + }, + }, + { + BITRISE_APP_DIR_PATH: null, + opts: { + category: '', + description: '', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: 'Local path of the generated `.app` directory', + title: '.app directory path', + unset: false, + }, + }, + { + BITRISE_DSYM_DIR_PATH: null, + opts: { + category: '', + description: + 'This Environment Variable points to the path of the directory which contains the dSYMs files.\nIf `export_all_dsyms` is set to `yes`, the Step will collect every dSYM (app dSYMs and framwork dSYMs).', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: "The created .dSYM dir's path", + unset: false, + }, + }, + { + BITRISE_DSYM_PATH: null, + opts: { + category: '', + description: + 'This Environment Variable points to the path of the zip file which contains the dSYM files.\nIf `export_all_dsyms` is set to `yes`, the Step will also collect framework dSYMs in addition to app dSYMs.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: "The created .dSYM.zip file's path", + unset: false, + }, + }, + { + BITRISE_XCARCHIVE_PATH: null, + opts: { + category: '', + description: '', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: "The created .xcarchive file's path", + title: '.xcarchive file path', + unset: false, + }, + }, + { + BITRISE_XCARCHIVE_ZIP_PATH: null, + opts: { + category: '', + description: '', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: "The created .xcarchive.zip file's path.", + title: '.xcarchive.zip path', + unset: false, + }, + }, + { + BITRISE_XCODEBUILD_ARCHIVE_LOG_PATH: null, + opts: { + category: '', + description: + 'The file path of the raw `xcodebuild archive` command log. The log is placed into the `Output directory path`.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: '`xcodebuild archive` command log file path', + unset: false, + }, + }, + { + BITRISE_XCODEBUILD_EXPORT_ARCHIVE_LOG_PATH: null, + opts: { + category: '', + description: + 'The file path of the raw `xcodebuild -exportArchive` command log. The log is placed into the `Output directory path`.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: '`xcodebuild -exportArchive` command log file path', + unset: false, + }, + }, + { + BITRISE_IDEDISTRIBUTION_LOGS_PATH: null, + opts: { + category: '', + description: 'Exported when `xcodebuild -exportArchive` command fails.', + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Path to the xcdistributionlogs', + unset: false, + }, + }, + ], + }, + objectID: '41605250000', + }, + { + info: { + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/codecov/assets/icon.svg', + }, + maintainer: 'verified', + }, + latest_version_number: '3.3.3', + cvs: 'codecov@3.3.3', + id: 'codecov', + version: '3.3.3', + is_latest: true, + is_deprecated: false, + step: { + title: 'Codecov', + summary: 'Upload your code coverage files to Codecov.io', + description: + 'Reduce technical debt with visualized test performance,\nfaster code reviews and workflow enhancements.\nNow you can upload your code coverage files to Codecov every time you kick off a build!', + website: 'https://codecov.io', + source_code_url: 'https://github.com/codecov/codecov-bitrise', + support_url: 'https://community.codecov.io', + published_at: '2023-09-15T09:34:57.29313-07:00', + source: { + git: 'https://github.com/codecov/codecov-bitrise.git', + commit: 'e8d493c4251ae0d9032d54f17b97ff9351982bf3', + }, + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/codecov/assets/icon.svg', + }, + type_tags: ['test'], + is_requires_admin_user: false, + is_always_run: false, + is_skippable: true, + run_if: '', + timeout: 0, + }, + objectID: '34299171000', + }, + { + info: { + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/deploy-to-bitrise-io/assets/icon.svg', + }, + maintainer: 'bitrise', + }, + latest_version_number: '2.8.1', + cvs: 'deploy-to-bitrise-io@2.8.1', + id: 'deploy-to-bitrise-io', + version: '2.8.1', + is_latest: true, + is_deprecated: false, + step: { + title: 'Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files', + summary: + "Deploys build artifacts to make them available for the user on the build's **Artifacts** tab. \nSends test results to the Test Reports add-on (build's **Tests** tab).\nUploads Pipeline intermediate files to make them available in subsequent Stages and also uploads Bitrise and user generated html reports.", + description: + "The Step accesses artifacts from a directory specified as the `$BITRISE_DEPLOY_DIR` where artifacts generated by previous Steps gets stored. \nThese artifacts are then uploaded on the **Artifacts** tab of any given build. For installable artifacts, such as IPAs or APKs, the Step can create a public install page that allows testers to install the app on their devices. \nYou can also use the Step to notify users about the build. If you wish to use the Test Reports add-on, you must add this Step in your Workflow since the Step converts test results to the right format and sends them to the add-on.\nThe Step can also share Pipeline intermediate files. These files are build artifacts generated by Workflows in a Pipeline intended to be shared with subsequent Stages.\nAlso it collects and uploads all of the html reports located in the `BITRISE_HTML_REPORT_DIR` folder.\n\n### Configuring the Build Artifact Deployment section of the Step\n\n1. Set the value for the **Deploy directory or file path** required input. The default value is the `$BITRISE_DEPLOY_DIR` Env Var which is exposed by the Bitrise CLI.\nIf you provide a directory, everything in that directory, excluding sub-directories, gets uploaded. \nIf you provide only a file, then only that file gets uploaded. \nTo upload a directory's content recursively, you should use the **Compress the artifacts into one file?** which will compress the whole directory, with every sub-directory included.\n2. Set the value of the **Notify: User Roles** input. It sends an email with the [public install URL](https://devcenter.bitrise.io/deploy/bitrise-app-deployment/) to those Bitrise users whose roles are included in this field. \nThe default value is `everyone`. If you wish to notify based on user roles, add one or more roles and separate them with commas, for example, `developers`, `admins`. If you don't want to notify anyone, set the input to `none`.\n3. Set the **Notify: Emails** sensitive input. It sends the public install URL in an email to the email addresses provided here. If you’re adding multiple email address, make sure to separate them with commas. \nThe recipients do not have to be in your Bitrise team. Please note that if the email address is associated with a Bitrise account, the user must be [watching](https://devcenter.bitrise.io/builds/configuring-notifications/#watching-an-app) the app.\n4. The **Enable public page for the App?** required input is set to `true` by default. It creates a long and random URL which can be shared with those who do not have a Bitrise account. \nIf you set this input to `false`, the **Notify: Emails** input will be ignored and the **Notify: User Roles** will receive the build URL instead of the public install URL.\n5. With the **Compress the artifacts into one file?** required input set to `true`, you can compress the artifacts found in the Deploy directory into a single file.\nYou can specify a custom name for the zip file with the `zip_name` option. If you don't specify one, the default `Deploy directory` name will be used. \nIf the **Compress the artifacts into one file?** is set to `false`, the artifacts in the Deploy directory will be deployed separately.\n6. With the **Format for the BITRISE_PUBLIC_INSTALL_PAGE_URL_MAP output** required input field, you can customize the output format of the public install page’s multiple artifact URLs so that the next Step can render the output (for example, our **Send a Slack message** Step). \nProvide a language template description using [https://golang.org/pkg/text/template](https://golang.org/pkg/text/template) so that the **Deploy to Bitrise.io** Step can build the required custom output.\n7. With the **Format for the BITRISE_PERMANENT_DOWNLOAD_URL_MAP output** required input, you can customize the output format of the `BITRISE_PERMANENT_DOWNLOAD_URL_MAP` so that the next Step can render the output.\nThe next Steps will use this input to generate the related output in the specified format. The output contains multiple permanent URLs for multiple artifacts.\nProvide a language template description using [https://golang.org/pkg/text/template](https://golang.org/pkg/text/template) so that the **Deploy to Bitrise.io** Step can build the required custom output.\n8. The **Test API's base URL** and the **API Token** input fields are automatically populated for you.\n9. The html report upload does not have any specific settings because it will happen automatically.\n\n### Configuring the Pipeline Intermediate File Sharing section of the Step\n\nThe **Files to share between pipeline stages** input specifies the files meant to be intermediate files shared between the Pipeline Stages. When uploading the Pipeline intermediate files, you must assign environment variable keys to them in the **Files to share between pipeline stages** input.\nThe inputs `path:env_key` values will be saved together with the file and later automatically reconstructed by the [Pull Pipeline intermediate files Step](https://www.bitrise.io/integrations/steps/pull-intermediate-files). \nYou can use a shorthand of just `env_var` for `$env_var:env_var`, when the `env_var` holds the path to the file(s) you want to share with subsequent stages.\nThe directories you specify will be archived and uploaded as a single file.\n\n#### Configuring the Debug section of the Step\n\nIf you wish to use any of the Step’s debug features, set the following inputs:\n1. In the **Name of the compressed artifact (without .zip extension)** input you can add a custom name for the compressed artifact. If you leave this input empty, the default `Deploy directory` name is used.\nPlease note that this input only works if you set the **Compress the artifacts into one file?** input to `true`.\n2. The **Bitrise Build URL** and the **Bitrise Build API Token** inputs are automatically populated.\n3. If **The Enable Debug Mode** required input is set to `true`, the Step prints more verbose logs. It is `false` by default. \n4. If you need a specific [bundletool version](https://github.com/google/bundletool/releases) other than the default value, you can modify the value of the **Bundletool version** required input. \nBundletool generates an APK from an Android App Bundle so that you can test the APK.\n\n### Troubleshooting\n\n- If your users did not get notified via email, check the **Enable public page for the App?** input. If it is set to `false`, no email notifications will be sent.\n- If there are no artifacts uploaded on the **APPS & ARTIFACTS tab**, then check the logs to see if the directory you used in the **Deploy directory or file path** input contained any artifacts. \n- If the email is not received, we recommend, that you check if the email is associated with Bitrise account and if so, if the account is “watching” the app.\n\n### Useful links\n\n- [Deployment on Bitrise](https://devcenter.bitrise.io/deploy/deployment-index/)\n- [Watching an app](https://devcenter.bitrise.io/builds/configuring-notifications/#watching-an-app)\n- [Using artifacts from different Stages](https://devcenter.bitrise.io/en/builds/build-pipelines/configuring-a-bitrise-pipeline.html#using-artifacts-from-different-stages)\n- [Viewing HTML reports](https://devcenter.bitrise.io/en/builds/build-data-and-troubleshooting/viewing-html-reports)\n \n ### Related Steps\n\n- [Deploy to Google Play](https://www.bitrise.io/integrations/steps/google-play-deploy)\n- [Deploy to iTunesConnect](https://www.bitrise.io/integrations/steps/deploy-to-itunesconnect-deliver)\n- [Pull Pipeline intermediate files](https://www.bitrise.io/integrations/steps/pull-intermediate-files)", + website: 'https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io', + source_code_url: 'https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io', + support_url: 'https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io/issues', + published_at: '2024-06-05T08:45:40.770036373Z', + source: { + git: 'https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io.git', + commit: '45842c8d910ffd036a494cfb7456a730f6c7a0b5', + }, + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/deploy-to-bitrise-io/assets/icon.svg', + }, + host_os_tags: ['osx-10.10'], + type_tags: ['deploy'], + toolkit: { + go: { + package_name: 'github.com/bitrise-steplib/steps-deploy-to-bitrise-io', + }, + }, + is_requires_admin_user: false, + is_always_run: true, + is_skippable: false, + run_if: '.IsCI', + timeout: 0, + outputs: [ + { + BITRISE_PUBLIC_INSTALL_PAGE_URL: null, + opts: { + category: '', + description: "Public Install Page's URL, if the\n*Enable public page for the App?* option was *enabled*.", + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Public Install Page URL', + unset: false, + }, + }, + { + BITRISE_PUBLIC_INSTALL_PAGE_URL_MAP: null, + opts: { + category: '', + description: + "Public Install Page URLs by the artifact's file path.\nOnly set it if the *Enable public page for the App?* option was *enabled*.\n\nThe default format is `KEY1=>VALUE|KEY2=>VALUE` but is controlled by the `public_install_page_url_map_format` input\n\nExamples:\n\n- $BITRISE_DEPLOY_DIR/ios_app.ipa=>https://ios_app/public/install/page\n- $BITRISE_DEPLOY_DIR/android_app.apk=>https://android_app/public/install/page|$BITRISE_DEPLOY_DIR/ios_app.ipa=>https://ios_app/public/install/page", + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Map of filenames and Public Install Page URLs', + unset: false, + }, + }, + { + BITRISE_PERMANENT_DOWNLOAD_URL_MAP: null, + opts: { + category: '', + description: + "The output contains permanent Download URLs for each artifact. The URLs can be shared in any communication channel and they won't expire.\nThe default format is `KEY1=>VALUE|KEY2=>VALUE` where key is the filename and the value is the URL.\nIf you change `permanent_download_url_map_format` input then that will modify the format of this Env Var.\nYou can customize the format of the multiple URLs.\n\nExamples:\n\n- $BITRISE_DEPLOY_DIR/ios_app.ipa=>https://app.bitrise.io/artifacts/ipa-slug/download\n- $BITRISE_DEPLOY_DIR/android_app.apk=>https://app.bitrise.io/artifacts/apk-slug/download|$BITRISE_DEPLOY_DIR/ios_app.ipa=>https://app.bitrise.io/artifacts/ipa-slug/download", + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Map of filenames and Permanent Download URLs', + unset: false, + }, + }, + { + BITRISE_ARTIFACT_DETAILS_PAGE_URL: null, + opts: { + category: '', + description: + "Details Page's URL.\n\nAt the moment, only installable artifacts (.aab, .apk, .ipa) have details page URL.", + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Details Page URL', + unset: false, + }, + }, + { + BITRISE_ARTIFACT_DETAILS_PAGE_URL_MAP: null, + opts: { + category: '', + description: + "Details Page URLs by the artifact's path. \n\nThe default format is `KEY1=>VALUE\\|KEY2=>VALUE` but is controlled by the `details_page_url_map_format` input\n\nExamples:\n\n- $BITRISE_DEPLOY_DIR/ios_app.ipa=>https://app.bitrise.io/apps/ios_app/installable-artifacts/ipa-slug\n- $BITRISE_DEPLOY_DIR/android_app.apk=>https://app.bitrise.io/apps/android_app/installable-artifacts/apk-slug|$BITRISE_DEPLOY_DIR/ios_app.ipa=>https://app.bitrise.io/apps/ios_app/installable-artifacts/ipa-slug", + is_dont_change_value: false, + is_expand: true, + is_required: false, + is_sensitive: false, + is_template: false, + skip_if_empty: false, + summary: '', + title: 'Map of filenames and Public Install Page URLs', + unset: false, + }, + }, + ], + }, + objectID: '48767735000', + }, + { + info: { + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/azure-devops-status/assets/icon.svg', + }, + maintainer: 'community', + }, + latest_version_number: '1.0.1', + cvs: 'azure-devops-status@1.0.1', + id: 'azure-devops-status', + version: '1.0.1', + is_latest: true, + is_deprecated: false, + step: { + title: 'Azure DevOps status', + summary: 'Update commit status for Azure DevOps repositories\n', + description: + 'Update commit status for Azure DevOps repositories.\nThis step always runs, no matter if build succeeded or failed.\n', + website: 'https://github.com/mediusoft/bitrise-step-azure-devops-status', + source_code_url: 'https://github.com/mediusoft/bitrise-step-azure-devops-status', + support_url: 'https://github.com/mediusoft/bitrise-step-azure-devops-status/issues', + published_at: '2020-03-17T00:04:11.37749+02:00', + source: { + git: 'https://github.com/mediusoft/bitrise-step-azure-devops-status.git', + commit: '1c28119b926f95b405ddad80b258ce9e414d44bf', + }, + asset_urls: { + 'icon.svg': 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/azure-devops-status/assets/icon.svg', + }, + host_os_tags: ['osx-10.10', 'ubuntu-16.04'], + type_tags: ['utility'], + toolkit: { + bash: { + entry_file: 'step.sh', + }, + }, + deps: { + brew: [ + { + name: 'curl', + }, + ], + apt_get: [ + { + name: 'curl', + }, + ], + }, + is_requires_admin_user: false, + is_always_run: true, + is_skippable: true, + run_if: 'not (enveq "BITRISE_GIT_COMMIT" "")', + timeout: 0, + }, + objectID: '33866073001', + }, +]; + +const useAlgoliaSteps = (): AlgoliaStepResponse[] => { + const steps = useMemo(() => MockSteps, []); + return steps; +}; + +export default useAlgoliaSteps; diff --git a/source/javascripts/models/Algolia.ts b/source/javascripts/models/Algolia.ts new file mode 100644 index 000000000..1e572c882 --- /dev/null +++ b/source/javascripts/models/Algolia.ts @@ -0,0 +1,23 @@ +import { Step } from './BitriseYml'; + +type StepInfoModel = { + maintainer?: string; + asset_urls?: Step['asset_urls'] & { + 'icon.svg'?: string; + 'icon.png'?: string; + }; +}; + +export type StepModel = Step; + +export type AlgoliaStepResponse = Partial<{ + readonly objectID: string; + cvs: string; + id: string; + version: string; + is_deprecated: boolean; + is_latest: boolean; + latest_version_number: string; + step: Partial; + info: StepInfoModel; +}>; diff --git a/source/javascripts/components/PipelinesPage/PipelinesPage.types.ts b/source/javascripts/models/BitriseYml.ts similarity index 100% rename from source/javascripts/components/PipelinesPage/PipelinesPage.types.ts rename to source/javascripts/models/BitriseYml.ts From 6fc29dabd9360e336a544c7f882bbdcb7f5b25e7 Mon Sep 17 00:00:00 2001 From: Zoltan Szabo Date: Fri, 21 Jun 2024 14:41:29 +0200 Subject: [PATCH 8/8] refactor: StepDrawer improvements --- .../components/StepDrawer/StepDrawer.mocks.ts | 108 ------------------ .../components/StepDrawer/StepDrawer.tsx | 13 +-- .../components/StepDrawer/StepDrawer.types.ts | 30 ++++- .../components/StepDrawer/StepDrawer.utils.ts | 15 +++ .../StepDrawer/components/StepCard.tsx | 57 --------- .../components/StepCategoryGrid.tsx | 31 +++++ .../StepDrawer/components/StepFilter.tsx | 12 +- .../StepDrawer/components/StepGridCard.tsx | 59 ++++++++++ .../StepDrawer/components/StepList.tsx | 50 ++------ .../StepDrawer/hooks/useSearchSteps.ts | 24 ++++ .../StepDrawer/hooks/useStepCategories.ts | 13 +++ .../components/StepDrawer/hooks/useSteps.ts | 37 ------ 12 files changed, 195 insertions(+), 254 deletions(-) delete mode 100644 source/javascripts/components/StepDrawer/StepDrawer.mocks.ts delete mode 100644 source/javascripts/components/StepDrawer/components/StepCard.tsx create mode 100644 source/javascripts/components/StepDrawer/components/StepCategoryGrid.tsx create mode 100644 source/javascripts/components/StepDrawer/components/StepGridCard.tsx create mode 100644 source/javascripts/components/StepDrawer/hooks/useSearchSteps.ts create mode 100644 source/javascripts/components/StepDrawer/hooks/useStepCategories.ts delete mode 100644 source/javascripts/components/StepDrawer/hooks/useSteps.ts diff --git a/source/javascripts/components/StepDrawer/StepDrawer.mocks.ts b/source/javascripts/components/StepDrawer/StepDrawer.mocks.ts deleted file mode 100644 index 995facee6..000000000 --- a/source/javascripts/components/StepDrawer/StepDrawer.mocks.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Step } from './StepDrawer.types'; - -export const MockSteps: Step[] = [ - { - id: 'activate-ssh-key', - title: 'Activate SSH key', - icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/activate-ssh-key/assets/icon.svg', - version: '1.1.6', - description: - 'Add your SSH key to the build machine to access private repositories\n' + - '\n' + - 'This Step makes sure Bitrise has access to your repository when cloning SSH URLs. The Step saves the provided private key of your SSH keypair to a file and then loads it into the SSH agent.', - categories: ['access-control'], - isOfficial: true, - isVerified: false, - isDeprecated: false, - }, - { - id: 'clone', - title: 'Git Clone', - description: - 'Checks out the repository, updates submodules and exports git metadata as Step outputs.\n' + - '\n' + - 'The checkout process depends on the Step settings and the build trigger parameters (coming from your git server).', - version: '8.3.1', - icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/git-clone/assets/icon.svg', - categories: ['utility'], - isOfficial: true, - isVerified: false, - isDeprecated: false, - }, - { - id: 'npm', - title: 'Run npm command', - icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/npm/assets/icon.svg', - version: '1.1.6', - description: - "The Step runs npm with the command and arguments you provide, for example, to install missing packages or run a package's test.", - categories: ['build', 'test', 'utility'], - isOfficial: true, - isVerified: false, - isDeprecated: false, - }, - { - id: 'test', - title: 'Xcode Test for iOS', - description: "Runs your project's pre-defined Xcode tests on every build.", - version: '5.1.1', - icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/xcode-test/assets/icon.svg', - categories: ['test'], - isOfficial: true, - isVerified: false, - isDeprecated: false, - }, - { - id: 'xcode-archive', - title: 'Xcode Archive & Export for iOS', - description: - 'Archive and export an Xcode project.\n' + - '\n' + - 'This Step will archive your Xcode project and export it as an .ipa file. You can also export the archive as a .xcarchive file.', - version: '5.1.2', - icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/xcode-archive/assets/icon.svg', - categories: ['test', 'build', 'deploy'], - isOfficial: true, - isVerified: false, - isDeprecated: false, - }, - { - id: 'codecov', - title: 'Codecov', - description: - 'Upload your code coverage files to Codecov.io\n' + - '\n' + - 'Reduce technical debt with visualized test performance, faster code reviews and workflow enhancements. Now you can upload your code coverage files to Codecov every time you kick off a build!', - version: '3.3.3', - icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/codecov/assets/icon.svg', - categories: ['test'], - isOfficial: false, - isVerified: true, - isDeprecated: false, - }, - { - id: 'deploy-to-bitrise-io', - title: 'Deploy to Bitrise.io', - description: - "Deploys build artifacts to make them available for the user on the build's Artifacts tab.\n" + - "Sends test results to the Test Reports add-on (build's Tests tab). Uploads Pipeline intermediate files to make them available in subsequent Stages and also uploads Bitrise and user generated html reports.", - version: '2.8.1', - icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/deploy-to-bitrise-io/assets/icon.svg', - categories: ['test', 'deploy'], - isOfficial: true, - isVerified: false, - isDeprecated: false, - }, - { - id: 'azure-devops-status', - title: 'Azure DevOps Status', - description: - 'Update commit status for Azure DevOps repositories. This step always runs, no matter if build succeeded or failed.', - version: '1.0.1', - icon: 'https://bitrise-steplib-collection.s3.amazonaws.com/steps/azure-devops-status/assets/icon.svg', - categories: ['test'], - isOfficial: false, - isVerified: false, - isDeprecated: true, - }, -]; diff --git a/source/javascripts/components/StepDrawer/StepDrawer.tsx b/source/javascripts/components/StepDrawer/StepDrawer.tsx index 1c8277437..7b7131022 100644 --- a/source/javascripts/components/StepDrawer/StepDrawer.tsx +++ b/source/javascripts/components/StepDrawer/StepDrawer.tsx @@ -1,9 +1,9 @@ import { Box, Drawer, Text, useDisclosure } from '@bitrise/bitkit'; import { FormProvider, useForm } from 'react-hook-form'; -import { FilterFormValues } from './StepDrawer.types'; + +import { SearchFormValues } from './StepDrawer.types'; import StepFilter from './components/StepFilter'; import StepList from './components/StepList'; -import { useCategories, useFilter } from './hooks/useSteps'; type Props = { isOpen: boolean; @@ -11,23 +11,20 @@ type Props = { const StepDrawer = ({ isOpen: isInitialOpen }: Props) => { const { isOpen, onClose } = useDisclosure({ defaultIsOpen: isInitialOpen }); - const { categories } = useCategories(); - const form = useForm({ + const form = useForm({ defaultValues: { search: '', categories: [], }, }); - const { steps } = useFilter(form.watch()); - return ( Add Step - - + + diff --git a/source/javascripts/components/StepDrawer/StepDrawer.types.ts b/source/javascripts/components/StepDrawer/StepDrawer.types.ts index 35a07f36c..0ae12233e 100644 --- a/source/javascripts/components/StepDrawer/StepDrawer.types.ts +++ b/source/javascripts/components/StepDrawer/StepDrawer.types.ts @@ -1,4 +1,7 @@ -export type FilterFormValues = { +import { AlgoliaStepResponse } from '../../models/Algolia'; +import defaultIcon from '../../../images/step/icon-default.svg'; + +export type SearchFormValues = { search: string; projectType: string; categories: string[]; @@ -8,6 +11,7 @@ export type Step = { id: string; icon: string; title: string; + summary: string; description: string; version: string; categories: string[]; @@ -15,3 +19,27 @@ export type Step = { isVerified: boolean; isDeprecated: boolean; }; + +export const fromAlgolia = (response?: AlgoliaStepResponse): Step | undefined => { + if (!response) { + return undefined; + } + + return { + id: response.id || '', + icon: + response.step?.asset_urls?.['icon.svg'] || + response.step?.asset_urls?.['icon.png'] || + response.info?.asset_urls?.['icon.svg'] || + response.info?.asset_urls?.['icon.png'] || + defaultIcon, + title: response.step?.title || '', + summary: response.step?.summary || '', + description: response.step?.description || '', + version: response.version || '', + categories: response.step?.type_tags || [], + isOfficial: response.info?.maintainer === 'bitrise' || false, + isVerified: response.info?.maintainer === 'community' || false, + isDeprecated: response.is_deprecated || false, + }; +}; diff --git a/source/javascripts/components/StepDrawer/StepDrawer.utils.ts b/source/javascripts/components/StepDrawer/StepDrawer.utils.ts index 66bf743ff..6ff05d07f 100644 --- a/source/javascripts/components/StepDrawer/StepDrawer.utils.ts +++ b/source/javascripts/components/StepDrawer/StepDrawer.utils.ts @@ -1,3 +1,18 @@ import capitalize from 'lodash/capitalize'; +import { Step } from './StepDrawer.types'; export const displayCategoryName = (category: string) => capitalize(category).replace('-', ' '); + +export const getStepsByCategories = (steps: Step[]) => { + return steps.reduce( + (acc, step) => { + step.categories.forEach((category) => { + acc[category] ||= []; + acc[category].push(step); + }); + + return acc; + }, + {} as Record, + ); +}; diff --git a/source/javascripts/components/StepDrawer/components/StepCard.tsx b/source/javascripts/components/StepDrawer/components/StepCard.tsx deleted file mode 100644 index bd47afdd2..000000000 --- a/source/javascripts/components/StepDrawer/components/StepCard.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { Box, Card, Icon, Text } from '@bitrise/bitkit'; -import { LazyLoadImage } from 'react-lazy-load-image-component'; -import { useBoolean } from 'usehooks-ts'; -import { Step } from '../StepDrawer.types'; -import defaultStepIcon from '../../../../images/step/icon-default.svg'; -import StepBadge from '../../StepBadge/StepBadge'; - -type Props = Step; - -const StepCard = ({ icon, title, description, version, isOfficial, isVerified, isDeprecated }: Props) => { - const { value: hovered, setTrue, setFalse } = useBoolean(false); - - return ( - - - - - - - - {title} - - {version} - - - - - {description} - - {hovered && } - - ); -}; - -export default StepCard; diff --git a/source/javascripts/components/StepDrawer/components/StepCategoryGrid.tsx b/source/javascripts/components/StepDrawer/components/StepCategoryGrid.tsx new file mode 100644 index 000000000..64f46e4c7 --- /dev/null +++ b/source/javascripts/components/StepDrawer/components/StepCategoryGrid.tsx @@ -0,0 +1,31 @@ +import { Box, Text } from '@bitrise/bitkit'; +import { SimpleGrid } from '@chakra-ui/react'; + +import { Step } from '../StepDrawer.types'; +import { displayCategoryName } from '../StepDrawer.utils'; +import StepGridCard from './StepGridCard'; + +type Props = { + category: string; + steps: Step[]; +}; +const StepCategoryGrid = ({ category, steps }: Props) => { + if (steps.length === 0) { + return null; + } + + return ( + + + {displayCategoryName(category)} + + + {steps.map((step) => ( + + ))} + + + ); +}; + +export default StepCategoryGrid; diff --git a/source/javascripts/components/StepDrawer/components/StepFilter.tsx b/source/javascripts/components/StepDrawer/components/StepFilter.tsx index 1aeef168e..715872845 100644 --- a/source/javascripts/components/StepDrawer/components/StepFilter.tsx +++ b/source/javascripts/components/StepDrawer/components/StepFilter.tsx @@ -1,11 +1,11 @@ import { Box, SearchInput, Tag } from '@bitrise/bitkit'; import { Controller } from 'react-hook-form'; -type Props = { - categories?: string[]; -}; +import useStepCategories from '../hooks/useStepCategories'; + +const StepFilter = () => { + const { categories } = useStepCategories(); -const StepFilter = ({ categories = [] }: Props) => { return ( { /> {categories.map((category) => ( - {category} + + {category} + ))} diff --git a/source/javascripts/components/StepDrawer/components/StepGridCard.tsx b/source/javascripts/components/StepDrawer/components/StepGridCard.tsx new file mode 100644 index 000000000..3d9da204d --- /dev/null +++ b/source/javascripts/components/StepDrawer/components/StepGridCard.tsx @@ -0,0 +1,59 @@ +import { Box, Card, Icon, Image, Text } from '@bitrise/bitkit'; + +import defaultStepIcon from '../../../../images/step/icon-default.svg'; +import StepBadge from '../../StepBadge/StepBadge'; +import { Step } from '../StepDrawer.types'; + +type Props = Step; + +const StepGridCard = ({ icon, title, description, version, isOfficial, isVerified, isDeprecated }: Props) => { + return ( + + + + {title} + + + + + {title} + + + {version} + + + + + {description} + + + + ); +}; + +export default StepGridCard; diff --git a/source/javascripts/components/StepDrawer/components/StepList.tsx b/source/javascripts/components/StepDrawer/components/StepList.tsx index 8f61fbd72..bf14bf80c 100644 --- a/source/javascripts/components/StepDrawer/components/StepList.tsx +++ b/source/javascripts/components/StepDrawer/components/StepList.tsx @@ -1,47 +1,21 @@ import { useMemo } from 'react'; -import { Box, Text } from '@bitrise/bitkit'; -import { SimpleGrid } from '@chakra-ui/react'; -import { Step } from '../StepDrawer.types'; -import { displayCategoryName } from '../StepDrawer.utils'; -import StepCard from './StepCard'; +import { Box } from '@bitrise/bitkit'; +import { useFormContext } from 'react-hook-form'; -type Props = { - categories: string[]; - steps: Step[]; -}; - -const StepList = ({ categories = [], steps = [] }: Props) => { - const stepsByCategories = useMemo( - () => - steps.reduce( - (acc, step) => { - step.categories.forEach((category) => { - acc[category] ||= []; - acc[category].push(step); - }); +import { SearchFormValues } from '../StepDrawer.types'; +import { getStepsByCategories } from '../StepDrawer.utils'; +import useSearchSteps from '../hooks/useSearchSteps'; +import StepCategoryGrid from './StepCategoryGrid'; - return acc; - }, - {} as Record, - ), - [steps], - ); +const StepList = () => { + const form = useFormContext(); + const { steps } = useSearchSteps(form.watch()); + const stepsByCategories = useMemo(() => getStepsByCategories(steps), [steps]); return ( - {categories?.map((category) => ( - <> - {stepsByCategories[category]?.length > 0 && ( - - - {displayCategoryName(category)} - - - {stepsByCategories[category]?.map((step) => )} - - - )} - + {Object.entries(stepsByCategories).map(([category, categorySteps]) => ( + ))} ); diff --git a/source/javascripts/components/StepDrawer/hooks/useSearchSteps.ts b/source/javascripts/components/StepDrawer/hooks/useSearchSteps.ts new file mode 100644 index 000000000..c5de25a86 --- /dev/null +++ b/source/javascripts/components/StepDrawer/hooks/useSearchSteps.ts @@ -0,0 +1,24 @@ +import { fromAlgolia, SearchFormValues, Step } from '../StepDrawer.types'; +import useAlgoliaSteps from '../../../hooks/useAlgoliaSteps'; + +const useSearchSteps = ({ search, categories }: SearchFormValues): { steps: Step[] } => { + const stepObjs = useAlgoliaSteps(); + const searchValue = search.toLowerCase(); + let steps = stepObjs.map(fromAlgolia).filter(Boolean) as Step[]; + + if (categories.length > 0) { + steps = steps.filter((step) => step?.categories.some((category) => categories.includes(category))); + } + + if (searchValue) { + steps = steps.filter((step) => { + const name = step?.title.toLowerCase(); + const description = step?.description.toLowerCase(); + return name?.includes(searchValue) || description?.includes(searchValue); + }); + } + + return { steps }; +}; + +export default useSearchSteps; diff --git a/source/javascripts/components/StepDrawer/hooks/useStepCategories.ts b/source/javascripts/components/StepDrawer/hooks/useStepCategories.ts new file mode 100644 index 000000000..69489fc1e --- /dev/null +++ b/source/javascripts/components/StepDrawer/hooks/useStepCategories.ts @@ -0,0 +1,13 @@ +import { useMemo } from 'react'; +import uniq from 'lodash/uniq'; +import useAlgoliaSteps from '../../../hooks/useAlgoliaSteps'; + +const useStepCategories = () => { + const stepObjs = useAlgoliaSteps(); + const categories = useMemo(() => { + return uniq(stepObjs.flatMap((obj) => obj.step?.type_tags || [])).sort(); + }, [stepObjs]); + return { categories }; +}; + +export default useStepCategories; diff --git a/source/javascripts/components/StepDrawer/hooks/useSteps.ts b/source/javascripts/components/StepDrawer/hooks/useSteps.ts deleted file mode 100644 index e9c157b33..000000000 --- a/source/javascripts/components/StepDrawer/hooks/useSteps.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { useMemo } from 'react'; -import uniq from 'lodash/uniq'; -import { MockSteps } from '../StepDrawer.mocks'; -import { FilterFormValues } from '../StepDrawer.types'; - -export const useSteps = () => { - const steps = useMemo(() => MockSteps, []); - return { steps }; -}; - -export const useCategories = () => { - const { steps } = useSteps(); - const categories = useMemo(() => { - return uniq(steps.flatMap((step) => step.categories)).sort(); - }, [steps]); - return { categories }; -}; - -export const useFilter = ({ categories, search }: FilterFormValues) => { - const { steps } = useSteps(); - const searchValue = search.toLowerCase(); - let filteredSteps = steps; - - if (categories.length > 0) { - filteredSteps = steps.filter((step) => step.categories.some((category) => categories.includes(category))); - } - - if (searchValue) { - filteredSteps = steps.filter((step) => { - const name = step.title.toLowerCase(); - const description = step.description.toLowerCase(); - return name.includes(searchValue) || description.includes(searchValue); - }); - } - - return { steps: filteredSteps }; -};