Skip to content
49 changes: 38 additions & 11 deletions cypress/component/CreatorYAMLView.cy.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
import React from 'react';
import { FlagProvider, IConfig } from '@unleash/proxy-client-react';
import CreatorYAMLView from '../../src/components/creator/CreatorYAMLView';

const unleashConfig: IConfig = {
appName: 'test-app',
url: 'https://unleash.example.com/api/',
clientKey: 'test',
refreshInterval: 0,
disableRefresh: true,
bootstrap: [
{
name: 'platform.learning-resources.quickstarts.git-service',
enabled: false,
impressionData: false,
variant: { name: 'disabled', enabled: false },
},
],
};

const Wrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<FlagProvider config={unleashConfig}>{children}</FlagProvider>
);

const setMonacoValue = (value: string) => {
// Retry until Monaco is ready and models are available
cy.window().should((win: any) => {
Expand Down Expand Up @@ -35,7 +56,7 @@ const getMonacoValue = (): Cypress.Chainable<string> => {
describe('CreatorYAMLView', () => {
beforeEach(() => {
// Mount the component before each test
cy.mount(<CreatorYAMLView />);
cy.mount(<Wrapper><CreatorYAMLView /></Wrapper>);

// This single wait ensures the editor is ready for all tests
cy.get('.lr-c-creator-yaml-view__editor', { timeout: 10000 }).should('be.visible');
Expand Down Expand Up @@ -97,11 +118,13 @@ describe('CreatorYAMLView', () => {
const onChangeTags = cy.stub().as('onChangeTags');

cy.mount(
<CreatorYAMLView
onChangeQuickStartSpec={onChangeQuickStartSpec}
onChangeBundles={onChangeBundles}
onChangeTags={onChangeTags}
/>
<Wrapper>
<CreatorYAMLView
onChangeQuickStartSpec={onChangeQuickStartSpec}
onChangeBundles={onChangeBundles}
onChangeTags={onChangeTags}
/>
</Wrapper>
);

// Wait for editor to initialize
Expand Down Expand Up @@ -132,7 +155,9 @@ spec:
const onChangeQuickStartSpec = cy.stub().as('onChangeQuickStartSpec');

cy.mount(
<CreatorYAMLView onChangeQuickStartSpec={onChangeQuickStartSpec} />
<Wrapper>
<CreatorYAMLView onChangeQuickStartSpec={onChangeQuickStartSpec} />
</Wrapper>
);

cy.get('.monaco-editor textarea', { timeout: 10000 }).should('exist');
Expand Down Expand Up @@ -160,7 +185,7 @@ spec:
});

it('should show error alert for invalid YAML', () => {
cy.mount(<CreatorYAMLView />);
cy.mount(<Wrapper><CreatorYAMLView /></Wrapper>);

// Wait for editor to be ready
cy.get('.monaco-editor textarea', { timeout: 10000 }).should('exist');
Expand All @@ -185,7 +210,9 @@ spec:
const onChangeQuickStartSpec = cy.stub().as('onChangeQuickStartSpec');

cy.mount(
<CreatorYAMLView onChangeQuickStartSpec={onChangeQuickStartSpec} />
<Wrapper>
<CreatorYAMLView onChangeQuickStartSpec={onChangeQuickStartSpec} />
</Wrapper>
);

// Wait for editor to initialize
Expand Down Expand Up @@ -221,7 +248,7 @@ spec:
});

it('should recover from error when valid YAML is entered', () => {
cy.mount(<CreatorYAMLView />);
cy.mount(<Wrapper><CreatorYAMLView /></Wrapper>);

// Wait for editor to be ready
cy.get('.monaco-editor textarea', { timeout: 10000 }).should('exist');
Expand Down Expand Up @@ -253,7 +280,7 @@ spec:
});

it('should update editor content via Monaco API', () => {
cy.mount(<CreatorYAMLView />);
cy.mount(<Wrapper><CreatorYAMLView /></Wrapper>);

// Wait for editor to be ready
cy.get('.monaco-editor textarea', { timeout: 10000 }).should('exist');
Expand Down
49 changes: 39 additions & 10 deletions src/Creator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ import useSuspenseLoader, {
import fetchFilters from './utils/fetchFilters';
import { ExtendedQuickstart } from './utils/fetchQuickstarts';
import useFilterMap from './hooks/useFilterMap';

const BASE_METADATA = {
name: 'test-quickstart',
};
import { useFlag } from '@unleash/proxy-client-react';

function makeDemoQuickStart(
kind: ItemKind | null,
Expand All @@ -37,7 +34,6 @@ function makeDemoQuickStart(
...baseQuickStart,
metadata: {
...baseQuickStart.metadata,
name: 'test-quickstart',
...(kindMeta?.extraMetadata ?? {}),
},
};
Expand All @@ -51,6 +47,9 @@ const CreatorInternal = ({
filterLoader: UnwrappedLoader<typeof fetchFilters>;
}) => {
const { data: filterData } = filterLoader();
const showGitService = useFlag(
'platform.learning-resources.quickstarts.git-service'
);
const [rawKind, setRawKind] = useState<ItemKind | null>(null);
const filterMap = useFilterMap({ data: filterData });

Expand Down Expand Up @@ -89,6 +88,16 @@ const CreatorInternal = ({
}));
};

const updateMetadataName = (name: string) => {
setRawQuickStart((old) => ({
...old,
metadata: {
...old.metadata,
name,
},
}));
};

const updateMetadataTags = (tags: Array<{ kind: string; value: string }>) => {
setRawQuickStart((old) => ({
...old,
Expand Down Expand Up @@ -139,8 +148,8 @@ const CreatorInternal = ({
});
});
updates.metadata = {
name: old.metadata.name,
tags: allTags,
...BASE_METADATA,
...meta.extraMetadata,
};

Expand All @@ -151,10 +160,27 @@ const CreatorInternal = ({
setRawKind(newKind);
};

const quickStart = useMemo(
() => makeDemoQuickStart(rawKind, rawQuickStart),
[rawKind, rawQuickStart]
);
const quickStart = useMemo(() => {
const demo = makeDemoQuickStart(rawKind, rawQuickStart);
if (!showGitService) return demo;

const allTags = bundles.toSorted().map((bundle) => ({
kind: 'bundle',
value: bundle,
}));
Object.entries(tags).forEach(([kind, values]) => {
values.forEach((value) => {
allTags.push({ kind, value });
});
});
return {
...demo,
metadata: {
...demo.metadata,
tags: allTags,
},
};
}, [rawKind, rawQuickStart, bundles, tags, showGitService]);

const files = useMemo(() => {
const effectiveName = quickStart.spec.displayName
Expand Down Expand Up @@ -233,6 +259,9 @@ const CreatorInternal = ({
updateSpec(() => spec);
}}
onChangeMetadataTags={updateMetadataTags}
onChangeMetadataName={
showGitService ? updateMetadataName : undefined
}
filterData={filterData}
onChangeBundles={setBundles}
onChangeCurrentStage={setCurrentStage}
Expand Down
105 changes: 105 additions & 0 deletions src/components/creator/CreatePRModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from 'react';
import {
Alert,
Button,
Content,
Modal,
ModalBody,
ModalFooter,
ModalHeader,
Spinner,
} from '@patternfly/react-core';
import CodeBranchIcon from '@patternfly/react-icons/dist/dynamic/icons/code-branch-icon';
import { PRResponse } from '../../utils/createQuickstartPR';

type CreatePRModalProps = {
isOpen: boolean;
onClose: () => void;
onConfirm: () => void;
quickstartName: string;
prLoading: boolean;
prResult: PRResponse | null;
prError: string | null;
};

const CreatePRModal: React.FC<CreatePRModalProps> = ({
isOpen,
onClose,
onConfirm,
quickstartName,
prLoading,
prResult,
prError,
}) => {
const showConfirm = !prLoading && !prResult && !prError;

return (
<Modal
isOpen={isOpen}
onClose={prLoading ? undefined : onClose}
aria-label="Create Pull Request"
variant="small"
>
<ModalHeader
title={
prResult
? 'Pull Request Created'
: prError
? 'Pull Request Failed'
: 'Create Pull Request'
}
/>
<ModalBody>
{showConfirm && (
<Content component="p">
This will submit a pull request for{' '}
<strong>{quickstartName}</strong> to the quickstarts repository. The
PR will be checked against existing quickstarts to determine if this
is a new submission or an update.
</Content>
)}
{prLoading && (
<div style={{ textAlign: 'center', padding: '24px 0' }}>
<Spinner size="lg" />
<Content component="p" className="pf-v6-u-mt-md">
Submitting pull request...
</Content>
</div>
)}
{prResult && (
<Alert variant="success" title="PR created successfully" isInline>
<a href={prResult.prUrl} target="_blank" rel="noopener noreferrer">
{prResult.prUrl}
</a>
</Alert>
)}
{prError && (
<Alert variant="danger" title="Failed to create PR" isInline>
{prError}
</Alert>
)}
</ModalBody>
<ModalFooter>
{showConfirm && (
<Button
variant="primary"
onClick={onConfirm}
icon={<CodeBranchIcon />}
>
Confirm
</Button>
)}
{prError && (
<Button variant="primary" onClick={onConfirm}>
Retry
</Button>
)}
<Button variant="link" onClick={onClose} isDisabled={prLoading}>
{prResult ? 'Close' : 'Cancel'}
</Button>
</ModalFooter>
</Modal>
);
};

export default CreatePRModal;
4 changes: 4 additions & 0 deletions src/components/creator/CreatorWizard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { act, render, screen, waitFor } from '@testing-library/react';
import CreatorWizard, { CreatorWizardProps } from './CreatorWizard';
import { ExtendedQuickstart } from '../../utils/fetchQuickstarts';

jest.mock('@unleash/proxy-client-react', () => ({
useFlag: () => false,
}));

jest.mock('@redhat-cloud-services/frontend-components/useChrome', () => ({
__esModule: true,
useChrome: () => ({
Expand Down
Loading
Loading