From 81a313d717b374e07b632ba366bf4c2a6a385010 Mon Sep 17 00:00:00 2001 From: anobaka Date: Tue, 10 Sep 2024 23:13:42 +0800 Subject: [PATCH] fix #554; fix #555; resolve #548; update docs for v1.9.0-beta3; --- docs/CHANGELOG.md | 13 +- docs/README.md | 2 +- .../Controllers/EnhancementController.cs | 13 +- .../components/EnhancerSelectorV2/index.tsx | 264 ++++++++++-------- .../components/ResourceCover/index.tsx | 2 +- src/ClientApp/src/localization/cn.json | 4 +- .../Resource/components/FilterPanel/index.tsx | 1 + src/ClientApp/src/sdk/Api.ts | 17 ++ src/ClientApp/src/sdk/apis.js | 45 +++ src/ClientApp/src/sdk/constants.ts | 52 ++-- 10 files changed, 267 insertions(+), 146 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f5dfed82..c1b26992 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,14 +1,21 @@ -## [1.9.0-beta3](https://cdn-public.anobaka.com/app/bakabase/inside-world/1.9.0-beta3/installer/Bakabase.InsideWorld.zip) (2024-09-06) +## [1.9.0-beta3](https://cdn-public.anobaka.com/app/bakabase/inside-world/1.9.0-beta3/installer/Bakabase.InsideWorld.zip) (2024-09-10) ### Features -* 在配置媒体库路径信息时,允许将正则表达式应用至资源文件(夹)名 ([#547](https://github.com/anobaka/InsideWorld/issues/547)) -* 选择属性框调整为三个维度:内置、预置和自定义,允许将增强目标绑定至预置属性 ([#546](https://github.com/anobaka/InsideWorld/issues/546)) * 打开属性选择框时,如果没有已选属性,则默认切换至未选择列表 ([#545](https://github.com/anobaka/InsideWorld/issues/545)) +* 选择属性框调整为三个维度:内置、预置和自定义,允许将增强目标绑定至预置属性 ([#546](https://github.com/anobaka/InsideWorld/issues/546)) +* 在配置媒体库路径信息时,允许将正则表达式应用至资源文件(夹)名 ([#547](https://github.com/anobaka/InsideWorld/issues/547)) +* 增加根据分类和增强器删除增强记录的功能 ([#548](https://github.com/anobaka/InsideWorld/issues/548)) +* 在增强器增强目标中配置默认预置属性,在自动绑定属性启用时尝试匹配预置属性 ([#550](https://github.com/anobaka/InsideWorld/issues/550)) +* 增加属性转换测试功能 ([#552](https://github.com/anobaka/InsideWorld/issues/552)) ### Bug Fixes * 手动编辑动态增强目标时,增强名称没有实时更新 ([#544](https://github.com/anobaka/InsideWorld/issues/544)) +* 属性转换时使用了错误的目标属性Descriptor ([#551](https://github.com/anobaka/InsideWorld/issues/551)) +* 基础数据反序列化时未移除转义符 ([#553](https://github.com/anobaka/InsideWorld/issues/553)) +* 关闭资源详情窗口后资源封面显示异常 ([#554](https://github.com/anobaka/InsideWorld/issues/554)) +* 删除筛选条件会导致搜索关键字也被清空 ([#555](https://github.com/anobaka/InsideWorld/issues/555)) ## [1.9.0-beta2](https://cdn-public.anobaka.com/app/bakabase/inside-world/1.9.0-beta2/installer/Bakabase.InsideWorld.zip) (2024-09-05) diff --git a/docs/README.md b/docs/README.md index 15dbc011..10632ea9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,7 +16,7 @@ Inside World 是一款离线媒体管理库,用于本地媒体快速处理、 | 版本 | 发布时间 | 下载地址 | 更新说明 | | ------------- | ------------- | ------------- | ------------- | | [v2.0.0](https://github.com/anobaka/InsideWorld/milestone/51) | 2024 ETA | / | / | -| [v1.9.0-beta3](./CHANGELOG.md) | 2024-09-06 | [下载](https://cdn-public.anobaka.com/app/bakabase/inside-world-dev-test/1.9.0-beta3/installer/Bakabase.zip) | [1.9.0以前的版本升级前必看](/guide/v190/v1.9.0) | +| [v1.9.0-beta3](./CHANGELOG.md) | 2024-09-10 | [下载](https://cdn-public.anobaka.com/app/bakabase/inside-world-dev-test/1.9.0-beta3/installer/Bakabase.zip) | [1.9.0以前的版本升级前必看](/guide/v190/v1.9.0) | | [v1.9.0-beta2](./CHANGELOG.md) | 2024-09-05 | [下载](https://cdn-public.anobaka.com/app/bakabase/inside-world-dev-test/1.9.0-beta2/installer/Bakabase.zip) | [1.9.0以前的版本升级前必看](/guide/v190/v1.9.0) | | [v1.9.0-beta](./CHANGELOG.md) | 2024-08-28 | [下载](https://cdn-public.anobaka.com/app/bakabase/inside-world-dev-test/1.9.0-beta/installer/Bakabase.zip) | [1.9.0以前的版本升级前必看](/guide/v190/v1.9.0) | | [v1.8.2](./CHANGELOG.md) | 2024-08-26 | [下载](https://cdn-public.anobaka.com/app/bakabase/inside-world/1.8.2/installer/Bakabase.InsideWorld.zip) | / | diff --git a/src/Bakabase.Service/Controllers/EnhancementController.cs b/src/Bakabase.Service/Controllers/EnhancementController.cs index 2b6407ad..9046a3ab 100644 --- a/src/Bakabase.Service/Controllers/EnhancementController.cs +++ b/src/Bakabase.Service/Controllers/EnhancementController.cs @@ -108,7 +108,7 @@ public async Task CreateEnhancementForResourceByEnhancer(int resou [HttpDelete("~/media-library/{mediaLibraryId:int}/enhancement")] [SwaggerOperation(OperationId = "DeleteByEnhancementsMediaLibrary")] - public async Task RemoveMediaLibraryEnhancementRecords(int mediaLibraryId) + public async Task DeleteMediaLibraryEnhancementRecords(int mediaLibraryId) { var resourceIds = (await resourceService.GetAll(t => t.MediaLibraryId == mediaLibraryId)) .Select(t => t.Id).ToArray(); @@ -119,7 +119,7 @@ public async Task RemoveMediaLibraryEnhancementRecords(int mediaLi [HttpDelete("~/category/{categoryId:int}/enhancement")] [SwaggerOperation(OperationId = "DeleteEnhancementsByCategory")] - public async Task RemoveCategoryEnhancementRecords(int categoryId) + public async Task DeleteCategoryEnhancementRecords(int categoryId) { var resourceIds = (await resourceService.GetAll(t => t.CategoryId == categoryId)) .Select(t => t.Id).ToArray(); @@ -127,5 +127,14 @@ public async Task RemoveCategoryEnhancementRecords(int categoryId) await enhancementRecordService.DeleteAll(t => resourceIds.Contains(t.ResourceId)); return BaseResponseBuilder.Ok; } + + [HttpDelete("~/enhancer/{enhancerId:int}/enhancement")] + [SwaggerOperation(OperationId = "DeleteEnhancementsByEnhancer")] + public async Task DeleteEnhancerEnhancementRecords(int enhancerId) + { + await enhancementService.RemoveAll(t => t.EnhancerId == enhancerId, true); + await enhancementRecordService.DeleteAll(t => t.EnhancerId == enhancerId); + return BaseResponseBuilder.Ok; + } } } \ No newline at end of file diff --git a/src/ClientApp/src/components/EnhancerSelectorV2/index.tsx b/src/ClientApp/src/components/EnhancerSelectorV2/index.tsx index 8e512b4f..944ecd51 100644 --- a/src/ClientApp/src/components/EnhancerSelectorV2/index.tsx +++ b/src/ClientApp/src/components/EnhancerSelectorV2/index.tsx @@ -1,8 +1,8 @@ -import { useContext, useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { ExclamationCircleOutlined } from '@ant-design/icons'; +import { MoreOutlined } from '@ant-design/icons'; import type { CategoryEnhancerFullOptions } from './components/CategoryEnhancerOptionsDialog/models'; -import { Button, Checkbox, Chip, Divider, Link, Modal, Tooltip } from '@/components/bakaui'; +import { Button, Checkbox, Chip, Divider, Link, Listbox, ListboxItem, Modal, Popover, Tooltip } from '@/components/bakaui'; import { createPortalOfComponent } from '@/components/utils'; import BApi from '@/sdk/BApi'; import type { EnhancerDescriptor } from '@/components/EnhancerSelectorV2/models'; @@ -15,19 +15,25 @@ import type { DestroyableProps } from '@/components/bakaui/types'; import TargetNotSetupTip from '@/components/Enhancer/components/TargetNotSetupTip'; import { EnhancerTargetNotSetupTip } from '@/components/Enhancer'; -interface IProps extends DestroyableProps{ +interface IProps extends DestroyableProps { categoryId: number; onClose?: () => any; } +type Category = { + id: number; + name: string; +}; + const EnhancerSelector = ({ categoryId, onDestroyed, - onClose, -}: IProps) => { + onClose, + }: IProps) => { const { t } = useTranslation(); const { createPortal } = useBakabaseContext(); const [enhancers, setEnhancers] = useState([]); + const [category, setCategory] = useState(); const [categoryEnhancerOptionsList, setCategoryEnhancerOptionsList] = useState([]); const init = async () => { @@ -40,6 +46,7 @@ const EnhancerSelector = ({ // @ts-ignore await BApi.category.getCategory(categoryId, { additionalItems: CategoryAdditionalItem.EnhancerOptions | CategoryAdditionalItem.CustomProperties }).then(r => { const data = r.data || {}; + setCategory({ id: data.id!, name: data.name! }); setCategoryEnhancerOptionsList(data.enhancerOptions?.map(eo => (eo as CategoryEnhancerFullOptions)) || []); }); }; @@ -86,124 +93,157 @@ const EnhancerSelector = ({ style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 300px)' }} > {enhancers.map(e => { - const ceo = categoryEnhancerOptionsList.find(x => x.enhancerId == e.id); - return ( -
-
- {e.name} + const ceo = categoryEnhancerOptionsList.find(x => x.enhancerId == e.id); + return ( +
+
+ {e.name} +
+ {e.description && ( +
+ {e.description}
- {e.description && ( -
- {e.description} -
- )} - -
-
- {t('This enhancer can produce the following property values')} -
-
- {e.targets.map(target => { - return ( - +
+
+ {t('This enhancer can produce the following property values')} +
+
+ {e.targets.map(target => { + return ( + +
{target.description}
-
{target.description}
-
- {t('The value type of this target is')} + {t('The value type of this target is')} +   + +   - - -   - {t(`StandardValueType.${StandardValueType[target.valueType]}`)} - -
+ {t(`StandardValueType.${StandardValueType[target.valueType]}`)} +
- )} - > -
- - - {target.name} -
-
- ); - })} -
+ )} + > +
+ + + {target.name} + +
+ + ); + })}
- -
-
- {/*
+ +
+
+ + + + )} + placement={'top'} + > + { + let title: string; + let callApi: (() => Promise) | undefined; - {/* }, */} - {/* }); */} - {/* }} */} - {/* > */} - {/* {t('Enhance now')} */} - {/* */} -
-
- - - { - BApi.category.patchCategoryEnhancerOptions(categoryId, e.id, { - active: c, - }).then(() => { - patchCategoryEnhancerOptions(e.id, { active: c }); + switch (key) { + case 'Category': + title = t('Delete all enhancement records of this enhancer for category {{categoryName}}', { categoryName: category!.name }); + callApi = async () => await BApi.category.deleteEnhancementsByCategory(category!.id); + break; + case 'All': + title = t('Delete all enhancement records of this enhancer'); + callApi = async () => await BApi.enhancer.deleteEnhancementsByEnhancer(e.id); + break; + default: + return; + } + + createPortal(Modal, { + defaultVisible: true, + title, + onOk: callApi, }); }} > - {t('Enable')} - -
+ + {t('Delete all enhancement records of this enhancer for category {{categoryName}}', { categoryName: category?.name })} + + + {t('Delete all enhancement records of this enhancer')} + + + +
+
+ + + { + BApi.category.patchCategoryEnhancerOptions(categoryId, e.id, { + active: c, + }).then(() => { + patchCategoryEnhancerOptions(e.id, { active: c }); + }); + }} + > + {t('Enable')} +
- ); - })} +
+ ); + })}
); diff --git a/src/ClientApp/src/components/Resource/components/ResourceCover/index.tsx b/src/ClientApp/src/components/Resource/components/ResourceCover/index.tsx index a930adda..692de0ce 100644 --- a/src/ClientApp/src/components/Resource/components/ResourceCover/index.tsx +++ b/src/ClientApp/src/components/Resource/components/ResourceCover/index.tsx @@ -164,7 +164,7 @@ const ResourceCover = React.forwardRef((props: Props, ref) => { } if (refresh) { for (let i = 0; i < urls.length; i++) { - urls[i] += `&v=${uuidv4()}`; + urls[i] += urls[i].includes('?') ? `&v=${uuidv4()}` : `?v=${uuidv4()}`; } } setUrls(urls); diff --git a/src/ClientApp/src/localization/cn.json b/src/ClientApp/src/localization/cn.json index 1895784f..eb487f4c 100644 --- a/src/ClientApp/src/localization/cn.json +++ b/src/ClientApp/src/localization/cn.json @@ -1395,5 +1395,7 @@ "Check type conversion overview": "查看类型转换概览", "Type conversion overview": "类型转换总览", "Type to be converted": "待转换类型", - "Value to be converted": "待转换值" + "Value to be converted": "待转换值", + "Delete all enhancement records of this enhancer for category {{categoryName}}": "删除分类 {{categoryName}} 下所有当前增强器的增强记录", + "Delete all enhancement records of this enhancer": "删除当前增强器的所有增强记录" } diff --git a/src/ClientApp/src/pages/Resource/components/FilterPanel/index.tsx b/src/ClientApp/src/pages/Resource/components/FilterPanel/index.tsx index b45a9a5b..cdf47fa1 100644 --- a/src/ClientApp/src/pages/Resource/components/FilterPanel/index.tsx +++ b/src/ClientApp/src/pages/Resource/components/FilterPanel/index.tsx @@ -190,6 +190,7 @@ export default ({ group={searchForm.group} onChange={v => { setSearchForm({ + ...searchForm, group: v, }); }} diff --git a/src/ClientApp/src/sdk/Api.ts b/src/ClientApp/src/sdk/Api.ts index 778e3992..0fecd51f 100644 --- a/src/ClientApp/src/sdk/Api.ts +++ b/src/ClientApp/src/sdk/Api.ts @@ -1501,6 +1501,8 @@ export interface BakabaseModulesCustomPropertyModelsViewCustomPropertyTypeConver export interface BakabaseModulesCustomPropertyModelsViewCustomPropertyTypeConversionOverviewViewModelTin { /** [1: SingleLineText, 2: MultilineText, 3: SingleChoice, 4: MultipleChoice, 5: Number, 6: Percentage, 7: Rating, 8: Boolean, 9: Link, 10: Attachment, 11: Date, 12: DateTime, 13: Time, 14: Formula, 15: Multilevel, 16: Tags] */ type?: BakabaseModulesCustomPropertyAbstractionsModelsDomainConstantsCustomPropertyType; + /** [1: String, 2: ListString, 3: Decimal, 4: Link, 5: Boolean, 6: DateTime, 7: Time, 8: ListListString, 9: ListTag] */ + bizValueType?: BakabaseAbstractionsModelsDomainConstantsStandardValueType; serializedBizValue?: string | null; outputs?: BakabaseModulesCustomPropertyModelsViewCustomPropertyTypeConversionOverviewViewModelTout[] | null; } @@ -5101,6 +5103,21 @@ export class Api extends HttpClient + this.request({ + path: `/enhancer/${enhancerId}/enhancement`, + method: "DELETE", + format: "json", + ...params, + }), + /** * No description * diff --git a/src/ClientApp/src/sdk/apis.js b/src/ClientApp/src/sdk/apis.js index a4efdd14..6f429b8f 100644 --- a/src/ClientApp/src/sdk/apis.js +++ b/src/ClientApp/src/sdk/apis.js @@ -3819,6 +3819,51 @@ export const DeleteEnhancementsByCategoryURL = function(parameters = {}) { let keys = Object.keys(queryParameters) return domain + path + (keys.length > 0 ? '?' + (keys.map(key => key + '=' + encodeURIComponent(queryParameters[key])).join('&')) : '') } +/** + * + * request: DeleteEnhancementsByEnhancer + * url: DeleteEnhancementsByEnhancerURL + * method: DeleteEnhancementsByEnhancer_TYPE + * raw_url: DeleteEnhancementsByEnhancer_RAW_URL + * @param enhancerId - + */ +export const DeleteEnhancementsByEnhancer = function(parameters = {}) { + const domain = parameters.$domain ? parameters.$domain : getDomain() + const config = parameters.$config + let path = '/enhancer/{enhancerId}/enhancement' + let body + let queryParameters = {} + let form = {} + path = path.replace('{enhancerId}', `${parameters['enhancerId']}`) + if (parameters['enhancerId'] === undefined) { + return Promise.reject(new Error('Missing required parameter: enhancerId')) + } + if (parameters.$queryParameters) { + Object.keys(parameters.$queryParameters).forEach(function(parameterName) { + queryParameters[parameterName] = parameters.$queryParameters[parameterName] + }); + } + return request('delete', domain + path, body, queryParameters, form, config) +} +export const DeleteEnhancementsByEnhancer_RAW_URL = function() { + return '/enhancer/{enhancerId}/enhancement' +} +export const DeleteEnhancementsByEnhancer_TYPE = function() { + return 'delete' +} +export const DeleteEnhancementsByEnhancerURL = function(parameters = {}) { + let queryParameters = {} + const domain = parameters.$domain ? parameters.$domain : getDomain() + let path = '/enhancer/{enhancerId}/enhancement' + path = path.replace('{enhancerId}', `${parameters['enhancerId']}`) + if (parameters.$queryParameters) { + Object.keys(parameters.$queryParameters).forEach(function(parameterName) { + queryParameters[parameterName] = parameters.$queryParameters[parameterName] + }) + } + let keys = Object.keys(queryParameters) + return domain + path + (keys.length > 0 ? '?' + (keys.map(key => key + '=' + encodeURIComponent(queryParameters[key])).join('&')) : '') +} /** * * request: GetAllEnhancerDescriptors diff --git a/src/ClientApp/src/sdk/constants.ts b/src/ClientApp/src/sdk/constants.ts index 5c73b2ab..eaa1e1cf 100644 --- a/src/ClientApp/src/sdk/constants.ts +++ b/src/ClientApp/src/sdk/constants.ts @@ -56,32 +56,6 @@ export enum MigrationTiming {BeforeDbMigration = 1, AfterDbMigration = 2} export const migrationTimings = Object.keys(MigrationTiming).filter(k => typeof MigrationTiming[k] === 'number').map(t => ({label: t, value: MigrationTiming[t]})); export enum OsPlatform {Unknown = 0, Windows = 1, Osx = 2, Linux = 3, FreeBsd = 4} export const osPlatforms = Object.keys(OsPlatform).filter(k => typeof OsPlatform[k] === 'number').map(t => ({label: t, value: OsPlatform[t]})); -export enum CaptchaType {Image = 1, SmsMessage = 2} -export const captchaTypes = Object.keys(CaptchaType).filter(k => typeof CaptchaType[k] === 'number').map(t => ({label: t, value: CaptchaType[t]})); -export enum DingSysLevel {Other = 0, MainAdministrator = 1, SubAdministrator = 2, Boss = 100} -export const dingSysLevels = Object.keys(DingSysLevel).filter(k => typeof DingSysLevel[k] === 'number').map(t => ({label: t, value: DingSysLevel[t]})); -export enum ResponseCode {Success = 0, NotModified = 304, InvalidPayloadOrOperation = 400, Unauthenticated = 401, Unauthorized = 403, NotFound = 404, Conflict = 409, SystemError = 500, Timeout = 504, InvalidCaptcha = 100400} -export const responseCodes = Object.keys(ResponseCode).filter(k => typeof ResponseCode[k] === 'number').map(t => ({label: t, value: ResponseCode[t]})); -export enum Operation {DELETE = 0, INSERT = 1, EQUAL = 2} -export const operations = Object.keys(Operation).filter(k => typeof Operation[k] === 'number').map(t => ({label: t, value: Operation[t]})); -export enum ProgressorClientAction {Start = 1, Stop = 2, Initialize = 3} -export const progressorClientActions = Object.keys(ProgressorClientAction).filter(k => typeof ProgressorClientAction[k] === 'number').map(t => ({label: t, value: ProgressorClientAction[t]})); -export enum ProgressorEvent {StateChanged = 1, ProgressChanged = 2, ErrorOccurred = 3} -export const progressorEvents = Object.keys(ProgressorEvent).filter(k => typeof ProgressorEvent[k] === 'number').map(t => ({label: t, value: ProgressorEvent[t]})); -export enum ProgressorStatus {Idle = 1, Running = 2, Complete = 3, Suspended = 4} -export const progressorStatuses = Object.keys(ProgressorStatus).filter(k => typeof ProgressorStatus[k] === 'number').map(t => ({label: t, value: ProgressorStatus[t]})); -export enum FileStorageUploadResponseCode {Success = 0, Error = 500} -export const fileStorageUploadResponseCodes = Object.keys(FileStorageUploadResponseCode).filter(k => typeof FileStorageUploadResponseCode[k] === 'number').map(t => ({label: t, value: FileStorageUploadResponseCode[t]})); -export enum MessageStatus {ToBeSent = 0, Succeed = 1, Failed = 2} -export const messageStatuses = Object.keys(MessageStatus).filter(k => typeof MessageStatus[k] === 'number').map(t => ({label: t, value: MessageStatus[t]})); -export enum NotificationType {Os = 1, Email = 2, OsAndEmail = 3, WeChat = 4, Sms = 8} -export const notificationTypes = Object.keys(NotificationType).filter(k => typeof NotificationType[k] === 'number').map(t => ({label: t, value: NotificationType[t]})); -export enum AdbDeviceState {Device = 1, Offline = 2, NoDevice = 3} -export const adbDeviceStates = Object.keys(AdbDeviceState).filter(k => typeof AdbDeviceState[k] === 'number').map(t => ({label: t, value: AdbDeviceState[t]})); -export enum AdbExceptionCode {Error = 1, InvalidExitCode = 2} -export const adbExceptionCodes = Object.keys(AdbExceptionCode).filter(k => typeof AdbExceptionCode[k] === 'number').map(t => ({label: t, value: AdbExceptionCode[t]})); -export enum AdbInternalError {Error = 1, INSTALL_FAILED_ALREADY_EXISTS = 100, DELETE_FAILED_INTERNAL_ERROR = 101, FailedToConnectDevice = 200} -export const adbInternalErrors = Object.keys(AdbInternalError).filter(k => typeof AdbInternalError[k] === 'number').map(t => ({label: t, value: AdbInternalError[t]})); export enum CategoryResourceDisplayNameSegmentType {StaticText = 1, Property = 2, LeftWrapper = 3, RightWrapper = 4} export const categoryResourceDisplayNameSegmentTypes = Object.keys(CategoryResourceDisplayNameSegmentType).filter(k => typeof CategoryResourceDisplayNameSegmentType[k] === 'number').map(t => ({label: t, value: CategoryResourceDisplayNameSegmentType[t]})); export enum InitializationContentType {NotAcceptTerms = 1, NeedRestart = 2} @@ -196,6 +170,32 @@ export enum TagAdditionalItem {None = 0, GroupName = 1, PreferredAlias = 2} export const tagAdditionalItems = Object.keys(TagAdditionalItem).filter(k => typeof TagAdditionalItem[k] === 'number').map(t => ({label: t, value: TagAdditionalItem[t]})); export enum TagGroupAdditionalItem {Tags = 1, PreferredAlias = 2, TagNamePreferredAlias = 4} export const tagGroupAdditionalItems = Object.keys(TagGroupAdditionalItem).filter(k => typeof TagGroupAdditionalItem[k] === 'number').map(t => ({label: t, value: TagGroupAdditionalItem[t]})); +export enum CaptchaType {Image = 1, SmsMessage = 2} +export const captchaTypes = Object.keys(CaptchaType).filter(k => typeof CaptchaType[k] === 'number').map(t => ({label: t, value: CaptchaType[t]})); +export enum DingSysLevel {Other = 0, MainAdministrator = 1, SubAdministrator = 2, Boss = 100} +export const dingSysLevels = Object.keys(DingSysLevel).filter(k => typeof DingSysLevel[k] === 'number').map(t => ({label: t, value: DingSysLevel[t]})); +export enum ResponseCode {Success = 0, NotModified = 304, InvalidPayloadOrOperation = 400, Unauthenticated = 401, Unauthorized = 403, NotFound = 404, Conflict = 409, SystemError = 500, Timeout = 504, InvalidCaptcha = 100400} +export const responseCodes = Object.keys(ResponseCode).filter(k => typeof ResponseCode[k] === 'number').map(t => ({label: t, value: ResponseCode[t]})); +export enum Operation {DELETE = 0, INSERT = 1, EQUAL = 2} +export const operations = Object.keys(Operation).filter(k => typeof Operation[k] === 'number').map(t => ({label: t, value: Operation[t]})); +export enum ProgressorClientAction {Start = 1, Stop = 2, Initialize = 3} +export const progressorClientActions = Object.keys(ProgressorClientAction).filter(k => typeof ProgressorClientAction[k] === 'number').map(t => ({label: t, value: ProgressorClientAction[t]})); +export enum ProgressorEvent {StateChanged = 1, ProgressChanged = 2, ErrorOccurred = 3} +export const progressorEvents = Object.keys(ProgressorEvent).filter(k => typeof ProgressorEvent[k] === 'number').map(t => ({label: t, value: ProgressorEvent[t]})); +export enum ProgressorStatus {Idle = 1, Running = 2, Complete = 3, Suspended = 4} +export const progressorStatuses = Object.keys(ProgressorStatus).filter(k => typeof ProgressorStatus[k] === 'number').map(t => ({label: t, value: ProgressorStatus[t]})); +export enum FileStorageUploadResponseCode {Success = 0, Error = 500} +export const fileStorageUploadResponseCodes = Object.keys(FileStorageUploadResponseCode).filter(k => typeof FileStorageUploadResponseCode[k] === 'number').map(t => ({label: t, value: FileStorageUploadResponseCode[t]})); +export enum MessageStatus {ToBeSent = 0, Succeed = 1, Failed = 2} +export const messageStatuses = Object.keys(MessageStatus).filter(k => typeof MessageStatus[k] === 'number').map(t => ({label: t, value: MessageStatus[t]})); +export enum NotificationType {Os = 1, Email = 2, OsAndEmail = 3, WeChat = 4, Sms = 8} +export const notificationTypes = Object.keys(NotificationType).filter(k => typeof NotificationType[k] === 'number').map(t => ({label: t, value: NotificationType[t]})); +export enum AdbDeviceState {Device = 1, Offline = 2, NoDevice = 3} +export const adbDeviceStates = Object.keys(AdbDeviceState).filter(k => typeof AdbDeviceState[k] === 'number').map(t => ({label: t, value: AdbDeviceState[t]})); +export enum AdbExceptionCode {Error = 1, InvalidExitCode = 2} +export const adbExceptionCodes = Object.keys(AdbExceptionCode).filter(k => typeof AdbExceptionCode[k] === 'number').map(t => ({label: t, value: AdbExceptionCode[t]})); +export enum AdbInternalError {Error = 1, INSTALL_FAILED_ALREADY_EXISTS = 100, DELETE_FAILED_INTERNAL_ERROR = 101, FailedToConnectDevice = 200} +export const adbInternalErrors = Object.keys(AdbInternalError).filter(k => typeof AdbInternalError[k] === 'number').map(t => ({label: t, value: AdbInternalError[t]})); export enum ExHentaiCategory {Unknown = 0, Misc = 1, Doushijin = 2, Manga = 4, ArtistCG = 8, GameCG = 16, ImageSet = 32, Cosplay = 64, AsianPorn = 128, NonH = 256, Western = 512} export const exHentaiCategories = Object.keys(ExHentaiCategory).filter(k => typeof ExHentaiCategory[k] === 'number').map(t => ({label: t, value: ExHentaiCategory[t]})); export enum ExHentaiConnectionStatus {Ok = 1, InvalidCookie = 2, IpBanned = 3, UnknownError = 4}