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
27 changes: 21 additions & 6 deletions libs/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,18 @@
"Content is base64 encoded": "Content is base64 encoded",
"Delete file": "Delete file",
"Add file": "Add file",
"Inline application": "Inline application",
"Image based application": "Image based application",
"Quadlet application": "Quadlet application",
"Compose application": "Compose application",
"Application {{ appNum }}": "Application {{ appNum }}",
"Application type": "Application type",
"Select an application type": "Select an application type",
"Definition source": "Definition source",
"Configuration Sources": "Configuration Sources",
"OCI reference": "OCI reference",
"Pull definitions from container registry (reusable, versioned).": "Pull definitions from container registry (reusable, versioned).",
"Inline": "Inline",
"Define application files directly in this interface (custom, one-off).": "Define application files directly in this interface (custom, one-off).",
"OCI reference URL": "OCI reference URL",
"Application name": "Application name",
"The unique identifier for this application.": "The unique identifier for this application.",
"If not specified, the image name will be used. Application name must be unique.": "If not specified, the image name will be used. Application name must be unique.",
Expand All @@ -358,6 +365,7 @@
"Add an application variable": "Add an application variable",
"Application workloads": "Application workloads",
"Define the application workloads that shall run on the device.": "Define the application workloads that shall run on the device.",
"Configure containerized applications and services that will run on your fleet devices. You can deploy single containers, Quadlet applications for advanced container orchestration or inline applications with custom files.": "Configure containerized applications and services that will run on your fleet devices. You can deploy single containers, Quadlet applications for advanced container orchestration or inline applications with custom files.",
"Delete application": "Delete application",
"Add application": "Add application",
"(0777) Read, write, and execute permissions for all users.": "(0777) Read, write, and execute permissions for all users.",
Expand Down Expand Up @@ -429,7 +437,8 @@
"The device will download and apply updates as soon as they are available.": "The device will download and apply updates as soon as they are available.",
"Device alias": "Device alias",
"Device labels": "Device labels",
"Inline": "Inline",
"Quadlet": "Quadlet",
"Compose": "Compose",
"Image based": "Image based",
"Unnamed": "Unnamed",
"Device fleet": "Device fleet",
Expand Down Expand Up @@ -663,14 +672,20 @@
"Use alphanumeric characters, or underscore (_)": "Use alphanumeric characters, or underscore (_)",
"Variable value is required.": "Variable value is required.",
"Variable names of an application must be unique": "Variable names of an application must be unique",
"Application type is required": "Application type is required",
"Name is required for inline applications.": "Name is required for inline applications.",
"Definition source is required": "Definition source is required",
"Name is required for {{ appType }} applications.": "Name is required for {{ appType }} applications.",
"Use lowercase alphanumeric characters, or dash (-). Must start and end with an alphanumeric character.": "Use lowercase alphanumeric characters, or dash (-). Must start and end with an alphanumeric character.",
"File path is required": "File path is required",
"File path length cannot exceed {{ maxCharacters }} characters.": "File path length cannot exceed {{ maxCharacters }} characters.",
"Application file path must be relative. It cannot be outside the application directory.": "Application file path must be relative. It cannot be outside the application directory.",
"Inline applications must include at least one file.": "Inline applications must include at least one file.",
"Application must include at least one file.": "Application must include at least one file.",
"Each file of the same application must use different paths.": "Each file of the same application must use different paths.",
"File name must be one of: {{ allowedFileNames }}": "File name must be one of: {{ allowedFileNames }}",
"Unsupported quadlet file type {{ extension }}. Supported types: {{ supportedTypes }}": "Unsupported quadlet file type {{ extension }}. Supported types: {{ supportedTypes }}",
"Quadlet application must include at least one of the following file types: {{ supportedTypes }}": "Quadlet application must include at least one of the following file types: {{ supportedTypes }}",
"Quadlet files must be at root level (no subdirectories)": "Quadlet files must be at root level (no subdirectories)",
"Definition source must be image for this type of applications": "Definition source must be image for this type of applications",
"Application type is required": "Application type is required",
"Image is required.": "Image is required.",
"Application image includes invalid characters.": "Application image includes invalid characters.",
"Application name must be unique.": "Application name must be unique.",
Expand Down
7 changes: 5 additions & 2 deletions libs/types/models/ApplicationVolume.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
import type { ImageMountVolumeProviderSpec } from './ImageMountVolumeProviderSpec';
import type { ImageVolumeProviderSpec } from './ImageVolumeProviderSpec';
export type ApplicationVolume = {
import type { MountVolumeProviderSpec } from './MountVolumeProviderSpec';
export type ApplicationVolume = ({
/**
* Unique name of the volume used within the application.
*/
name: string;
} & ImageVolumeProviderSpec;
} & (ImageVolumeProviderSpec | MountVolumeProviderSpec | ImageMountVolumeProviderSpec));

6 changes: 6 additions & 0 deletions libs/types/models/DeviceApplicationStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/* eslint-disable */
import type { ApplicationStatusType } from './ApplicationStatusType';
import type { ApplicationVolumeStatus } from './ApplicationVolumeStatus';
import type { AppType } from './AppType';
export type DeviceApplicationStatus = {
/**
* Human readable name of the application.
Expand All @@ -18,6 +19,11 @@ export type DeviceApplicationStatus = {
*/
restarts: number;
status: ApplicationStatusType;
/**
* Whether the application is embedded in the bootc image.
*/
embedded: boolean;
appType: AppType;
/**
* Status of volumes used by this application.
*/
Expand Down
4 changes: 4 additions & 0 deletions libs/types/models/TokenResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export type TokenResponse = {
* Token type.
*/
token_type?: TokenResponse.token_type;
/**
* OIDC ID token (JWT). Present when using OIDC with openid scope.
*/
id_token?: string;
/**
* OAuth2 refresh token.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { Bullseye } from '@patternfly/react-core';
import { Bullseye, Label } from '@patternfly/react-core';
import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';

import { DeviceApplicationStatus } from '@flightctl/types';
Expand Down Expand Up @@ -35,6 +35,7 @@ const ApplicationsTable = ({ appsStatus, specApps }: ApplicationsTableProps) =>
<Th modifier="wrap">{t('Status')}</Th>
<Th modifier="wrap">{t('Ready')}</Th>
<Th modifier="wrap">{t('Restarts')}</Th>
<Th modifier="wrap">{t('Type')}</Th>
</Tr>
</Thead>
<Tbody>
Expand All @@ -43,6 +44,7 @@ const ApplicationsTable = ({ appsStatus, specApps }: ApplicationsTableProps) =>
status: null,
ready: '-',
restarts: '-',
appType: null,
};

return (
Expand All @@ -53,6 +55,9 @@ const ApplicationsTable = ({ appsStatus, specApps }: ApplicationsTableProps) =>
</Td>
<Td dataLabel={t('Ready')}>{appDetails.ready}</Td>
<Td dataLabel={t('Restarts')}>{appDetails.restarts}</Td>
<Td dataLabel={t('Type')}>
{appDetails.appType ? <Label variant="outline">{appDetails.appType}</Label> : '-'}
</Td>
</Tr>
);
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import {
AppType,
// eslint-disable-next-line no-restricted-imports
ApplicationProviderSpec,
ApplicationVolume,
ConfigProviderSpec,
DeviceSpec,
EncodingType,
FileSpec,
GitConfigProviderSpec,
HttpConfigProviderSpec,
ImageMountVolumeProviderSpec,
InlineApplicationProviderSpec,
InlineConfigProviderSpec,
KubernetesSecretProviderSpec,
Expand Down Expand Up @@ -209,26 +211,38 @@ export const toAPIApplication = (app: AppForm): ApplicationProviderSpec => {
return acc;
}, {});

const volumes = app.volumes?.map((v) => ({
name: v.name,
image: {
reference: v.reference,
pullPolicy: v.pullPolicy,
},
}));
const volumes = app.volumes?.map((v) => {
// @ts-expect-error We will only set the fields that are present
const volume: ApplicationVolume = {
name: v.name,
};
// It's either one of the two fields, or both.
// ImageMountVolumeProviderSpec is the spec that has both fields
if (v.image) {
(volume as ImageMountVolumeProviderSpec).image = v.image;
}
if (v.mount) {
(volume as ImageMountVolumeProviderSpec).mount = v.mount;
}
return volume;
});

if (isImageAppForm(app)) {
const data = {
const data: ApplicationProviderSpec = {
image: app.image,
appType: app.appType,
envVars,
volumes,
};
return app.name ? { ...data, name: app.name } : data;
if (app.name) {
data.name = app.name;
}
return data;
}

return {
name: app.name,
appType: AppType.AppTypeCompose,
appType: app.appType,
inline: app.files.map(
(file): InlineApplicationFileFixed => ({
path: file.path,
Expand Down Expand Up @@ -377,36 +391,32 @@ export const getApiConfig = (ct: SpecConfigTemplate): ConfigSourceProvider => {
const getAppFormVariables = (app: ApplicationProviderSpecFixed) =>
Object.entries(app.envVars || {}).map(([varName, varValue]) => ({ name: varName, value: varValue }));

const getAppFormVolumes = (app: ApplicationProviderSpecFixed) =>
app.volumes?.map((v) => ({
name: v.name,
reference: v.image.reference,
pullPolicy: v.image.pullPolicy,
}));

export const getApplicationValues = (deviceSpec?: DeviceSpec): AppForm[] => {
const apps = deviceSpec?.applications || [];
return apps.map((app) => {
if (!app.appType) {
throw new Error('Application appType is required');
}
if (isImageAppProvider(app)) {
return {
specType: AppSpecType.OCI_IMAGE,
name: app.name || '',
image: app.image,
appType: app.appType as AppType.AppTypeCompose | AppType.AppTypeQuadlet,
variables: getAppFormVariables(app),
volumes: getAppFormVolumes(app),
volumes: app.volumes || [],
};
}

const inlineApp = app as InlineApplicationProviderSpec;
return {
specType: AppSpecType.INLINE,
appType: app.appType,
name: app.name || '',
files: (app as InlineApplicationProviderSpec).inline.map((file) => ({
path: file.path || '',
content: file.content,
base64: file.contentEncoding === EncodingType.EncodingBase64,
})),
files: inlineApp.inline,
variables: getAppFormVariables(app),
volumes: getAppFormVolumes(app),
};
volumes: app.volumes || [],
} as InlineAppForm;
});
Comment thread
celdrake marked this conversation as resolved.
};

Expand Down
Loading