From 9ab64db194747dc7d638b988b1510e550a446d34 Mon Sep 17 00:00:00 2001 From: mjcbfl <86734693+mjcbfl@users.noreply.github.com> Date: Wed, 6 Dec 2023 16:39:50 -0330 Subject: [PATCH 1/2] Added File Input Element. --- src/elements/file-input.ts | 44 +++++++++++++++++++++++++ src/elements/index.ts | 16 +++++++++ src/internal/constants/element-types.ts | 1 + src/internal/constants/props.ts | 2 ++ src/internal/dto/slack-dto.ts | 2 ++ src/internal/methods/set-methods.ts | 32 ++++++++++++++++++ src/internal/types/index.ts | 4 ++- tests/elements/file-input.spec.ts | 23 +++++++++++++ tests/elements/mocks/file-input.mock.ts | 9 +++++ tests/elements/mocks/index.ts | 1 + tests/methods/filetypes.ts | 19 +++++++++++ tests/methods/index.ts | 2 ++ tests/methods/max-files.ts | 18 ++++++++++ tests/mocks/method-arg-mocks.ts | 2 ++ 14 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/elements/file-input.ts create mode 100644 tests/elements/file-input.spec.ts create mode 100644 tests/elements/mocks/file-input.mock.ts create mode 100644 tests/methods/filetypes.ts create mode 100644 tests/methods/max-files.ts diff --git a/src/elements/file-input.ts b/src/elements/file-input.ts new file mode 100644 index 0000000..9505307 --- /dev/null +++ b/src/elements/file-input.ts @@ -0,0 +1,44 @@ +import { ElementBuilderBase } from '../internal/base'; +import { ElementType } from '../internal/constants'; +import { SlackElementDto } from '../internal/dto'; +import { applyMixins } from '../internal/helpers'; +import { + ActionId, + Filetypes, + MaxFiles, + End, +} from '../internal/methods'; + +export interface FileInputParams { + actionId?: string; + filetypes?: string[]; + maxFiles?: number; +} + +export interface FileInputBuilder extends ActionId, + Filetypes, + MaxFiles, + End { +} + +/** + * @@link https://api.slack.com/reference/block-kit/block-elements#file_input + * @@displayName File Input Builder + */ + +export class FileInputBuilder extends ElementBuilderBase { + /** @internal */ + + public build(): Readonly { + return this.getResult(SlackElementDto, { + type: ElementType.FileInput, + }); + } +} + +applyMixins(FileInputBuilder, [ + ActionId, + Filetypes, + MaxFiles, + End, +]); diff --git a/src/elements/index.ts b/src/elements/index.ts index ab6158a..79e210e 100644 --- a/src/elements/index.ts +++ b/src/elements/index.ts @@ -22,6 +22,7 @@ import { TimePickerBuilder, TimePickerParams } from './timepicker'; import { URLInputBuilder, URLInputParams } from './url-input'; import { UserMultiSelectBuilder, UserMultiSelectParams } from './user-multi-select'; import { UserSelectBuilder, UserSelectParams } from './user-select'; +import { FileInputBuilder, FileInputParams } from './file-input'; export type { ButtonBuilder, @@ -68,6 +69,8 @@ export type { UserMultiSelectParams, UserSelectBuilder, UserSelectParams, + FileInputBuilder, + FileInputParams, }; /** @@ -229,6 +232,18 @@ export function Img(params?: ImgParams): ImgBuilder { return new ImgBuilder(params); } +/** + * @param {Object} [params] Parameters passed to the constructor. + * @param {string} [params.filetypes] Sets the accepted filetypes. + * @param {string} [params.maxFiles] Sets the maximum number of files to upload. + * + * {@link https://api.slack.com/reference/block-kit/block-elements#file_input|View in Slack API Documentation} + */ + +export function FileInput(params?: FileInputParams): FileInputBuilder { + return new FileInputBuilder(params); +} + /** * @param {Object} [params] Parameters passed to the constructor. * @param {string} [params.actionId] Sets a string to be an identifier for the source of an action in interaction payloads. @@ -382,6 +397,7 @@ const elements = { URLInput, UserMultiSelect, UserSelect, + FileInput, }; // Strange export. I know. For IDE highlighting purposes. diff --git a/src/internal/constants/element-types.ts b/src/internal/constants/element-types.ts index b26f7a2..e3db341 100644 --- a/src/internal/constants/element-types.ts +++ b/src/internal/constants/element-types.ts @@ -21,4 +21,5 @@ export enum ElementType { URLInput = 'url_text_input', EmailInput = 'email_text_input', NumberInput = 'number_input', + FileInput = 'file_input', } diff --git a/src/internal/constants/props.ts b/src/internal/constants/props.ts index 2b27d2a..f31343c 100644 --- a/src/internal/constants/props.ts +++ b/src/internal/constants/props.ts @@ -87,4 +87,6 @@ export enum Prop { TitleUrl = 'titleUrl', ThumbnailUrl = 'thumbnailUrl', VideoUrl = 'videoUrl', + MaxFiles = 'maxFiles', + Filetypes = 'filetypes', } diff --git a/src/internal/dto/slack-dto.ts b/src/internal/dto/slack-dto.ts index 1ad5902..4f5ee6a 100644 --- a/src/internal/dto/slack-dto.ts +++ b/src/internal/dto/slack-dto.ts @@ -85,6 +85,8 @@ export enum Param { videoUrl = 'video_url', minValue = 'min_value', maxValue = 'max_value', + maxFiles = 'max_files', + filetypes = 'filetypes', } export class SlackDto implements ObjectLiteral { diff --git a/src/internal/methods/set-methods.ts b/src/internal/methods/set-methods.ts index c40e680..3c7bbf1 100644 --- a/src/internal/methods/set-methods.ts +++ b/src/internal/methods/set-methods.ts @@ -769,3 +769,35 @@ export abstract class VideoUrl extends Builder { return this.set(videoUrl, Prop.VideoUrl); } } + +export abstract class MaxFiles extends Builder { + /** + * @description Maximum number of files that can be uploaded for this file_input element. Minimum of 1, maximum of 10. Defaults to 10 if not specified. + * + * {@link https://api.slack.com/block-kit|Open Official Slack Block Kit Documentation} + * {@link https://www.blockbuilder.dev|Open Block Builder Documentation} + */ + + public maxFiles(maxFiles:Settable = 10): this { + return this.set(maxFiles, Prop.MaxFiles); + } +} + +export abstract class Filetypes extends Builder { + /** + * @description An array of valid file extensions that will be accepted for this element. All file extensions will be accepted if filetypes is not specified. + * + * **Slack Validation Rules and Tips:** + * * **Required if the text property is undefined** ⚠ + * * Maximum of 10 items. + * * Maximum of 2000 characters for each field. + * * Markdown supported. + * + * {@link https://api.slack.com/block-kit|Open Official Slack Block Kit Documentation} + * {@link https://www.blockbuilder.dev|Open Block Builder Documentation} + */ + + public filetypes(filetypes:Settable = []): this { + return this.set(filetypes.flat(), Prop.Filetypes); + } +} diff --git a/src/internal/types/index.ts b/src/internal/types/index.ts index da31abe..248acfb 100644 --- a/src/internal/types/index.ts +++ b/src/internal/types/index.ts @@ -8,6 +8,7 @@ import type { DatePickerBuilder, DateTimePickerBuilder, ExternalMultiSelectBuilder, ExternalSelectBuilder, + FileInputBuilder, ImgBuilder, OverflowMenuBuilder, RadioButtonsBuilder, @@ -83,7 +84,8 @@ export type InputElementBuilder = | TimePickerBuilder | URLInputBuilder | UserMultiSelectBuilder - | UserSelectBuilder; + | UserSelectBuilder + | FileInputBuilder; export type ContextElement = ImgBuilder | string; diff --git a/tests/elements/file-input.spec.ts b/tests/elements/file-input.spec.ts new file mode 100644 index 0000000..da094b6 --- /dev/null +++ b/tests/elements/file-input.spec.ts @@ -0,0 +1,23 @@ +import { FileInputBuilder as Class } from '../../src/elements/file-input'; +import { SlackElementDto as DtoClass } from '../../src/internal'; +import { params } from './mocks/file-input.mock'; +import * as methods from '../methods'; +import { testCompositeBuilderClass } from '../test-composite-builder-class'; + +const className = 'FileInput'; +const category = 'Elements'; + +const config = { + Class, + DtoClass, + params, + className, + category, +}; + +const methodsConfig = [ + methods.filetypes, + methods.maxFiles, +]; + +testCompositeBuilderClass({ config, methods: methodsConfig }); diff --git a/tests/elements/mocks/file-input.mock.ts b/tests/elements/mocks/file-input.mock.ts new file mode 100644 index 0000000..af23761 --- /dev/null +++ b/tests/elements/mocks/file-input.mock.ts @@ -0,0 +1,9 @@ +import { FileInputBuilder } from '../../../src/elements/file-input'; + +export const params = { + actionId: 'actionId', + filetypes: 'filetypes', + maxFiles: 'maxFiles', +}; + +export const mock = new FileInputBuilder(params); diff --git a/tests/elements/mocks/index.ts b/tests/elements/mocks/index.ts index 1bece24..f67d3b9 100644 --- a/tests/elements/mocks/index.ts +++ b/tests/elements/mocks/index.ts @@ -20,3 +20,4 @@ export * as TimePicker from './time-picker.mock'; export * as URLInput from './url-input.mock'; export * as UserMultiSelect from './user-multiselect.mock'; export * as UserSelect from './user-select.mock'; +export * as FileInput from './file-input.mock'; \ No newline at end of file diff --git a/tests/methods/filetypes.ts b/tests/methods/filetypes.ts new file mode 100644 index 0000000..439ebaf --- /dev/null +++ b/tests/methods/filetypes.ts @@ -0,0 +1,19 @@ +import { CompositeBuilderClassConfig } from '../test-config-types'; +import { Prop } from '../../src/internal/constants'; +import { methodArgMocks } from '../mocks/method-arg-mocks'; +import { SlackDto } from '../../src/internal'; +import * as checks from '../checks'; + +export const filetypes = (params: CompositeBuilderClassConfig): void => { + const config = { + ...params, + methodArgMock: methodArgMocks.filetypes, + methodName: Prop.Filetypes, + propSetterPropName: Prop.Filetypes, + slackDtoParamName: SlackDto.mapParam(Prop.Filetypes), + expectArray: true, + }; + + checks.settableProperty(config); + checks.literalBuild(config); +}; diff --git a/tests/methods/index.ts b/tests/methods/index.ts index 5565f78..44bb464 100644 --- a/tests/methods/index.ts +++ b/tests/methods/index.ts @@ -82,3 +82,5 @@ export * from './ts'; export * from './url'; export * from './value'; export * from './video-url'; +export * from './max-files'; +export * from './filetypes'; diff --git a/tests/methods/max-files.ts b/tests/methods/max-files.ts new file mode 100644 index 0000000..1abd979 --- /dev/null +++ b/tests/methods/max-files.ts @@ -0,0 +1,18 @@ +import { CompositeBuilderClassConfig } from '../test-config-types'; +import { Prop } from '../../src/internal/constants'; +import { methodArgMocks } from '../mocks/method-arg-mocks'; +import { SlackDto } from '../../src/internal'; +import * as checks from '../checks'; + +export const maxFiles = (params: CompositeBuilderClassConfig): void => { + const config = { + ...params, + methodArgMock: methodArgMocks.maxFiles, + methodName: Prop.MaxFiles, + propSetterPropName: Prop.MaxFiles, + slackDtoParamName: SlackDto.mapParam(Prop.MaxFiles), + }; + + checks.settableProperty(config); + checks.literalBuild(config); +}; diff --git a/tests/mocks/method-arg-mocks.ts b/tests/mocks/method-arg-mocks.ts index 6fda7bf..e5b42eb 100644 --- a/tests/mocks/method-arg-mocks.ts +++ b/tests/mocks/method-arg-mocks.ts @@ -85,4 +85,6 @@ export const methodArgMocks = { titleUrl: methodArgMocksByType.string, thumbnailUrl: methodArgMocksByType.string, videoUrl: methodArgMocksByType.string, + maxFiles: methodArgMocksByType.int, + filetypes: methodArgMocksByType.arrayStrings, }; From 87be022d0ba1cbbca1b282957aa616ad476e2cc0 Mon Sep 17 00:00:00 2001 From: Michael Budgell Date: Tue, 19 Dec 2023 13:50:58 -0330 Subject: [PATCH 2/2] Fixed to comply wint linter. --- tests/elements/mocks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/elements/mocks/index.ts b/tests/elements/mocks/index.ts index f67d3b9..fbce905 100644 --- a/tests/elements/mocks/index.ts +++ b/tests/elements/mocks/index.ts @@ -20,4 +20,4 @@ export * as TimePicker from './time-picker.mock'; export * as URLInput from './url-input.mock'; export * as UserMultiSelect from './user-multiselect.mock'; export * as UserSelect from './user-select.mock'; -export * as FileInput from './file-input.mock'; \ No newline at end of file +export * as FileInput from './file-input.mock';