Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
frontend-data-crawler-be
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
BangNSK
frontend-data-crawler-be
Commits
4b5d694e
Commit
4b5d694e
authored
Jul 30, 2026
by
ThinhNC
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(api-keys): add API key management interface
parent
060f545a
Changes
7
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
643 additions
and
1 deletion
+643
-1
App.tsx
src/App.tsx
+2
-0
PageTitle.tsx
src/components/PageTitle.tsx
+1
-0
DashboardLayout.tsx
src/layouts/DashboardLayout.tsx
+7
-1
ApiKeys.tsx
src/pages/ApiKeys.tsx
+582
-0
Logs.tsx
src/pages/Logs.tsx
+4
-0
api.ts
src/services/api.ts
+42
-0
apiError.ts
src/utils/apiError.ts
+5
-0
No files found.
src/App.tsx
View file @
4b5d694e
...
...
@@ -10,6 +10,7 @@ import { JobDetail } from './pages/JobDetail';
import
{
Users
}
from
'./pages/Users'
;
import
{
Logs
}
from
'./pages/Logs'
;
import
{
Profile
}
from
'./pages/Profile'
;
import
{
ApiKeys
}
from
'./pages/ApiKeys'
;
import
{
ForgotPassword
}
from
'./pages/ForgotPassword'
;
import
{
ResetPassword
}
from
'./pages/ResetPassword'
;
import
{
VerifyEmail
}
from
'./pages/VerifyEmail'
;
...
...
@@ -59,6 +60,7 @@ export default function App() {
{
/* Profile */
}
<
Route
path=
"profile"
element=
{
<
Profile
/>
}
/>
<
Route
path=
"api-keys"
element=
{
<
ApiKeys
/>
}
/>
{
/* Admin Only Routes */
}
<
Route
...
...
src/components/PageTitle.tsx
View file @
4b5d694e
...
...
@@ -9,6 +9,7 @@ const TITLES: Record<string, string> = {
'/reset-password'
:
'Đặt lại mật khẩu | Data Crawler'
,
'/verify-email'
:
'Xác minh email | Data Crawler'
,
'/profile'
:
'Hồ sơ cá nhân | Data Crawler'
,
'/api-keys'
:
'Quản lý API Key | Data Crawler'
,
'/users'
:
'Quản lý người dùng | Data Crawler'
,
'/logs'
:
'Nhật ký hệ thống | Data Crawler'
,
};
...
...
src/layouts/DashboardLayout.tsx
View file @
4b5d694e
import
React
from
'react'
;
import
{
Link
,
useNavigate
,
useLocation
,
Outlet
}
from
'react-router-dom'
;
import
{
useAuth
}
from
'../context/auth'
;
import
{
Database
,
Users
,
History
,
User
,
LogOut
,
Compass
}
from
'lucide-react'
;
import
{
Database
,
Users
,
History
,
User
,
LogOut
,
Compass
,
KeyRound
}
from
'lucide-react'
;
export
const
DashboardLayout
:
React
.
FC
=
()
=>
{
const
{
user
,
logout
,
isAdmin
}
=
useAuth
();
...
...
@@ -20,6 +20,12 @@ export const DashboardLayout: React.FC = () => {
icon
:
<
Database
className=
"h-5 w-5"
/>,
allowed
:
true
,
},
{
name
:
'Quản lý API Key'
,
path
:
'/api-keys'
,
icon
:
<
KeyRound
className=
"h-5 w-5"
/>,
allowed
:
true
,
},
{
name
:
'Quản lý Users'
,
path
:
'/users'
,
...
...
src/pages/ApiKeys.tsx
0 → 100644
View file @
4b5d694e
This diff is collapsed.
Click to expand it.
src/pages/Logs.tsx
View file @
4b5d694e
...
...
@@ -42,6 +42,9 @@ const ACTION_COLORS: Record<string, string> = {
RESET_PASSWORD
:
'bg-sky-100 text-sky-700'
,
VERIFY_EMAIL
:
'bg-teal-100 text-teal-700'
,
RESEND_VERIFICATION
:
'bg-teal-100 text-teal-700'
,
CREATE_API_KEY
:
'bg-emerald-100 text-emerald-700'
,
UPDATE_API_KEY_STATUS
:
'bg-indigo-100 text-indigo-700'
,
REVOKE_API_KEY
:
'bg-rose-100 text-rose-700'
,
};
const
ACTION_OPTIONS
=
[
...
...
@@ -61,6 +64,7 @@ const ACTION_OPTIONS = [
'ADMIN_UPDATE_USER'
,
'ADMIN_DELETE_USER'
,
'CREATE_API_KEY'
,
'UPDATE_API_KEY_STATUS'
,
'REVOKE_API_KEY'
,
'CREATE_WEBHOOK_CONFIG'
,
'DELETE_WEBHOOK_CONFIG'
,
...
...
src/services/api.ts
View file @
4b5d694e
import
axios
from
'axios'
;
export
interface
ApiKeyRecord
{
id
:
string
;
userId
:
string
;
name
:
string
;
keyPrefix
:
string
;
isActive
:
boolean
;
expiresAt
:
string
|
null
;
lastUsedAt
:
string
|
null
;
createdAt
:
string
;
updatedAt
:
string
;
}
export
interface
CreatedApiKey
extends
ApiKeyRecord
{
rawKey
:
string
;
}
interface
ApiResponse
<
T
>
{
success
:
boolean
;
data
:
T
;
}
export
const
API_BASE_URL
=
(
import
.
meta
.
env
.
VITE_API_BASE_URL
||
'http://171.247.68.96:4011/api/v1'
)
.
replace
(
/
\/
$/
,
''
);
...
...
@@ -73,6 +94,27 @@ api.interceptors.response.use(
export
const
getApiUrl
=
(
path
:
string
)
=>
`
${
API_BASE_URL
}
/
${
path
.
replace
(
/^
\/
+/
,
''
)}
`
;
export
const
apiKeysApi
=
{
async
list
():
Promise
<
ApiKeyRecord
[]
>
{
const
response
=
await
api
.
get
<
ApiResponse
<
ApiKeyRecord
[]
>>
(
'/api-keys'
);
return
response
.
data
.
data
;
},
async
create
(
input
:
{
name
:
string
;
expiresAt
:
string
|
null
}):
Promise
<
CreatedApiKey
>
{
const
response
=
await
api
.
post
<
ApiResponse
<
CreatedApiKey
>>
(
'/api-keys'
,
input
);
return
response
.
data
.
data
;
},
async
setActive
(
id
:
string
,
isActive
:
boolean
):
Promise
<
ApiKeyRecord
>
{
const
response
=
await
api
.
patch
<
ApiResponse
<
ApiKeyRecord
>>
(
`/api-keys/
${
id
}
`
,
{
isActive
});
return
response
.
data
.
data
;
},
async
revoke
(
id
:
string
):
Promise
<
void
>
{
await
api
.
delete
(
`/api-keys/
${
id
}
`
);
},
};
function
notifyAuthExpired
()
{
localStorage
.
removeItem
(
'accessToken'
);
localStorage
.
removeItem
(
'refreshToken'
);
...
...
src/utils/apiError.ts
View file @
4b5d694e
...
...
@@ -15,6 +15,11 @@ const MESSAGE_TRANSLATIONS: Record<string, string> = {
'Password must contain at least one uppercase letter'
:
'Mật khẩu phải có ít nhất một chữ hoa.'
,
'Password must contain at least one number'
:
'Mật khẩu phải có ít nhất một chữ số.'
,
'Password must contain at least one special character'
:
'Mật khẩu phải có ít nhất một ký tự đặc biệt.'
,
'API Key expiration must be in the future'
:
'Thời điểm hết hạn của API Key phải ở trong tương lai.'
,
'Invalid ISO datetime format for expiration'
:
'Thời điểm hết hạn của API Key không đúng định dạng.'
,
'API Key status is required'
:
'Vui lòng chọn trạng thái cho API Key.'
,
'API Key status must be a boolean'
:
'Trạng thái API Key không hợp lệ.'
,
'API key not found'
:
'Không tìm thấy API Key.'
,
};
interface
ApiErrorShape
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment