Skip to content
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
11 changes: 2 additions & 9 deletions DEV.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,29 @@
## 技术栈

* React 18

* AntDesign 5

* Zustand

* Emotion

* i18n

* pnpm

* ...



## 目录结构


```text
.
└── packages
├── arex arex 主项目包
├── arex-core arex 公共组件包 - 提供面向业务逻辑封装的重型组件
├── arex-request arex 请求包 - 提供浏览器发送 http-rest 请求支持
└── arex-lite arex 精简版 - 提供 arex 项目结构及组件 demo 演示

```



## 本地开发

### 启动项目

`Fork` 并 `git clone` 仓库
Expand All @@ -67,3 +58,5 @@ pnpm run test
pnpm run build
```

### 服务接口代理
本地开发需要修改packages/arex/config/proxy.json文件,指向服务接口地址。
7 changes: 7 additions & 0 deletions packages/arex-request/src/components/Request/RequestBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ArexContentTypes } from '../../types';
import RequestBinaryBody from './RequestBinaryBody';
import RequestBodyFormData from './RequestBodyFormData';
import RequestRawBody, { RequestRawBodyRef } from './RequestRawBody';
import RequestURLEncodeBody from './RequestURLEncodeBody';

const rawSmallCateOptions = [
{
Expand All @@ -23,6 +24,10 @@ const rawSmallCateOptions = [
label: 'application/octet-stream',
value: 'application/octet-stream',
},
{
label: 'application/x-www-form-urlencoded',
value: 'application/x-www-form-urlencoded',
},
];

const RequestBody = () => {
Expand Down Expand Up @@ -124,6 +129,8 @@ const RequestBody = () => {
<RequestBodyFormData />
) : store.request.body.contentType.startsWith('application/octet-stream') ? (
<RequestBinaryBody />
) : store.request.body.contentType.startsWith('application/x-www-form-urlencoded') ? (
<RequestURLEncodeBody />
) : null}
</div>
);
Expand Down
111 changes: 111 additions & 0 deletions packages/arex-request/src/components/Request/RequestURLEncodeBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { CopyOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons';
import { copyToClipboard, SpaceBetweenWrapper, TooltipButton } from '@arextest/arex-core';
import { App, Typography } from 'antd';
import pagination from 'antd/es/pagination';
import PM from 'postman-collection';
import React, { FC, useEffect } from 'react';
import { useTranslation } from 'react-i18next';

import { useArexRequestStore } from '../../hooks';
import { ArexRESTParam } from '../../types';
import HeadersTable from '../HeadersTable';

const RequestURLEncodeBody: FC = () => {
const { t } = useTranslation();
const { message } = App.useApp();
const { store, dispatch } = useArexRequestStore();
const { params } = store.request;
const body = store.request?.body?.body as string;

const setParams = (params: ArexRESTParam[]) => {
dispatch((state) => {
state.request.params = params;
// 同时更新body为URI编码格式
const urlEncoded = params
.filter((p) => p.active && p.key)
.map((p) => `${encodeURIComponent(p.key)}=${encodeURIComponent(p.value || '')}`)
.join('&');
if (state.request.body) {
state.request.body.body = urlEncoded;
}
});
};

// 初始化时从body解析参数
useEffect(() => {
if (body && params.length === 0) {
try {
const urlParams = new URLSearchParams(body);
const parsedParams: ArexRESTParam[] = [];
urlParams.forEach((value, key) => {
parsedParams.push({
key: decodeURIComponent(key),
value: decodeURIComponent(value),
active: true,
id: String(Math.random()),
});
});
if (parsedParams.length > 0) {
dispatch((state) => {
state.request.params = parsedParams;
});
}
} catch (e) {
console.warn('Failed to parse URL encoded body:', e);
}
}
}, [body, dispatch]);

const handleCopyParameters = () => {
const urlEncoded = params
.filter((p) => p.active)
.map((p) => `${encodeURIComponent(p.key)}=${encodeURIComponent(p.value)}`)
.join('&');
copyToClipboard(urlEncoded);
message.success(t('action.copy_success'));
};

return (
<div>
<SpaceBetweenWrapper>
<Typography.Text type='secondary'>{t('request.urlencoded_body')}</Typography.Text>
<div>
<TooltipButton
title={t('action.copy')}
icon={<CopyOutlined />}
onClick={handleCopyParameters}
/>

<TooltipButton
title={t('action.clear_all')}
icon={<DeleteOutlined />}
onClick={() => {
setParams([]);
}}
/>

<TooltipButton
title={t('add.new')}
icon={<PlusOutlined />}
onClick={() => {
setParams(
params.concat([{ value: '', key: '', id: String(Math.random()), active: true }]),
);
}}
/>
</div>
</SpaceBetweenWrapper>

<HeadersTable
editable
rowKey='id'
pagination={false}
dataSource={params}
// @ts-ignore
onEdit={setParams}
/>
</div>
);
};

export default RequestURLEncodeBody;
1 change: 1 addition & 0 deletions packages/arex-request/src/types/ArexContentTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const KnownContentTypes = {
'application/json': 'json',
'multipart/form-data': 'multipart',
'application/octet-stream': 'binary',
'application/x-www-form-urlencoded': 'urlencoded',
} as const;

export type ArexContentTypes = keyof typeof KnownContentTypes;
6 changes: 5 additions & 1 deletion packages/arex-server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ const SERVICE_SCHEDULE_URL = process.env.SERVICE_SCHEDULE_URL;
const SERVICE_STORAGE_URL = process.env.SERVICE_STORAGE_URL;

if (!SERVICE_API_URL || !SERVICE_SCHEDULE_URL || !SERVICE_STORAGE_URL) {
throw new Error('SERVICE_API_URL, SERVICE_SCHEDULE_URL, SERVICE_STORAGE_URL are required');
const missingVars = [];
if (!SERVICE_API_URL) missingVars.push('SERVICE_API_URL');
if (!SERVICE_SCHEDULE_URL) missingVars.push('SERVICE_SCHEDULE_URL');
if (!SERVICE_STORAGE_URL) missingVars.push('SERVICE_STORAGE_URL');
throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`);
}

app.use(
Expand Down
6 changes: 3 additions & 3 deletions packages/arex/config/proxy.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[
{
"path": "/webApi",
"target": "http://10.118.1.217:18090"
"target": "http://localhost:8090"
},
{
"path": "/schedule",
"target": "http://10.118.1.217:18092"
"target": "http://localhost:8092"
},
{
"path": "/storage",
"target": "http://10.118.1.217:18093"
"target": "http://localhost:8093"
}
]
1 change: 0 additions & 1 deletion packages/arex/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"@emotion/styled": "^11.10.6",
"@formkit/auto-animate": "^0.7.0",
"@monaco-editor/react": "^4.6.0",
"@sentry/react": "^7.113.0",
"ahooks": "^3.7.5",
"allotment": "^1.20.2",
"antd": "^5.19.0",
Expand Down
3 changes: 0 additions & 3 deletions packages/arex/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@ import ReactDOM from 'react-dom/client';
import { BrowserRouter, HashRouter } from 'react-router-dom';

import { isClientProd } from '@/constant';
import { initSentry } from '@/utils/sentry';

import App from './App';

dayjs.extend(customParseFormat);

initSentry();

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
React.createElement(isClientProd ? HashRouter : BrowserRouter, {}, <App />),
);
16 changes: 0 additions & 16 deletions packages/arex/src/utils/sentry.ts

This file was deleted.

Loading