Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,63 @@ jobs:
run: npm ci
- name: Attempt a build
run: npm run build:ocp
build-containers:
name: Build containers
runs-on: ubuntu-latest
strategy:
matrix:
os: [el9, el10]
variant: [standalone, ocp]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x

- name: Install dependencies
run: npm ci

- name: Determine Containerfile
id: containerfile
run: |
if [[ "${{ matrix.variant }}" == "standalone" ]]; then
echo "file=packaging/images/${{ matrix.os }}/Containerfile" >> $GITHUB_OUTPUT
else
echo "file=packaging/images/${{ matrix.os }}/Containerfile.ocp" >> $GITHUB_OUTPUT
fi

- name: Build container (${{ matrix.os }} ${{ matrix.variant }})
run: |
echo "Building ${{ matrix.variant }} UI container for ${{ matrix.os }}..."
podman build -f ${{ steps.containerfile.outputs.file }} -t test-ui:${{ matrix.os }}-${{ matrix.variant }} .
echo "✓ Successfully built ${{ matrix.os }} ${{ matrix.variant }} container"

- name: Verify container - help command
id: verify-help
run: |
echo "Testing help command..."
if timeout 30s podman run --rm test-ui:${{ matrix.os }}-${{ matrix.variant }} ./flightctl-ui --help; then
echo "Help command successful"
echo "passed=true" >> $GITHUB_OUTPUT
else
echo "Help command failed"
echo "passed=false" >> $GITHUB_OUTPUT
fi

- name: Verify container - binary exists
if: steps.verify-help.outputs.passed != 'true'
run: |
echo "Help command failed, checking if binary exists..."
if timeout 30s podman run --rm test-ui:${{ matrix.os }}-${{ matrix.variant }} ls -la /app/proxy/flightctl-ui; then
echo "Binary exists but help command failed"
else
echo "Binary missing"
exit 1
fi

integration-tests:
needs: preflight-check
if: needs.preflight-check.outputs.skip == 'false'
Expand Down
26 changes: 22 additions & 4 deletions .github/workflows/push-to-main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,23 @@ jobs:
publish-flightctl-ui:
runs-on: ubuntu-latest
needs: [generate-tags]
strategy:
matrix:
os: [el9, el10]
steps:
- uses: actions/checkout@v4

- name: Generate OS-specific image name
id: os-image
run: |
echo "image_name=${{ env.QUAY_STANDALONE_REPO }}-${{ matrix.os }}" >> $GITHUB_OUTPUT
echo "Generated image name: ${{ env.QUAY_STANDALONE_REPO }}-${{ matrix.os }}"

- name: Build
id: build
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.QUAY_STANDALONE_REPO }}
image: ${{ steps.os-image.outputs.image_name }}
tags: ${{ needs.generate-tags.outputs.image_tags }}
labels: |
org.flightctl.flightctl-ui.github.repository=${{ github.repository }}
Expand All @@ -63,7 +72,7 @@ jobs:
org.flightctl.flightctl-ui.github.ref_name=${{ github.ref_name }}
extra-args: |
--ulimit nofile=10000:10000
containerfiles: Containerfile
containerfiles: packaging/images/${{ matrix.os }}/Containerfile
context: .

- name: Validate FIPS
Expand All @@ -86,14 +95,23 @@ jobs:
publish-flightctl-ocp-ui:
runs-on: ubuntu-latest
needs: [generate-tags]
strategy:
matrix:
os: [el9, el10]
steps:
- uses: actions/checkout@v4

- name: Generate OS-specific image name
id: os-image
run: |
echo "image_name=${{ env.QUAY_OCP_REPO }}-${{ matrix.os }}" >> $GITHUB_OUTPUT
echo "Generated image name: ${{ env.QUAY_OCP_REPO }}-${{ matrix.os }}"

- name: Build
id: build
uses: redhat-actions/buildah-build@v2
with:
image: ${{ env.QUAY_OCP_REPO }}
image: ${{ steps.os-image.outputs.image_name }}
tags: ${{ needs.generate-tags.outputs.image_tags }}
labels: |
org.flightctl.flightctl-ui.github.repository=${{ github.repository }}
Expand All @@ -103,7 +121,7 @@ jobs:
org.flightctl.flightctl-ui.github.ref_name=${{ github.ref_name }}
extra-args: |
--ulimit nofile=10000:10000
containerfiles: Containerfile.ocp
containerfiles: packaging/images/${{ matrix.os }}/Containerfile.ocp
context: .

- name: Validate FIPS
Expand Down
84 changes: 84 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# FlightCtl UI Makefile for EL9/EL10 parallel support

# Default OS - can be overridden with OS=el10
OS ?= el9

# Container registry settings
REGISTRY ?= quay.io
REGISTRY_OWNER ?= flightctl

# Version/tag settings
SOURCE_GIT_TAG ?= $(shell git describe --long --tags --exclude latest --dirty)
VERSION ?= $(shell echo $(SOURCE_GIT_TAG) | sed 's/^v//')

# Image names
STANDALONE_IMAGE_NAME = flightctl-ui
OCP_IMAGE_NAME = flightctl-ocp-ui

# Build targets
.PHONY: help build-ui build-ocp-ui build-all clean

help: ## Show this help message
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

build-ui: packaging/images/$(OS)/Containerfile ## Build standalone UI container for current OS (default: el9)
@echo "Building standalone UI container for $(OS)..."
podman build \
-f packaging/images/$(OS)/Containerfile \
-t localhost/$(STANDALONE_IMAGE_NAME)-$(OS):latest \
-t $(REGISTRY)/$(REGISTRY_OWNER)/$(STANDALONE_IMAGE_NAME)-$(OS):$(VERSION) \
.

build-ocp-ui: packaging/images/$(OS)/Containerfile.ocp ## Build OCP UI container for current OS (default: el9)
@echo "Building OCP UI container for $(OS)..."
podman build \
-f packaging/images/$(OS)/Containerfile.ocp \
-t localhost/$(OCP_IMAGE_NAME)-$(OS):latest \
-t $(REGISTRY)/$(REGISTRY_OWNER)/$(OCP_IMAGE_NAME)-$(OS):$(VERSION) \
.

build-ui-el9: ## Build standalone UI container for EL9
$(MAKE) build-ui OS=el9

build-ui-el10: ## Build standalone UI container for EL10
$(MAKE) build-ui OS=el10

build-ocp-ui-el9: ## Build OCP UI container for EL9
$(MAKE) build-ocp-ui OS=el9

build-ocp-ui-el10: ## Build OCP UI container for EL10
$(MAKE) build-ocp-ui OS=el10

build-all: build-ui-el9 build-ui-el10 build-ocp-ui-el9 build-ocp-ui-el10 ## Build all UI containers (both OS variants)

clean: ## Clean up built containers
@echo "Cleaning up UI containers..."
podman rmi -f localhost/$(STANDALONE_IMAGE_NAME)-el9:latest localhost/$(STANDALONE_IMAGE_NAME)-el10:latest 2>/dev/null || true
podman rmi -f localhost/$(OCP_IMAGE_NAME)-el9:latest localhost/$(OCP_IMAGE_NAME)-el10:latest 2>/dev/null || true
@echo "Cleanup complete"

# Development targets
dev: ## Run standalone UI in development mode
npm run dev

dev-ocp: ## Run OCP plugin UI in development mode
npm run dev:ocp

install: ## Install npm dependencies
npm ci

build: ## Build UI applications (npm build)
npm run build

build-ocp: ## Build OCP plugin application
npm run build:ocp

lint: ## Run linting
npm run lint

# Show current configuration
show-config: ## Show current build configuration
@echo "OS: $(OS)"
@echo "VERSION: $(VERSION)"
@echo "REGISTRY: $(REGISTRY)"
@echo "REGISTRY_OWNER: $(REGISTRY_OWNER)"
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,47 @@ Monorepo containing UIs for [Flight Control](https://github.com/flightctl/flight

## Building

### Checkout the repository and run
### JavaScript/TypeScript Applications

Checkout the repository and run:

```shell
cd flightctl-ui
npm ci
npm run build
```

### Container Images (EDM-3308: EL9/EL10 Support)

The UI supports building containers for both Enterprise Linux 9 and 10. Containerfiles are organized by OS in a directory structure similar to the main FlightCtl repository:

```text
packaging/images/el9/Containerfile # EL9 standalone UI
packaging/images/el9/Containerfile.ocp # EL9 OCP plugin UI
packaging/images/el10/Containerfile # EL10 standalone UI
packaging/images/el10/Containerfile.ocp # EL10 OCP plugin UI
```

Use the provided Makefile:

```shell
# Build for specific OS (default: el9)
make build-ui OS=el9 # Standalone UI for EL9
make build-ui OS=el10 # Standalone UI for EL10
make build-ocp-ui OS=el9 # OCP Plugin UI for EL9
make build-ocp-ui OS=el10 # OCP Plugin UI for EL10

# Build all variants
make build-all

# Show available targets
make help
```

Built images will use OS-qualified names:
- `localhost/flightctl-ui-el9:latest` and `localhost/flightctl-ocp-ui-el9:latest`
- `localhost/flightctl-ui-el10:latest` and `localhost/flightctl-ocp-ui-el10:latest`

### Running Standalone UI with backend running in Kind

If backend is running in your Kind cluster, use the following command to start the UI application.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ import FlightCtlWizardFooter from '../../common/FlightCtlWizardFooter';
import LeaveFormConfirmation from '../../common/LeaveFormConfirmation';
import ErrorBoundary from '../../common/ErrorBoundary';
import { getErrorMessage } from '../../../utils/error';
import { usePermissionsContext } from '../../common/PermissionsContext';
import PageWithPermissions from '../../common/PageWithPermissions';
import { RESOURCE, VERB } from '../../../types/rbac';

const orderedIds = [generalInfoStepId, typeConfigStepId, versionStepId, reviewStepId];

Expand Down Expand Up @@ -250,4 +253,26 @@ const AddCatalogItemWizard = () => {
);
};

export default AddCatalogItemWizard;
const addCatalogItemWizardPermissions = [
{ kind: RESOURCE.CATALOG, verb: VERB.LIST },
{ kind: RESOURCE.CATALOG_ITEM, verb: VERB.GET },
{ kind: RESOURCE.CATALOG_ITEM, verb: VERB.CREATE },
{ kind: RESOURCE.CATALOG_ITEM, verb: VERB.PATCH },
];

const AddCatalogItemWizardWithPermissions = () => {
const {
router: { useParams },
} = useAppContext();
const { catalogId, itemId } = useParams<{ catalogId: string; itemId: string }>();
const isEdit = !!catalogId && !!itemId;
const { checkPermissions, loading } = usePermissionsContext();
const [canListCatalogs, canGet, canCreate, canPatch] = checkPermissions(addCatalogItemWizardPermissions);
return (
<PageWithPermissions allowed={canListCatalogs && (isEdit ? canPatch && canGet : canCreate)} loading={loading}>
<AddCatalogItemWizard />
</PageWithPermissions>
);
};

export default AddCatalogItemWizardWithPermissions;
12 changes: 8 additions & 4 deletions libs/ui-components/src/components/Catalog/CatalogPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import CreateCatalogModal from './AddCatalogItemWizard/CreateCatalogModal';
import WithTooltip from '../common/WithTooltip';
import ResourceSyncImportStatus from '../ResourceSync/ResourceSyncImportStatus';
import CatalogLandingPage, { CatalogLandingPageContent, useLandingPagePermissions } from './CatalogLandingPage';
import PageWithPermissions from '../common/PageWithPermissions';

import './CatalogPage.css';

Expand Down Expand Up @@ -424,16 +425,19 @@ const catalogPagePermissions = [
{ kind: RESOURCE.DEVICE, verb: VERB.PATCH },
{ kind: RESOURCE.CATALOG, verb: VERB.PATCH },
{ kind: RESOURCE.CATALOG, verb: VERB.DELETE },
{ kind: RESOURCE.CATALOG_ITEM, verb: VERB.LIST },
{ kind: RESOURCE.CATALOG, verb: VERB.LIST },
];

const CatalogPage = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const { checkPermissions } = usePermissionsContext();
const [canEditFleet, canEditDevice, canEditCatalog, canDeleteCatalog] = checkPermissions(catalogPagePermissions);
const { checkPermissions, loading } = usePermissionsContext();
const [canEditFleet, canEditDevice, canEditCatalog, canDeleteCatalog, canListItems, canListCatalogs] =
checkPermissions(catalogPagePermissions);

return (
<>
<PageWithPermissions allowed={canListItems && canListCatalogs} loading={loading}>
<ResourceSyncImportStatus type="catalog" />
<ListPage title={t('Software Catalog')}>
<CatalogPageContent
Expand All @@ -453,7 +457,7 @@ const CatalogPage = () => {
showCatalogMgmt
/>
</ListPage>
</>
</PageWithPermissions>
);
};

Expand Down
Loading
Loading