Skip to content

Commit 0960736

Browse files
authored
feat:add q dev ui (#8587)
1 parent 1db010b commit 0960736

9 files changed

Lines changed: 481 additions & 1 deletion

File tree

backend/plugins/q_dev/models/migrationscripts/20250320_modify_file_meta.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (*modifyFileMetaTable) Up(basicRes context.BasicRes) errors.Error {
5151
return errors.Default.Wrap(err, "failed to load column metadata for _tool_q_dev_s3_file_meta.processed_time")
5252
}
5353
if len(cols) == 0 {
54-
// If column is not visible in metadata, treat as no processing needed
54+
// If column is not visible in metadata, treat as no processing needed
5555
return nil
5656
}
5757
if nullable, ok := cols[0].Nullable(); ok {

config-ui/src/plugins/register/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { TAPDConfig } from './tapd';
3333
import { WebhookConfig } from './webhook';
3434
import { ZenTaoConfig } from './zentao';
3535
import { OpsgenieConfig } from './opsgenie';
36+
import { QDevConfig } from './q-dev';
3637
import { TeambitionConfig } from './teambition';
3738
import { TestmoConfig } from './testmo';
3839
import { SlackConfig } from './slack/config';
@@ -50,6 +51,7 @@ export const pluginConfigs: IPluginConfig[] = [
5051
JiraConfig,
5152
PagerDutyConfig,
5253
SlackConfig,
54+
QDevConfig,
5355
SonarQubeConfig,
5456
TAPDConfig,
5557
TestmoConfig,
Lines changed: 62 additions & 0 deletions
Loading
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
import { IPluginConfig } from '@/types';
20+
21+
import Icon from './assets/icon.svg?react';
22+
23+
export const QDevConfig: IPluginConfig = {
24+
plugin: 'q_dev',
25+
name: 'Q Developer',
26+
icon: ({ color }) => <Icon fill={color} />,
27+
sort: 20,
28+
connection: {
29+
docLink: '', // TODO: 添加文档链接
30+
initialValues: {
31+
accessKeyId: '',
32+
secretAccessKey: '',
33+
region: 'us-east-1',
34+
bucket: '',
35+
identityStoreId: '',
36+
identityStoreRegion: 'us-east-1',
37+
rateLimitPerHour: 20000,
38+
},
39+
fields: [
40+
'name',
41+
{
42+
key: 'accessKeyId',
43+
label: 'AWS Access Key ID',
44+
subLabel: '请输入您的AWS Access Key ID',
45+
},
46+
{
47+
key: 'secretAccessKey',
48+
label: 'AWS Secret Access Key',
49+
subLabel: '请输入您的AWS Secret Access Key',
50+
},
51+
{
52+
key: 'region',
53+
label: 'AWS区域',
54+
subLabel: '请输入AWS区域,例如:us-east-1',
55+
},
56+
{
57+
key: 'bucket',
58+
label: 'S3存储桶名称',
59+
subLabel: '请输入存储Q Developer数据的S3存储桶名称',
60+
},
61+
{
62+
key: 'identityStoreId',
63+
label: 'IAM Identity Store ID',
64+
subLabel: '请输入Identity Store ID,格式:d-xxxxxxxxxx',
65+
},
66+
{
67+
key: 'identityStoreRegion',
68+
label: 'IAM Identity Center区域',
69+
subLabel: '请输入IAM Identity Center所在的AWS区域',
70+
},
71+
'proxy',
72+
{
73+
key: 'rateLimitPerHour',
74+
subLabel: '设置每小时的API请求限制,用于控制数据收集速度',
75+
defaultValue: 20000,
76+
},
77+
],
78+
},
79+
dataScope: {
80+
title: 'Data Sources',
81+
},
82+
};
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
import { ChangeEvent, useEffect } from 'react';
20+
import { Input } from 'antd';
21+
22+
import { Block } from '@/components';
23+
24+
interface Props {
25+
accessKeyId: string;
26+
secretAccessKey: string;
27+
region: string;
28+
errors: {
29+
accessKeyId?: string;
30+
secretAccessKey?: string;
31+
region?: string;
32+
};
33+
setValues: (values: any) => void;
34+
setErrors: (errors: any) => void;
35+
}
36+
37+
export const AwsCredentials = ({
38+
accessKeyId,
39+
secretAccessKey,
40+
region,
41+
errors,
42+
setValues,
43+
setErrors
44+
}: Props) => {
45+
46+
const validateAccessKeyId = (value: string) => {
47+
if (!value) {
48+
return 'AWS Access Key ID是必填项';
49+
}
50+
if (!/^[A-Z0-9]{20}$/.test(value)) {
51+
return 'AWS Access Key ID格式不正确';
52+
}
53+
return '';
54+
};
55+
56+
const validateSecretAccessKey = (value: string) => {
57+
if (!value) {
58+
return 'AWS Secret Access Key是必填项';
59+
}
60+
if (value.length < 40) {
61+
return 'AWS Secret Access Key长度不足';
62+
}
63+
return '';
64+
};
65+
66+
const validateRegion = (value: string) => {
67+
if (!value) {
68+
return 'AWS区域是必填项';
69+
}
70+
if (!/^[a-z0-9-]+$/.test(value)) {
71+
return 'AWS区域格式不正确';
72+
}
73+
return '';
74+
};
75+
76+
const handleAccessKeyIdChange = (e: ChangeEvent<HTMLInputElement>) => {
77+
const value = e.target.value;
78+
setValues({ accessKeyId: value });
79+
setErrors({ accessKeyId: validateAccessKeyId(value) });
80+
};
81+
82+
const handleSecretAccessKeyChange = (e: ChangeEvent<HTMLInputElement>) => {
83+
const value = e.target.value;
84+
setValues({ secretAccessKey: value });
85+
setErrors({ secretAccessKey: validateSecretAccessKey(value) });
86+
};
87+
88+
const handleRegionChange = (e: ChangeEvent<HTMLInputElement>) => {
89+
const value = e.target.value;
90+
setValues({ region: value });
91+
setErrors({ region: validateRegion(value) });
92+
};
93+
94+
return (
95+
<>
96+
<Block title="AWS Access Key ID" description="请输入您的AWS Access Key ID" required>
97+
<Input
98+
style={{ width: 386 }}
99+
placeholder="AKIAIOSFODNN7EXAMPLE"
100+
value={accessKeyId}
101+
onChange={handleAccessKeyIdChange}
102+
status={errors.accessKeyId ? 'error' : ''}
103+
/>
104+
{errors.accessKeyId && <div style={{ color: 'red', fontSize: '12px', marginTop: '4px' }}>{errors.accessKeyId}</div>}
105+
</Block>
106+
107+
<Block title="AWS Secret Access Key" description="请输入您的AWS Secret Access Key" required>
108+
<Input.Password
109+
style={{ width: 386 }}
110+
placeholder="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
111+
value={secretAccessKey}
112+
onChange={handleSecretAccessKeyChange}
113+
status={errors.secretAccessKey ? 'error' : ''}
114+
/>
115+
{errors.secretAccessKey && <div style={{ color: 'red', fontSize: '12px', marginTop: '4px' }}>{errors.secretAccessKey}</div>}
116+
</Block>
117+
118+
<Block title="AWS区域" description="请输入AWS区域,例如:us-east-1" required>
119+
<Input
120+
style={{ width: 386 }}
121+
placeholder="us-east-1"
122+
value={region}
123+
onChange={handleRegionChange}
124+
status={errors.region ? 'error' : ''}
125+
/>
126+
{errors.region && <div style={{ color: 'red', fontSize: '12px', marginTop: '4px' }}>{errors.region}</div>}
127+
</Block>
128+
</>
129+
);
130+
};

0 commit comments

Comments
 (0)