@@ -6,39 +6,63 @@
|
||||
/// <reference types="react" />
|
||||
|
||||
import { ApiHolder } from '@backstage/core-plugin-api';
|
||||
import { CustomFieldExtensionSchema } from '@backstage/plugin-scaffolder-react';
|
||||
import { ComponentType } from 'react';
|
||||
import { CustomValidator } from '@rjsf/utils';
|
||||
import { Dispatch } from 'react';
|
||||
import { ElementType } from 'react';
|
||||
import { ErrorSchema } from '@rjsf/utils';
|
||||
import { ErrorTransformer } from '@rjsf/utils';
|
||||
import { Experimental_DefaultFormStateBehavior } from '@rjsf/utils';
|
||||
import { Extension } from '@backstage/core-plugin-api';
|
||||
import { FieldExtensionComponent } from '@backstage/plugin-scaffolder-react';
|
||||
import { FieldProps } from '@rjsf/utils';
|
||||
import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react';
|
||||
import { FieldProps } from '@rjsf/core';
|
||||
import { FieldValidation } from '@rjsf/utils';
|
||||
import { FormProps as FormProps_2 } from '@rjsf/core-v5';
|
||||
import { FieldValidation as FieldValidation_2 } from '@rjsf/core';
|
||||
import { default as Form_2 } from '@rjsf/core-v5';
|
||||
import { FormContextType } from '@rjsf/utils';
|
||||
import { FormEvent } from 'react';
|
||||
import { FormProps } from '@backstage/plugin-scaffolder-react';
|
||||
import { GenericObjectType } from '@rjsf/utils';
|
||||
import { HTMLAttributes } from 'react';
|
||||
import { IChangeEvent } from '@rjsf/core-v5';
|
||||
import { IconComponent } from '@backstage/core-plugin-api';
|
||||
import { IdSchema } from '@rjsf/utils';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { LayoutOptions } from '@backstage/plugin-scaffolder-react';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import { default as React_2 } from 'react';
|
||||
import { ReactElement } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { Ref } from 'react';
|
||||
import { Registry } from '@rjsf/utils';
|
||||
import { RegistryWidgetsType } from '@rjsf/utils';
|
||||
import { ReviewStepProps } from '@backstage/plugin-scaffolder-react';
|
||||
import { RJSFSchema } from '@rjsf/utils';
|
||||
import { RJSFValidationError } from '@rjsf/utils';
|
||||
import { ScaffolderStep } from '@backstage/plugin-scaffolder-react';
|
||||
import { ScaffolderTaskOutput } from '@backstage/plugin-scaffolder-react';
|
||||
import { SetStateAction } from 'react';
|
||||
import { StrictRJSFSchema } from '@rjsf/utils';
|
||||
import { TaskStep } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react';
|
||||
import { UIOptionsType } from '@rjsf/utils';
|
||||
import { TemplatesType } from '@rjsf/utils';
|
||||
import { UiSchema } from '@rjsf/utils';
|
||||
import { ValidatorType } from '@rjsf/utils';
|
||||
|
||||
// @alpha
|
||||
export const createFieldValidation: () => FieldValidation;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "FieldExtensionComponent" needs to be exported by the entry point alpha.d.ts
|
||||
//
|
||||
// @alpha
|
||||
export function createNextScaffolderFieldExtension<
|
||||
export function createLegacyScaffolderFieldExtension<
|
||||
TReturnValue = unknown,
|
||||
TInputProps extends UIOptionsType = {},
|
||||
TInputProps = unknown,
|
||||
>(
|
||||
options: NextFieldExtensionOptions<TReturnValue, TInputProps>,
|
||||
options: LegacyFieldExtensionOptions<TReturnValue, TInputProps>,
|
||||
): Extension<FieldExtensionComponent<TReturnValue, TInputProps>>;
|
||||
|
||||
// @alpha
|
||||
@@ -55,61 +79,46 @@ export const extractSchemaFromStep: (inputStep: JsonObject) => {
|
||||
schema: JsonObject;
|
||||
};
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "ScaffolderRJSFFormProps" needs to be exported by the entry point alpha.d.ts
|
||||
//
|
||||
// @alpha
|
||||
export const Form: (
|
||||
props: PropsWithChildren<FormProps_2>,
|
||||
props: PropsWithChildren<ScaffolderRJSFFormProps>,
|
||||
) => React_2.JSX.Element;
|
||||
|
||||
// @alpha
|
||||
export type FormProps = Pick<
|
||||
FormProps_2,
|
||||
'transformErrors' | 'noHtml5Validate'
|
||||
>;
|
||||
|
||||
// @alpha
|
||||
export type NextCustomFieldValidator<
|
||||
TFieldReturnValue,
|
||||
TUiOptions = unknown,
|
||||
> = (
|
||||
export type LegacyCustomFieldValidator<TFieldReturnValue> = (
|
||||
data: TFieldReturnValue,
|
||||
field: FieldValidation,
|
||||
field: FieldValidation_2,
|
||||
context: {
|
||||
apiHolder: ApiHolder;
|
||||
formData: JsonObject;
|
||||
schema: JsonObject;
|
||||
uiSchema?: NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
|
||||
},
|
||||
) => void | Promise<void>;
|
||||
|
||||
// @alpha
|
||||
export interface NextFieldExtensionComponentProps<
|
||||
export interface LegacyFieldExtensionComponentProps<
|
||||
TFieldReturnValue,
|
||||
TUiOptions = {},
|
||||
> extends PropsWithChildren<FieldProps<TFieldReturnValue>> {
|
||||
TUiOptions = unknown,
|
||||
> extends FieldProps<TFieldReturnValue> {
|
||||
// (undocumented)
|
||||
uiSchema?: NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
|
||||
uiSchema: FieldProps['uiSchema'] & {
|
||||
'ui:options'?: TUiOptions;
|
||||
};
|
||||
}
|
||||
|
||||
// @alpha
|
||||
export type NextFieldExtensionOptions<
|
||||
export type LegacyFieldExtensionOptions<
|
||||
TFieldReturnValue = unknown,
|
||||
TUiOptions = unknown,
|
||||
TInputProps = unknown,
|
||||
> = {
|
||||
name: string;
|
||||
component: (
|
||||
props: NextFieldExtensionComponentProps<TFieldReturnValue, TUiOptions>,
|
||||
props: LegacyFieldExtensionComponentProps<TFieldReturnValue, TInputProps>,
|
||||
) => JSX.Element | null;
|
||||
validation?: NextCustomFieldValidator<TFieldReturnValue, TUiOptions>;
|
||||
validation?: LegacyCustomFieldValidator<TFieldReturnValue>;
|
||||
schema?: CustomFieldExtensionSchema;
|
||||
};
|
||||
|
||||
// @alpha
|
||||
export interface NextFieldExtensionUiSchema<TFieldReturnValue, TUiOptions>
|
||||
extends UiSchema<TFieldReturnValue> {
|
||||
// (undocumented)
|
||||
'ui:options'?: TUiOptions & UIOptionsType;
|
||||
}
|
||||
|
||||
// @alpha
|
||||
export interface ParsedTemplateSchema {
|
||||
// (undocumented)
|
||||
@@ -176,12 +185,13 @@ export const Stepper: (stepperProps: StepperProps) => React_2.JSX.Element;
|
||||
// @alpha
|
||||
export type StepperProps = {
|
||||
manifest: TemplateParameterSchema;
|
||||
extensions: NextFieldExtensionOptions<any, any>[];
|
||||
extensions: FieldExtensionOptions<any, any>[];
|
||||
templateName?: string;
|
||||
FormProps?: FormProps;
|
||||
formProps?: FormProps;
|
||||
initialState?: Record<string, JsonValue>;
|
||||
onCreate: (values: Record<string, JsonValue>) => Promise<void>;
|
||||
components?: {
|
||||
ReviewStepComponent?: ComponentType<ReviewStepProps>;
|
||||
ReviewStateComponent?: (props: ReviewStateProps) => JSX.Element;
|
||||
createButtonText?: ReactNode;
|
||||
reviewButtonText?: ReactNode;
|
||||
@@ -236,12 +246,6 @@ export const TemplateGroup: (
|
||||
props: TemplateGroupProps,
|
||||
) => React_2.JSX.Element | null;
|
||||
|
||||
// @alpha (undocumented)
|
||||
export type TemplateGroupFilter = {
|
||||
title?: React_2.ReactNode;
|
||||
filter: (entity: TemplateEntityV1beta3) => boolean;
|
||||
};
|
||||
|
||||
// @alpha
|
||||
export interface TemplateGroupProps {
|
||||
// (undocumented)
|
||||
@@ -276,6 +280,8 @@ export interface TemplateGroupsProps {
|
||||
text: string;
|
||||
url: string;
|
||||
}[];
|
||||
// Warning: (ae-forgotten-export) The symbol "TemplateGroupFilter" needs to be exported by the entry point alpha.d.ts
|
||||
//
|
||||
// (undocumented)
|
||||
groups: TemplateGroupFilter[];
|
||||
// (undocumented)
|
||||
@@ -314,16 +320,24 @@ export type WorkflowProps = {
|
||||
description?: string;
|
||||
namespace: string;
|
||||
templateName: string;
|
||||
components?: {
|
||||
ReviewStepComponent?: React_2.ComponentType<ReviewStepProps_2>;
|
||||
};
|
||||
onError(error: Error | undefined): JSX.Element | null;
|
||||
} & Pick<
|
||||
StepperProps,
|
||||
| 'extensions'
|
||||
| 'FormProps'
|
||||
| 'formProps'
|
||||
| 'components'
|
||||
| 'onCreate'
|
||||
| 'initialState'
|
||||
| 'layouts'
|
||||
>;
|
||||
|
||||
// Warnings were encountered during analysis:
|
||||
//
|
||||
// src/legacy/extensions/types.d.ts:23:5 - (ae-forgotten-export) The symbol "CustomFieldExtensionSchema" needs to be exported by the entry point alpha.d.ts
|
||||
// src/next/components/Workflow/Workflow.d.ts:13:9 - (ae-forgotten-export) The symbol "ReviewStepProps_2" needs to be exported by the entry point alpha.d.ts
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -7,18 +7,42 @@
|
||||
|
||||
import { ApiHolder } from '@backstage/core-plugin-api';
|
||||
import { ApiRef } from '@backstage/core-plugin-api';
|
||||
import { ComponentType } from 'react';
|
||||
import { CustomValidator } from '@rjsf/utils';
|
||||
import { ElementType } from 'react';
|
||||
import { ErrorSchema } from '@rjsf/utils';
|
||||
import { ErrorTransformer } from '@rjsf/utils';
|
||||
import { Experimental_DefaultFormStateBehavior } from '@rjsf/utils';
|
||||
import { Extension } from '@backstage/core-plugin-api';
|
||||
import { FieldProps } from '@rjsf/core';
|
||||
import { FieldValidation } from '@rjsf/core';
|
||||
import type { FormProps } from '@rjsf/core-v5';
|
||||
import { FieldValidation } from '@rjsf/utils';
|
||||
import Form from '@rjsf/core-v5';
|
||||
import { FormContextType } from '@rjsf/utils';
|
||||
import { FormEvent } from 'react';
|
||||
import type { FormProps as FormProps_2 } from '@rjsf/core-v5';
|
||||
import { GenericObjectType } from '@rjsf/utils';
|
||||
import { HTMLAttributes } from 'react';
|
||||
import { IChangeEvent } from '@rjsf/core-v5';
|
||||
import { IdSchema } from '@rjsf/utils';
|
||||
import { JsonObject } from '@backstage/types';
|
||||
import { JSONSchema7 } from 'json-schema';
|
||||
import { JsonValue } from '@backstage/types';
|
||||
import { Observable } from '@backstage/types';
|
||||
import { PropsWithChildren } from 'react';
|
||||
import { default as React_2 } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { Ref } from 'react';
|
||||
import { Registry } from '@rjsf/utils';
|
||||
import { RegistryWidgetsType } from '@rjsf/utils';
|
||||
import { RJSFSchema } from '@rjsf/utils';
|
||||
import { RJSFValidationError } from '@rjsf/utils';
|
||||
import { StrictRJSFSchema } from '@rjsf/utils';
|
||||
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
|
||||
import { TaskStep } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
|
||||
import { TemplatesType } from '@rjsf/utils';
|
||||
import { UIOptionsType } from '@rjsf/utils';
|
||||
import { UiSchema } from '@rjsf/utils';
|
||||
import { ValidatorType } from '@rjsf/utils';
|
||||
|
||||
// @public
|
||||
export type Action = {
|
||||
@@ -40,7 +64,7 @@ export type ActionExample = {
|
||||
// @public
|
||||
export function createScaffolderFieldExtension<
|
||||
TReturnValue = unknown,
|
||||
TInputProps = unknown,
|
||||
TInputProps extends UIOptionsType = {},
|
||||
>(
|
||||
options: FieldExtensionOptions<TReturnValue, TInputProps>,
|
||||
): Extension<FieldExtensionComponent<TReturnValue, TInputProps>>;
|
||||
@@ -57,11 +81,14 @@ export type CustomFieldExtensionSchema = {
|
||||
};
|
||||
|
||||
// @public
|
||||
export type CustomFieldValidator<TFieldReturnValue> = (
|
||||
export type CustomFieldValidator<TFieldReturnValue, TUiOptions = unknown> = (
|
||||
data: TFieldReturnValue,
|
||||
field: FieldValidation,
|
||||
context: {
|
||||
apiHolder: ApiHolder;
|
||||
formData: JsonObject;
|
||||
schema: JsonObject;
|
||||
uiSchema?: FieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
|
||||
},
|
||||
) => void | Promise<void>;
|
||||
|
||||
@@ -71,27 +98,38 @@ export type FieldExtensionComponent<_TReturnValue, _TInputProps> = () => null;
|
||||
// @public
|
||||
export interface FieldExtensionComponentProps<
|
||||
TFieldReturnValue,
|
||||
TUiOptions = unknown,
|
||||
> extends FieldProps<TFieldReturnValue> {
|
||||
TUiOptions = {},
|
||||
> extends PropsWithChildren<ScaffolderRJSFFieldProps<TFieldReturnValue>> {
|
||||
// (undocumented)
|
||||
uiSchema: FieldProps['uiSchema'] & {
|
||||
'ui:options'?: TUiOptions;
|
||||
};
|
||||
uiSchema: FieldExtensionUiSchema<TFieldReturnValue, TUiOptions>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type FieldExtensionOptions<
|
||||
TFieldReturnValue = unknown,
|
||||
TInputProps = unknown,
|
||||
TUiOptions = unknown,
|
||||
> = {
|
||||
name: string;
|
||||
component: (
|
||||
props: FieldExtensionComponentProps<TFieldReturnValue, TInputProps>,
|
||||
props: FieldExtensionComponentProps<TFieldReturnValue, TUiOptions>,
|
||||
) => JSX.Element | null;
|
||||
validation?: CustomFieldValidator<TFieldReturnValue>;
|
||||
validation?: CustomFieldValidator<TFieldReturnValue, TUiOptions>;
|
||||
schema?: CustomFieldExtensionSchema;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface FieldExtensionUiSchema<TFieldReturnValue, TUiOptions>
|
||||
extends UiSchema<TFieldReturnValue> {
|
||||
// (undocumented)
|
||||
'ui:options'?: TUiOptions & UIOptionsType<TFieldReturnValue>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type FormProps = Pick<
|
||||
FormProps_2,
|
||||
'transformErrors' | 'noHtml5Validate'
|
||||
>;
|
||||
|
||||
// @public
|
||||
export type LayoutComponent<_TInputProps> = () => null;
|
||||
|
||||
@@ -105,7 +143,7 @@ export interface LayoutOptions<P = any> {
|
||||
|
||||
// @public
|
||||
export type LayoutTemplate<T = any> = NonNullable<
|
||||
FormProps<T>['uiSchema']
|
||||
FormProps_2<T>['uiSchema']
|
||||
>['ui:ObjectFieldTemplate'];
|
||||
|
||||
// @public
|
||||
@@ -124,6 +162,20 @@ export type LogEvent = {
|
||||
taskId: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type ReviewStepProps = {
|
||||
disableButtons: boolean;
|
||||
formData: JsonObject;
|
||||
handleBack: () => void;
|
||||
handleReset: () => void;
|
||||
handleCreate: () => void;
|
||||
steps: {
|
||||
uiSchema: UiSchema;
|
||||
mergedSchema: JsonObject;
|
||||
schema: JsonObject;
|
||||
}[];
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface ScaffolderApi {
|
||||
cancelTask(taskId: string): Promise<void>;
|
||||
@@ -186,8 +238,8 @@ export interface ScaffolderDryRunResponse {
|
||||
}
|
||||
|
||||
// @public
|
||||
export const ScaffolderFieldExtensions: React_2.ComponentType<
|
||||
React_2.PropsWithChildren<{}>
|
||||
export const ScaffolderFieldExtensions: React.ComponentType<
|
||||
React.PropsWithChildren<{}>
|
||||
>;
|
||||
|
||||
// @public
|
||||
@@ -226,6 +278,113 @@ export type ScaffolderOutputText = {
|
||||
content?: string;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type ScaffolderRJSFField<
|
||||
T = any,
|
||||
S extends StrictRJSFSchema = RJSFSchema,
|
||||
F extends FormContextType = any,
|
||||
> = ComponentType<ScaffolderRJSFFieldProps<T, S, F>>;
|
||||
|
||||
// @public
|
||||
export interface ScaffolderRJSFFieldProps<
|
||||
T = any,
|
||||
S extends StrictRJSFSchema = RJSFSchema,
|
||||
F extends FormContextType = any,
|
||||
> extends GenericObjectType,
|
||||
Pick<
|
||||
HTMLAttributes<HTMLElement>,
|
||||
Exclude<
|
||||
keyof HTMLAttributes<HTMLElement>,
|
||||
'onBlur' | 'onFocus' | 'onChange'
|
||||
>
|
||||
> {
|
||||
autofocus?: boolean;
|
||||
disabled: boolean;
|
||||
errorSchema?: ErrorSchema<T>;
|
||||
formContext?: F;
|
||||
formData: T;
|
||||
hideError?: boolean;
|
||||
idPrefix?: string;
|
||||
idSchema: IdSchema<T>;
|
||||
idSeparator?: string;
|
||||
name: string;
|
||||
onBlur: (id: string, value: any) => void;
|
||||
onChange: (
|
||||
newFormData: T | undefined,
|
||||
es?: ErrorSchema<T>,
|
||||
id?: string,
|
||||
) => any;
|
||||
onFocus: (id: string, value: any) => void;
|
||||
rawErrors: string[];
|
||||
readonly: boolean;
|
||||
registry: Registry<T, S, F>;
|
||||
required?: boolean;
|
||||
schema: S;
|
||||
uiSchema: UiSchema<T, S, F>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface ScaffolderRJSFFormProps<
|
||||
T = any,
|
||||
S extends StrictRJSFSchema = RJSFSchema,
|
||||
F extends FormContextType = any,
|
||||
> {
|
||||
acceptcharset?: string;
|
||||
action?: string;
|
||||
autoComplete?: string;
|
||||
children?: ReactNode;
|
||||
className?: string;
|
||||
customValidate?: CustomValidator<T, S, F>;
|
||||
disabled?: boolean;
|
||||
enctype?: string;
|
||||
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior;
|
||||
extraErrors?: ErrorSchema<T>;
|
||||
fields?: ScaffolderRJSFRegistryFieldsType<T, S, F>;
|
||||
focusOnFirstError?: boolean | ((error: RJSFValidationError) => void);
|
||||
formContext?: F;
|
||||
formData?: T;
|
||||
id?: string;
|
||||
idPrefix?: string;
|
||||
idSeparator?: string;
|
||||
_internalFormWrapper?: ElementType;
|
||||
liveOmit?: boolean;
|
||||
liveValidate?: boolean;
|
||||
method?: string;
|
||||
name?: string;
|
||||
noHtml5Validate?: boolean;
|
||||
// @deprecated
|
||||
noValidate?: boolean;
|
||||
omitExtraData?: boolean;
|
||||
onBlur?: (id: string, data: any) => void;
|
||||
onChange?: (data: IChangeEvent<T, S, F>, id?: string) => void;
|
||||
onError?: (errors: RJSFValidationError[]) => void;
|
||||
onFocus?: (id: string, data: any) => void;
|
||||
onSubmit?: (data: IChangeEvent<T, S, F>, event: FormEvent<any>) => void;
|
||||
readonly?: boolean;
|
||||
ref?: Ref<Form<T, S, F>>;
|
||||
schema: S;
|
||||
showErrorList?: false | 'top' | 'bottom';
|
||||
tagName?: ElementType;
|
||||
target?: string;
|
||||
templates?: Partial<Omit<TemplatesType<T, S, F>, 'ButtonTemplates'>> & {
|
||||
ButtonTemplates?: Partial<TemplatesType<T, S, F>['ButtonTemplates']>;
|
||||
};
|
||||
transformErrors?: ErrorTransformer<T, S, F>;
|
||||
translateString?: Registry['translateString'];
|
||||
uiSchema?: UiSchema<T, S, F>;
|
||||
validator: ValidatorType<T, S, F>;
|
||||
widgets?: RegistryWidgetsType<T, S, F>;
|
||||
}
|
||||
|
||||
// @public
|
||||
export type ScaffolderRJSFRegistryFieldsType<
|
||||
T = any,
|
||||
S extends StrictRJSFSchema = RJSFSchema,
|
||||
F extends FormContextType = any,
|
||||
> = {
|
||||
[name: string]: ScaffolderRJSFField<T, S, F>;
|
||||
};
|
||||
|
||||
// @public
|
||||
export interface ScaffolderScaffoldOptions {
|
||||
// (undocumented)
|
||||
@@ -313,6 +472,12 @@ export type TaskStream = {
|
||||
output?: ScaffolderTaskOutput;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type TemplateGroupFilter = {
|
||||
title?: React.ReactNode;
|
||||
filter: (entity: TemplateEntityV1beta3) => boolean;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type TemplateParameterSchema = {
|
||||
title: string;
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
* Copyright 2023 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Reference in New Issue
Block a user