Skip to content

Reflect RBAC rules from backend in GUI #2058

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ interface IProps {
userInput: object;
isTask?: boolean;
isResuming?: boolean;
disabled?: boolean;
}

interface Buttons {
Expand Down Expand Up @@ -433,6 +434,7 @@ export function WfoUserInputForm({
userInput,
isTask = false,
isResuming = false,
disabled = false,
}: IProps) {
const t = useTranslations('pydanticForms.userInputForm');
const tDialog = useTranslations('confirmationDialog');
Expand Down Expand Up @@ -544,6 +546,7 @@ export function WfoUserInputForm({
openLeavePageDialog(previous, t('previousQuestion')),
);
}}
disabled={disabled}
>
{buttons.previous.text ?? t('previous')}
</EuiButton>
Expand Down Expand Up @@ -586,6 +589,7 @@ export function WfoUserInputForm({
color={buttons.next.color ?? 'primary'}
isLoading={processing}
type="submit"
disabled={disabled}
>
{buttons.next.text ?? t('next')}
</EuiButton>
Expand All @@ -603,6 +607,7 @@ export function WfoUserInputForm({
: () => <WfoPlayFill color="#FFF" />
}
iconSide="right"
disabled={disabled}
>
{buttons.next.text ?? t(nextButtonTranslationKey)}
</EuiButton>
Expand Down Expand Up @@ -653,6 +658,7 @@ export function WfoUserInputForm({
showInlineError={true}
validate="onSubmit"
model={userInput}
disabled={disabled}
>
<AutoFields omitFields={['buttons']} />
{/* Show top level validation info about backend validation */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface UserInputFormWizardProps {
isTask: boolean;
hasNext?: boolean;
isResuming?: boolean;
allowSubmit?: boolean;
}

function stop(e: React.SyntheticEvent) {
Expand All @@ -51,6 +52,7 @@ export const UserInputFormWizard = ({
cancel,
isTask,
isResuming = false,
allowSubmit = true,
}: UserInputFormWizardProps) => {
const router = useRouter();
const [forms, setForms] = useState<Form[]>([
Expand Down Expand Up @@ -119,6 +121,7 @@ export const UserInputFormWizard = ({
userInput={currentUserInput}
isTask={isTask}
isResuming={isResuming}
disabled={!allowSubmit}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const WfoStartTaskButtonComboBox = () => {
workflowName: option.name,
},
label: option.description ?? option.name,
disabled: option.isAllowed === false,
}))
.sort((taskA, taskB) => taskA.label.localeCompare(taskB.label));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const WfoStartWorkflowButtonComboBox = () => {
productId: option.productId,
},
label: option.productName || '',
disabled: option.isAllowed === false,
}));

const handleOptionChange = async (selectedProduct: StartComboBoxOption) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useOrchestratorTheme, useWithOrchestratorTheme } from '@/hooks';
import { WfoChevronDown, WfoChevronUp } from '@/icons';
import type { EmailState } from '@/types';
import { StepStatus } from '@/types';
import { FormUserPermissions } from '@/types/forms';
import { calculateTimeDifference, formatDate } from '@/utils';

import { WfoStepStatusIcon } from '../WfoStepStatusIcon';
Expand All @@ -31,6 +32,7 @@ export interface WfoStepProps {
isTask: boolean;
isStartStep?: boolean;
processId?: string;
userPermissions: FormUserPermissions;
}

export const WfoStep = React.forwardRef(
Expand All @@ -43,6 +45,7 @@ export const WfoStep = React.forwardRef(
isStartStep = false,
isTask,
processId,
userPermissions,
}: WfoStepProps,
ref: LegacyRef<HTMLDivElement>,
) => {
Expand Down Expand Up @@ -209,6 +212,7 @@ export const WfoStep = React.forwardRef(
userInputForm={userInputForm}
isTask={isTask}
processId={processId}
userPermissions={userPermissions}
/>
)}
</EuiPanel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ import { UserInputFormWizard, WfoError, WfoLoading } from '@/components';
import { useOrchestratorTheme } from '@/hooks';
import { HttpStatus } from '@/rtk';
import { useResumeProcessMutation } from '@/rtk/endpoints/forms';
import { InputForm } from '@/types/forms';
import { FormUserPermissions, InputForm } from '@/types/forms';

interface WfoStepFormProps {
userInputForm: InputForm;
isTask: boolean;
processId?: string;
userPermissions: FormUserPermissions;
}

export const WfoStepForm = ({
userInputForm,
isTask,
processId,
userPermissions,
}: WfoStepFormProps) => {
const [isProcessing, setIsProcessing] = useState<boolean>(false);
const [hasError, setHasError] = useState<boolean>(false);
Expand Down Expand Up @@ -57,6 +59,7 @@ export const WfoStepForm = ({
hasNext={false}
isTask={isTask}
isResuming={true}
allowSubmit={userPermissions.resumeAllowed}
/>
)}
</EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { Ref, useImperativeHandle, useRef } from 'react';
import { getPageTemplateStyles } from '@/components/WfoPageTemplate/WfoPageTemplate/styles';
import { getTimelineStyles } from '@/components/WfoTimeline/styles';
import { useContentRef, useWithOrchestratorTheme } from '@/hooks';
import { FormUserPermissions } from '@/types/forms';

import { WfoStep } from '../WfoStep';
import { getWorkflowStepsStyles } from '../styles';
Expand All @@ -20,6 +21,7 @@ export type WfoStepListProps = {
onTriggerExpandStepListItem: (stepListItem: StepListItem) => void;
isTask: boolean;
processId: string;
userPermissions: FormUserPermissions;
};

export const WfoStepList = React.forwardRef(
Expand All @@ -32,6 +34,7 @@ export const WfoStepList = React.forwardRef(
onTriggerExpandStepListItem,
isTask,
processId,
userPermissions,
}: WfoStepListProps,
reference: Ref<WfoStepListRef>,
) => {
Expand Down Expand Up @@ -120,6 +123,7 @@ export const WfoStepList = React.forwardRef(
isStartStep={index === 0}
isTask={isTask}
processId={processId}
userPermissions={userPermissions}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import WfoDiff from '@/components/WfoDiff/WfoDiff';
import { WfoTraceback } from '@/components/WfoWorkflowSteps/WfoTraceback/WfoTraceback';
import { useGetRawProcessDetailQuery } from '@/rtk/endpoints/processDetail';
import { ProcessStatus, Step, StepStatus } from '@/types';
import { InputForm } from '@/types/forms';
import { FormUserPermissions, InputForm } from '@/types/forms';

export type StepListItem = {
step: Step;
Expand All @@ -29,6 +29,7 @@ export interface WfoWorkflowStepListProps {
processId: string;
isTask: boolean;
userInputForm?: InputForm;
userPermissions: FormUserPermissions;
}

export const WfoProcessRawData = ({ processId }: { processId: string }) => {
Expand Down Expand Up @@ -74,6 +75,7 @@ export const WfoWorkflowStepList = React.forwardRef(
processId,
isTask,
userInputForm,
userPermissions,
}: WfoWorkflowStepListProps,
reference: Ref<WfoStepListRef>,
) => {
Expand Down Expand Up @@ -214,6 +216,7 @@ export const WfoWorkflowStepList = React.forwardRef(
}
processId={processId}
onTriggerExpandStepListItem={handleExpandStepListItem}
userPermissions={userPermissions}
/>
)}
</>
Expand Down
3 changes: 2 additions & 1 deletion packages/orchestrator-ui-components/src/messages/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,8 @@
"no_validate_workflow": "This subscription can not be validated as the product has no validate workflows.",
"not_in_sync": "This subscription can not be modified because it is not in-sync. This means there is some error in the registration of the subscription or that it is being modified by another workflow.",
"relations_not_in_sync": "This subscription can not be modified because some related subscriptions are not in-sync. Locked subscriptions: {locked_relations}",
"no_modify_subscription_in_use_by_others": "This subscription can not be modified because it is in use by one or more other subscriptions: {unterminated_parents}"
"no_modify_subscription_in_use_by_others": "This subscription can not be modified because it is in use by one or more other subscriptions: {unterminated_parents}",
"insufficient_workflow_permissions": "Insufficient user permissions to run this workflow"
}
},
"subscriptionInstanceId": "Instance ID",
Expand Down
3 changes: 2 additions & 1 deletion packages/orchestrator-ui-components/src/messages/nl-NL.json
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@
"no_validate_workflow": "Deze subscription kan niet worden gevalideerd omdat het product geen validate workflows heeft.",
"not_in_sync": "Deze subscription kan niet worden gewijzigd omdat het niet in-sync is. Dit betekent dat er een fout zit in de registratie van de subscription of dat het wordt gewijzigd door een andere workflow.",
"relations_not_in_sync": "Deze subscription kan niet worden gewijzigd omdat sommige gerelateerde subscriptions niet in-sync zijn. Geblokkeerde subscriptions: {locked_relations}",
"no_modify_subscription_in_use_by_others": "Deze subscription kan niet worden gewijzigd omdat het in gebruik is door een of meer andere subscriptions: {unterminated_parents}"
"no_modify_subscription_in_use_by_others": "Deze subscription kan niet worden gewijzigd omdat het in gebruik is door een of meer andere subscriptions: {unterminated_parents}",
"insufficient_workflow_permissions": "Onvoldoende rechten om deze actie uit te kunnen voeren"
}
},
"subscriptionInstanceId": "Instance ID",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export const WfoProcessDetail = ({

const retryButtonIsDisabled =
buttonsAreDisabled ||
processDetail?.userPermissions!.retryAllowed === false ||
!listIncludesStatus(
[
ProcessStatus.FAILED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const WfoProcessDetailPage = ({
userInputForm={processDetail.form}
startedAt={processDetail.startedAt}
isTask={isTask}
userPermissions={processDetail.userPermissions}
/>
)) || <h1>Invalid processId</h1>}
</WfoProcessDetail>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export const processDetailQuery = `query ProcessDetail($processId: String!) {
isTask
form
traceback
userPermissions {
retryAllowed
resumeAllowed
}
steps {
name
status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const workflowOptionsQuery = `
workflows(first: 1000000, after: 0, filterBy: [{ field: "target", value: "${WorkflowTarget.CREATE}"}]) {
page {
name
isAllowed
products {
productType
productId
Expand All @@ -28,6 +29,7 @@ const taskOptionsQuery = `
workflows(first: 1000000, after: 0, filterBy: [{ field: "isTask", value: "true"}]) {
page {
name
isAllowed
description
}
}
Expand All @@ -36,6 +38,7 @@ const taskOptionsQuery = `

type WorkflowOption = {
workflowName: WorkflowDefinition['name'];
isAllowed: WorkflowDefinition['isAllowed'];
productName: ProductDefinition['name'];
productId: ProductDefinition['productId'];
productType: ProductDefinition['productType'];
Expand All @@ -44,6 +47,7 @@ type WorkflowOption = {

type WorkflowOptionsResult = StartOptionsResult<{
name: WorkflowDefinition['name'];
isAllowed: WorkflowDefinition['isAllowed'];
products: {
name: ProductDefinition['name'];
productId: ProductDefinition['productId'];
Expand All @@ -56,7 +60,10 @@ export type StartOptionsResponse<StartOption> = {
startOptions: StartOption[];
};

type TaskOption = Pick<WorkflowDefinition, 'name' | 'description'>;
type TaskOption = Pick<
WorkflowDefinition,
'name' | 'isAllowed' | 'description'
>;
type TaskOptionsResult = StartOptionsResult<TaskOption>;

const startButtonOptionsApi = orchestratorApi.injectEndpoints({
Expand All @@ -78,6 +85,7 @@ const startButtonOptionsApi = orchestratorApi.injectEndpoints({
workflow.products.forEach((product) => {
startOptions.push({
workflowName,
isAllowed: workflow.isAllowed,
productName: product.name,
productId: product.productId,
productType: product.productType,
Expand All @@ -97,6 +105,7 @@ const startButtonOptionsApi = orchestratorApi.injectEndpoints({
return {
startOptions: response.workflows.page.map((option) => ({
name: option.name,
isAllowed: option.isAllowed,
description: option.description,
})),
};
Expand Down
5 changes: 5 additions & 0 deletions packages/orchestrator-ui-components/src/types/forms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,8 @@ export type FormValidationError = {
data: ValidationErrorData;
status: HttpStatus;
};

export interface FormUserPermissions {
retryAllowed: boolean;
resumeAllowed: boolean;
}
5 changes: 4 additions & 1 deletion packages/orchestrator-ui-components/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ReactNode } from 'react';

import { Toast } from '@elastic/eui/src/components/toast/global_toast_list';

import { InputForm } from './forms';
import { FormUserPermissions, InputForm } from './forms';

export type Nullable<T> = T | null;

Expand Down Expand Up @@ -198,6 +198,7 @@ export interface ProcessDetail {
isTask: boolean;
steps: Step[];
traceback: string | null;
userPermissions: FormUserPermissions;
subscriptions: {
page: {
product: Pick<ProductDefinition, 'name'>;
Expand Down Expand Up @@ -262,6 +263,7 @@ export interface WorkflowDefinition {
description: string;
target: WorkflowTarget;
isTask: boolean;
isAllowed: boolean;
products: Pick<ProductDefinition, 'tag' | 'productId' | 'name'>[];
createdAt: string;
}
Expand Down Expand Up @@ -405,6 +407,7 @@ export type StartComboBoxOption = {
productId?: string;
};
label: string;
disabled?: boolean;
};

export interface GraphQlResultPage<T> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ const getProcessDetail = (data: Partial<ProcessDetail> = {}): ProcessDetail => {
workflowName: 'workflowName',
isTask: false,
traceback: null,
userPermissions: {
retryAllowed: true,
resumeAllowed: true,
},
steps: [
{
name: 'step name',
Expand Down
5 changes: 5 additions & 0 deletions version-compatibility.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
[
{
"orchestratorUiVersion": "5.3.0",
"minimumOrchestratorCoreVersion": "4.2.0",
"changes": "Endpoints in BE to support RBAC on individual running workflows."
},
{
"orchestratorUiVersion": "5.0.0",
"minimumOrchestratorCoreVersion": "4.0.0",
Expand Down