Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert task selection to quick search modal in pipeline builder #9583

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -11,6 +11,7 @@ interface QuickSearchBarProps {
searchTerm: string;
onSearch: (searchTerm: string) => void;
searchPlaceholder: string;
icon?: React.ReactNode;
}

const QuickSearchBar: React.FC<QuickSearchBarProps> = ({
Expand All @@ -20,14 +21,13 @@ const QuickSearchBar: React.FC<QuickSearchBarProps> = ({
searchTerm,
searchPlaceholder,
onSearch,
icon,
}) => {
const { t } = useTranslation();

return (
<InputGroup className="odc-quick-search-bar" data-test="quick-search-bar">
<InputGroupText>
<QuickSearchIcon />
</InputGroupText>
<InputGroupText>{icon || <QuickSearchIcon />}</InputGroupText>
<TextInput
type="search"
aria-label={t('console-shared~Quick search bar')}
Expand Down
Expand Up @@ -20,6 +20,7 @@ interface QuickSearchContentProps {
onSelect: (itemId: string) => void;
viewAll?: CatalogLinkData[];
closeModal: () => void;
limitItemCount: number;
}

const QuickSearchContent: React.FC<QuickSearchContentProps> = ({
Expand All @@ -32,6 +33,7 @@ const QuickSearchContent: React.FC<QuickSearchContentProps> = ({
selectedItemId,
onSelect,
closeModal,
limitItemCount,
}) => {
return (
<Split className="odc-quick-search-content">
Expand All @@ -42,7 +44,7 @@ const QuickSearchContent: React.FC<QuickSearchContentProps> = ({
})}
>
<QuickSearchList
listItems={catalogItems.slice(0, MAX_CATALOG_ITEMS_SHOWN)}
listItems={limitItemCount > 0 ? catalogItems.slice(0, limitItemCount) : catalogItems}
catalogItemTypes={catalogItemTypes}
viewAll={viewAll}
selectedItemId={selectedItemId}
Expand Down
Expand Up @@ -11,6 +11,9 @@ type QuickSearchControllerProps = {
searchPlaceholder: string;
allItemsLoaded: boolean;
isOpen: boolean;
icon?: React.ReactNode;
limitItemCount: number;
disableKeyboardOpen?: boolean;
setIsOpen: (isOpen: boolean) => void;
};

Expand All @@ -20,11 +23,15 @@ const QuickSearchController: React.FC<QuickSearchControllerProps> = ({
searchPlaceholder,
viewContainer,
allItemsLoaded,
limitItemCount,
icon,
isOpen,
setIsOpen,
disableKeyboardOpen = false,
}) => {
const { t } = useTranslation();

const isLimitedList = limitItemCount > 0;
const searchCatalog = React.useCallback(
(searchTerm: string): QuickSearchData => {
return quickSearchProviders.reduce(
Expand All @@ -34,7 +41,7 @@ const QuickSearchController: React.FC<QuickSearchControllerProps> = ({
: [];
const itemCount = items.length;
const viewAllLink =
itemCount > 0
itemCount > 0 && isLimitedList
karthikjeeyar marked this conversation as resolved.
Show resolved Hide resolved
? [
{
label: t(quickSearchProvider.catalogLinkLabel, { itemCount }),
Expand All @@ -59,7 +66,7 @@ const QuickSearchController: React.FC<QuickSearchControllerProps> = ({
{ filteredItems: [], viewAllLinks: [], catalogItemTypes: [] },
);
},
[namespace, quickSearchProviders, t],
[isLimitedList, namespace, quickSearchProviders, t],
);

React.useEffect(() => {
Expand All @@ -69,7 +76,7 @@ const QuickSearchController: React.FC<QuickSearchControllerProps> = ({
return;
}

if (e.code === 'Space' && e.ctrlKey) {
if (!disableKeyboardOpen && e.code === 'Space' && e.ctrlKey) {
e.preventDefault();
setIsOpen(true);
}
Expand All @@ -80,10 +87,12 @@ const QuickSearchController: React.FC<QuickSearchControllerProps> = ({
return () => {
window.removeEventListener('keydown', onKeyDown);
};
}, [setIsOpen]);
}, [setIsOpen, disableKeyboardOpen]);

return (
<QuickSearchModal
limitItemCount={limitItemCount}
icon={icon}
isOpen={isOpen}
closeModal={() => setIsOpen(false)}
namespace={namespace}
Expand Down
Expand Up @@ -9,7 +9,7 @@
scrollbar-color: var(--pf-global--BackgroundColor--light-300) var(--pf-global--palette--white);

&__form-button {
margin: var(--pf-global--spacer--md) 0px;
margin: var(--pf-global--spacer--md) 0px !important;
karthikjeeyar marked this conversation as resolved.
Show resolved Hide resolved
width: max-content;
}

Expand Down
Expand Up @@ -19,7 +19,7 @@
}
}
&--highlight {
background: var(--pf-global--active-color--200);
background: var(--pf-global--active-color--200) !important;
karthikjeeyar marked this conversation as resolved.
Show resolved Hide resolved
}
&:hover {
background: var(--pf-global--active-color--200);
Expand Down
Expand Up @@ -57,6 +57,14 @@ const QuickSearchList: React.FC<QuickSearchListProps> = ({
/>
);
};
React.useLayoutEffect(() => {
if (selectedItemId) {
const element = document.getElementById(selectedItemId);
if (element) {
element.scrollIntoView({ block: 'nearest' });
}
}
}, [selectedItemId]);

return (
<div className="odc-quick-search-list">
Expand Down Expand Up @@ -115,18 +123,21 @@ const QuickSearchList: React.FC<QuickSearchListProps> = ({
);
})}
</DataList>
<div className="odc-quick-search-list__all-items-link">
{viewAll?.map((catalogLink) => (
<Link
id={catalogLink.catalogType}
to={catalogLink.to}
key={catalogLink.catalogType}
style={{ fontSize: 'var(--pf-global--FontSize--sm)' }}
>
{catalogLink.label}
</Link>
))}
</div>

{viewAll?.length > 0 && (
<div className="odc-quick-search-list__all-items-link">
{viewAll.map((catalogLink) => (
<Link
id={catalogLink.catalogType}
to={catalogLink.to}
key={catalogLink.catalogType}
style={{ fontSize: 'var(--pf-global--FontSize--sm)' }}
>
{catalogLink.label}
</Link>
))}
</div>
)}
</div>
);
};
Expand Down
Expand Up @@ -12,6 +12,8 @@ interface QuickSearchModalProps {
searchCatalog: (searchTerm: string) => QuickSearchData;
searchPlaceholder: string;
viewContainer?: HTMLElement;
limitItemCount: number;
icon?: React.ReactNode;
}

const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
Expand All @@ -22,6 +24,8 @@ const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
searchPlaceholder,
allCatalogItemsLoaded,
viewContainer,
icon,
limitItemCount,
}) => {
const { t } = useTranslation();

Expand All @@ -42,6 +46,8 @@ const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
searchPlaceholder={searchPlaceholder}
namespace={namespace}
closeModal={closeModal}
limitItemCount={limitItemCount}
icon={icon}
/>
</Modal>
) : null;
Expand Down
Expand Up @@ -21,14 +21,18 @@ interface QuickSearchModalBodyProps {
searchPlaceholder: string;
namespace: string;
closeModal: () => void;
limitItemCount: number;
icon?: React.ReactNode;
}

const QuickSearchModalBody: React.FC<QuickSearchModalBodyProps> = ({
searchCatalog,
namespace,
closeModal,
limitItemCount,
searchPlaceholder,
allCatalogItemsLoaded,
icon,
}) => {
const [catalogItems, setCatalogItems] = React.useState<CatalogItem[]>(null);
const [catalogTypes, setCatalogTypes] = React.useState<CatalogType[]>([]);
Expand All @@ -38,7 +42,8 @@ const QuickSearchModalBody: React.FC<QuickSearchModalBodyProps> = ({
const [selectedItemId, setSelectedItemId] = React.useState<string>('');
const [selectedItem, setSelectedItem] = React.useState<CatalogItem>(null);
const [viewAll, setViewAll] = React.useState<CatalogLinkData[]>(null);
const listCatalogItems = catalogItems?.slice(0, 5);
const listCatalogItems =
limitItemCount > 0 ? catalogItems?.slice(0, limitItemCount) : catalogItems;
const ref = React.useRef<HTMLDivElement>(null);
const fireTelemetryEvent = useTelemetry();

Expand Down Expand Up @@ -161,8 +166,9 @@ const QuickSearchModalBody: React.FC<QuickSearchModalBodyProps> = ({

const getModalHeight = () => {
let height: number = 60;
const itemsHeight = viewAll?.length ? 388 : 365;
if (catalogItems?.length > 0) {
height += 388 + (viewAll?.length - 1) * 23;
height += itemsHeight + (viewAll?.length - 1) * 23;
}
return height;
};
Expand All @@ -175,6 +181,7 @@ const QuickSearchModalBody: React.FC<QuickSearchModalBodyProps> = ({
onSearch={onSearch}
showNoResults={catalogItems?.length === 0}
itemsLoaded={allCatalogItemsLoaded}
icon={icon}
autoFocus
/>
{catalogItems && selectedItem && (
Expand All @@ -187,6 +194,7 @@ const QuickSearchModalBody: React.FC<QuickSearchModalBodyProps> = ({
closeModal={closeModal}
selectedItem={selectedItem}
namespace={namespace}
limitItemCount={limitItemCount}
onSelect={(itemId) => {
setSelectedItemId(itemId);
setSelectedItem(catalogItems?.find((item) => item.uid === itemId));
Expand Down
22 changes: 22 additions & 0 deletions frontend/packages/pipelines-plugin/console-extensions.json
Expand Up @@ -155,5 +155,27 @@
},
"template": { "$codeRef": "yamlTemplates.newClusterTaskTemplate" }
}
},
{
"type": "console.catalog/item-type",
"properties": {
"type": "Red Hat",
"title": "%pipelines-plugin~Red Hat%",
"catalogDescription": "%pipelines-plugin~Browse for openshift pipeline tasks available in the cluster.%"
},
"flags": {
"required": ["OPENSHIFT_PIPELINE"]
}
},
{
"type": "console.catalog/item-provider",
"properties": {
"catalogId": "pipelines-task-catalog",
"type": "Red Hat",
"provider": { "$codeRef": "catalog.TektonTaskProvider" }
},
"flags": {
"required": ["OPENSHIFT_PIPELINE"]
}
}
]
Expand Up @@ -57,14 +57,18 @@ export const pipelineBuilderPage = {
.clear()
.type(pipelineName);
},
AddTask: (taskName: string = 'kn') => {
cy.get('input.odc-quick-search-bar__input').type(taskName);
cy.get('button.odc-quick-search-details__form-button').click();
},
selectTask: (taskName: string = 'kn') => {
cy.get('body').then(($body) => {
if ($body.text().includes('Unable to locate any tasks.')) {
cy.reload();
}
});
cy.get(pipelineBuilderPO.formView.taskDropdown).click();
cy.byTestActionID(taskName).click({ force: true });
pipelineBuilderPage.AddTask(taskName);
},
clickOnTask: (taskName: string) => cy.get(`[data-id="${taskName}"] text`).click({ force: true }),
selectParallelTask: (taskName: string) => {
Expand All @@ -73,15 +77,15 @@ export const pipelineBuilderPage = {
.eq(2)
.click({ force: true });
cy.get(pipelineBuilderPO.formView.parallelTask).click();
cy.byTestActionID(taskName).click();
pipelineBuilderPage.AddTask(taskName);
},
selectSeriesTask: (taskName: string) => {
cy.mouseHover(pipelineBuilderPO.formView.task);
cy.get(pipelineBuilderPO.formView.plusTaskIcon)
.first()
.click({ force: true });
cy.get(pipelineBuilderPO.formView.seriesTask).click();
cy.byTestActionID(taskName).click();
pipelineBuilderPage.AddTask(taskName);
},
clickOnAddWorkSpace: () => {
cy.byButtonText('Add workspace').click();
Expand Down Expand Up @@ -212,6 +216,6 @@ export const pipelineBuilderPage = {
cy.get(pipelineBuilderPO.formView.finallyTaskList).click({ force: true }),
selectFinallyTask: (taskName: string) => {
cy.get(pipelineBuilderPO.formView.finallyTaskList).click({ force: true });
cy.byTestActionID(taskName).click({ force: true });
pipelineBuilderPage.AddTask(taskName);
},
};
Expand Up @@ -3,6 +3,9 @@
"Create a Tekton Pipeline to automate delivery of your Application": "Create a Tekton Pipeline to automate delivery of your Application",
"Tasks": "Tasks",
"Triggers": "Triggers",
"Red Hat": "Red Hat",
"Browse for openshift pipeline tasks available in the cluster.": "Browse for openshift pipeline tasks available in the cluster.",
"Add": "Add",
"{{clusterTaskLabel}} details": "{{clusterTaskLabel}} details",
"Select a Builder Image and resource to see if there is a pipeline template available for this runtime.": "Select a Builder Image and resource to see if there is a pipeline template available for this runtime.",
"The pipeline template for Dockerfiles is not available at this time.": "The pipeline template for Dockerfiles is not available at this time.",
Expand Down Expand Up @@ -128,7 +131,6 @@
"Start": "Start",
"Start Pipeline": "Start Pipeline",
"There was an unknown error": "There was an unknown error",
"Add": "Add",
"Add Trigger": "Add Trigger",
"Select the trigger to remove from pipeline <1>{{pipelineName}}</1>.": "Select the trigger to remove from pipeline <1>{{pipelineName}}</1>.",
"Select TriggerTemplate": "Select TriggerTemplate",
Expand Down Expand Up @@ -234,7 +236,7 @@
"Add a sequential task before this task": "Add a sequential task before this task",
"Add a parallel task": "Add a parallel task",
"Task does not exist": "Task does not exist",
"Select task": "Select task",
"Add task": "Add task",
"No tasks": "No tasks",
"Delete task": "Delete task",
"When expression was met": "When expression was met",
Expand All @@ -249,6 +251,7 @@
"Select a Project to view the list of Pipelines or <2>create a Project</2>.": "Select a Project to view the list of Pipelines or <2>create a Project</2>.",
"Create Pipeline": "Create Pipeline",
"by name": "by name",
"View all tekton tasks ({{itemCount, number}})": "View all tekton tasks ({{itemCount, number}})",
"No options matching your criteria": "No options matching your criteria",
"{{resourceName}} results": "{{resourceName}} results",
"Value": "Value",
Expand Down
3 changes: 2 additions & 1 deletion frontend/packages/pipelines-plugin/package.json
Expand Up @@ -21,7 +21,8 @@
},
"exposedModules": {
"icons": "src/utils/icons.ts",
"yamlTemplates": "src/templates/pipelines.ts"
"yamlTemplates": "src/templates/pipelines.ts",
"catalog": "src/components/catalog"
}
}
}
@@ -0,0 +1 @@
export * from './providers';
@@ -0,0 +1 @@
export { default as TektonTaskProvider } from './useTasksProvider';