How to start with Cyborg

Warning

Saving a syntactically wrong YAML file will cause the dev server to fail.

Remember to regularly check for this and restart when needed.

How to add

new component

to a page?

// apps/jobportal/src/ui/Homepage/WorkshopTest.tsx

import { Section } from '@almacareer/cyborg-design-system/components/Section';

export default function WorkshopTest() {
	return <Section>Hello Cyborg!</Section>;
}
// apps/jobportal/src/app/[locale]/page.tsx

import { Container } from '@almacareer/cyborg-design-system/components/Container';
// ...
import WorkshopTest from '@/ui/Homepage/WorkshopTest';

export default async function HomePage() {
	const language = getLocale();
	const { t } = await getTranslator(language);

	return (
		<>
			<SearchContainer hasBackground>
				<Heading
					dangerouslySetInnerHTML={{ __html: t('page.homepage.content.h1') }}
					elementType="h1"
				/>
			</SearchContainer>
            <WorkshopTest />
			<Section>
				<Container variant="cygnus">
					<SectionElite />
				</Container>
			</Section>
			<Section>
				<Container variant="cygnus">
					<SectionAdvice />
				</Container>
			</Section>
		</>
	);
}

How to check

if featureFlag

is enabled?

# apps/jobportal/configuration/defaults/defaultFeatureFlags.yaml

apiVersion: cyborg/v1
kind: FeatureFlags
metadata:
  name: default.featureFlags
spec:
  applicationForm.page: false
  foobar: true
// apps/jobportal/src/ui/Homepage/WorkshopTest.tsx

import { Section } from '@almacareer/cyborg-design-system/components/Section';
import { WithServerFeature } from '@almacareer/cyborg-service-container/component/server';
import container from '@generated/container.server';

export default function WorkshopTest() {
	const isEnabled = container.isFeatureFlagEnabled('foobar');

	return (
		<Section>
			<p>Hello Cyborg!</p>
			<p>
				Feature flag <code>foobar</code>
                is {isEnabled ? 'enabled' : 'disabled'}
			</p>
			<WithServerFeature
                name="applicationForm.page"
                fallback={<strong>DISABLED</strong>}
            >
				ENABLED
			</WithServerFeature>
		</Section>
	);
}

How to query value

of a parameter?

// apps/jobportal/src/ui/Homepage/WorkshopTest.tsx

import { Section } from '@almacareer/cyborg-design-system/components/Section';
import { WithServerFeature } from '@almacareer/cyborg-service-container/component/server';
import container from '@generated/container.server';

export default function WorkshopTest() {
	const isEnabled = container.isFeatureFlagEnabled('foobar');

	return (
		<Section>
			<p>Hello Cyborg!</p>
   			<p>
				The current default language for this jobboard is{' '}
				<strong>{container.getParameter('language')}</strong>
			</p>
			<p>
				Feature flag <code>foobar</code>
                is {isEnabled ? 'enabled' : 'disabled'}
			</p>
			<WithServerFeature
                name="applicationForm.page"
                fallback={<strong>DISABLED</strong>}
            >
				ENABLED
			</WithServerFeature>
		</Section>
	);
}

How to override values for specific jobboards?

  • Locate the configuration folder for overrides:
    • apps/jobportal/configuration/{JOBBOARD_NAME}
  • Find or create configuration file of a required kind
  • Add of change the required option

How to

create a plugin?

mkdir plugins/my-awesome-plugin

cd plugins/my-awesome-plugin

mkdir configuration
mkdir src

Step 1: Create folder and structure

{
	"name": "@almacareer/cyborg-my-awesome-plugin",
	"version": "0.1.0",
	"private": true,
	"type": "module",
	"types": "./src/index.ts",
	"scripts": {
		"create-registry": "tsx ../../libs/create-container/bin/run.ts -o var -c configuration --registry-only",
		"lint": "npm-run-all --serial types lint:scripts",
		"types": "yarn create-registry && tsc",
		"test": "yarn create-registry && vitest run"
	},
	"dependencies": {
		"@almacareer/cyborg-configuration": "workspace:^",
		"@almacareer/cyborg-service-container": "workspace:^",
		"@lmc-eu/spirit-web-react": "^2.4.0"
	},
	"devDependencies": {
		"eslint-config-cyborg": "workspace:^",
   		"tsx": "^4.19.2",
  		"typescript": "^5.6.3",
		"vite-tsconfig-paths": "^5.0.1",
		"vitest": "~2.1.6",
		"vitest-config-cyborg": "workspace:^"
	},
	"exports": {
		".": "./src/index.ts",
		"./server": "./src/server.ts"
	}
}

Step 2: package.json

{
	"extends": "../../configs/typescript-config-cyborg/dom",
	"include": ["./src/**/*", "./tests/**/*", "./var/**/*"]
}

Step 3: tsconfig.json

import tsconfigPaths from 'vite-tsconfig-paths';
import config from 'vitest-config-cyborg';
import { mergeConfig } from 'vitest/config';

export default mergeConfig(config, {
	plugins: [tsconfigPaths()],
});

Step 4: vitest.config.ts

yarn workspace @almacareer/cyborg-jobportal add @almacareer/cyborg-my-awesome-plugin

yarn install

Step 5: Add as a dependency to the main app

yarn dev

Step 6: Restart dev server

How to

create component inside a plugin?

// plugins/my-awesome-plugin/src/ui/PluginTest.tsx

export default function PluginTest() {
	return <p>This is My Awesome Plugin</p>;
}

Create a component

// plugins/my-awesome-plugin/src/index.ts

import PluginTest from './ui/PluginTest';

export { PluginTest };

Export the component from plugin

// apps/jobportal/src/ui/Homepage/WorkshopTest.tsx

// ...
import { PluginTest } from '@almacareer/cyborg-my-awesome-plugin';
import {
	WithServerFeature,
	WithServerPlugin,
} from '@almacareer/cyborg-service-container/component/server';

export default function WorkshopTest() {
	const isEnabled = container.isFeatureFlagEnabled('foobar');
	const isPluginEnabled = container.isPluginEnabled('myAwesomePlugin');

	return (
		<Section>
			<Container variant="cygnus">
                {/* ... */}
				{isPluginEnabled
                    ? <PluginTest />
                    : <strong>My Awesome Plugin is disabled</strong>
                }
				<WithServerPlugin name="myAwesomePlugin">
					<PluginTest />
				</WithServerPlugin>
			</Container>
		</Section>
	);
}

Use it in application

How to allow component to be overidden?

// plugins/my-awesome-plugin/package.json

{
	"name": "@almacareer/cyborg-my-awesome-plugin",
	"version": "0.1.0",
	"private": true,
	"type": "module",
	"exports": {
		".": "./src/index.ts",
		"./server": "./src/server.ts",
		"./PluginTest": "./src/ui/PluginTest.tsx"
	},
	"scripts": {
		// ...
	}
}

Allow the source file to imported

# plugins/my-awesome-plugin/configuration/components.yaml

apiVersion: cyborg/v1
kind: Components
metadata:
  name: myAwesomePlugin.components
  namespace: myAwesomePlugin
  labels:
    cyborg/plugin: myAwesomePlugin
spec:
  server:
    AwesomeCyborg: '@almacareer/cyborg-my-awesome-plugin/PluginTest'

Register the component in a container

// apps/jobportal/src/ui/Homepage/WorkshopTest.tsx

import { Container } from '@almacareer/cyborg-design-system/components/Container';
import { Section } from '@almacareer/cyborg-design-system/components/Section';
import {
	WithServerFeature,
	WithServerPlugin,
} from '@almacareer/cyborg-service-container/component/server';
import container from '@generated/container.server';

export default function WorkshopTest() {
	const isEnabled = container.isFeatureFlagEnabled('foobar');
	const isPluginEnabled = container.isPluginEnabled('myAwesomePlugin');
	const PluginTest = container.getComponent('myAwesomePlugin.AwesomeCyborg');

	return (
		<Section>
			<Container variant="cygnus">
				<p>Hello Cyborg!</p>
				{/* ... */}
				{isPluginEnabled ? <PluginTest /> : <strong>My Awesome Plugin is disabled</strong>}
				<WithServerPlugin name="myAwesomePlugin">
					<PluginTest />
				</WithServerPlugin>
			</Container>
		</Section>
	);
}

Use it in application

// apps/jobportal/src/ui/Homepage/EvenMoreAwesomeCyborg.tsx

export default function EvenMoreAwesomeCyborg() {
	return <h1>This is even more awesome!</h1>;
}

Create an override

# apps/jobportal/configuration/cyborg/myAwesomePlugin.yaml

apiVersion: cyborg/v1
kind: Components
metadata:
  name: cyborg.myAwesomePlugin.Components
  namespace: myAwesomePlugin
spec:
  server:
    AwesomeCyborg: '@/ui/Homepage/EvenMoreAwesomeCyborg'

Register the override in configuration

How to

ask for a thing

from container

inside a plugin?

# plugins/my-awesome-plugin/configuration/dependencies.yaml 

apiVersion: cyborg/v1
kind: Dependencies
metadata:
  name: myAwesomePlugin.Dependencies
spec:
  parameters:
    language: string

Declare what you expect

cd plugins/my-awesome-plugin

yarn create-registry

Generate registry (for TypeScript support)

// plugins/my-awesome-plugin/src/ui/PluginTest.tsx

import container from '@almacareer/cyborg-service-container/server';

export default function PluginTest() {
	return (
		<>
			<p>This is My Awesome Plugin</p>
			<p>
				The name of the portal is {container.getBrand()}{' '}
				and the default language is {container.getParameter('language')}
			</p>
		</>
	);
}

Import container

How to

create a new route?

// plugins/my-awesome-plugin/src/pages/AwesomeHelloPage.tsx

export default function AwesomeHelloPage() {
	return (
		<>
			<h1>This page is defined inside a plugin</h1>
		</>
	);
}

Create a page component

// plugins/my-awesome-plugin/src/index.ts

import AwesomeHelloPage from './pages/AwesomeHelloPage';

export { AwesomeHelloPage };

Export it from a plugin (or register ina  container)

// apps/jobportal/src/app/[locale]/hello/page.tsx

import { AwesomeHelloPage } from '@almacareer/cyborg-my-awesome-plugin';

export default function HelloPage() {
	return <AwesomeHelloPage />;
}

Create a Next.js route

# plugins/my-awesome-plugin/configuration/routes.yaml

apiVersion: cyborg/v1
kind: Routes
metadata:
  name: myAwesomePlugin.routes
  namespace: myAwesomePlugin
  labels:
    cyborg/plugin: myAwesomePlugin
spec:
  awesomeHello:
    targetPath: /hello
    path:
      en: /hello-en
      sk: /hello-sk
      cs: /hello-cs
      de: /hello-de
      hr: /hello-hr

Register a Cyborg route

Visit a new page

http://localhost:3000/hello-en

How to start with Cyborg

By Milan Herda

How to start with Cyborg

  • 70