Skip to content
Merged
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
24 changes: 23 additions & 1 deletion .github/workflows/build-base-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,29 @@ on:
- 'package-lock.json'
- 'yarn.lock'
- 'Dockerfile-base'
workflow_dispatch:
inputs:
branch:
description: '构建基础镜像所用的分支'
required: true
type: string
default: 'main'

jobs:
build-and-push:
runs-on: ubuntu-latest

steps:
- name: Lock Pull Request
if: github.event_name == 'push'
run: |
curl -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-d '{"state":"pending", "description":"Action running, merge disabled", "context":"Lock PR"}' \
"https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }}"
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'workflow_dispatch' && inputs.branch || github.ref }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
Expand All @@ -43,8 +58,8 @@ jobs:
with:
platforms: linux/amd64,linux/arm64
push: true
tags: jumpserver/${{ env.REPO }}-base:${{ env.IMAGE_TAG }}
file: Dockerfile-base
tags: jumpserver/${{ env.REPO }}-base:${{ env.IMAGE_TAG }}

- name: Update Dockerfile
run: |
Expand All @@ -59,3 +74,10 @@ jobs:
git push
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Unlock Pull Request
if: github.event_name == 'push'
run: |
curl -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-d '{"state":"success", "description":"Action running, merge disabled", "context":"Lock PR"}' \
"https://api.github.com/repos/${{ github.repository }}/statuses/${{ github.sha }}"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ luna.tar.gz
luna/
package-lock.json
.angular

# generated at build time by scripts/generate-build-info.mjs
/src/environments/build-info.ts
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use base image to build the project avoid npm install every time
FROM jumpserver/luna-base:20250609_105214 AS stage-build
FROM jumpserver/luna-base:20260701_071908 AS stage-build

ARG VERSION
ENV VERSION=$VERSION
Expand Down
4 changes: 3 additions & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"aot": false,
"sourceMap": true,
"namedChunks": true,
"baseHref": "/luna/",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["src/polyfills.ts"],
Expand Down Expand Up @@ -101,7 +102,8 @@
"builder": "@angular/build:dev-server",
"options": {
"buildTarget": "Luna:build",
"proxyConfig": "proxy.conf.json"
"proxyConfig": "proxy.conf.json",
"servePath": "/luna"
},
"configurations": {
"production": {
Expand Down
39 changes: 22 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"license": "GPLv3",
"scripts": {
"ng": "ng",
"dev": "ng serve --proxy-config proxy.conf.json --hmr --host 0.0.0.0",
"start": "ng serve --proxy-config proxy.conf.json --host 0.0.0.0",
"build": "ng build --configuration production",
"dev": "node scripts/generate-build-info.mjs && ng serve --proxy-config proxy.conf.json --serve-path /luna --hmr --host 0.0.0.0",
"start": "node scripts/generate-build-info.mjs && ng serve --proxy-config proxy.conf.json --serve-path /luna --host 0.0.0.0",
"build": "node scripts/generate-build-info.mjs && ng build --configuration production",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
Expand All @@ -15,16 +15,16 @@
"private": true,
"dependencies": {
"@acrodata/code-editor": "^0.5.1",
"@angular/animations": "^19.0.0",
"@angular/animations": "^19.2.20",
"@angular/cdk": "^19.0.0",
"@angular/common": "^19.0.0",
"@angular/compiler": "^19.0.0",
"@angular/core": "^19.0.0",
"@angular/common": "^19.2.20",
"@angular/compiler": "^19.2.20",
"@angular/core": "^19.2.20",
"@angular/flex-layout": "15.0.0-beta.42",
"@angular/forms": "^19.0.0",
"@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
"@angular/forms": "^19.2.20",
"@angular/platform-browser": "^19.2.20",
"@angular/platform-browser-dynamic": "^19.2.20",
"@angular/router": "^19.2.20",
"@ant-design/icons-angular": "^19.0.0",
"@codemirror/language-data": "^6.5.1",
"@ngx-translate/core": "^16.0.4",
Expand All @@ -45,7 +45,7 @@
"guacamole-common-js": "^1.5.0",
"jquery": "^3.7.1",
"jsencrypt": "^3.3.2",
"lodash-es": "^4.17.21",
"lodash-es": "^4.18.0",
"metismenu": "^3.0.7",
"ng-zorro-antd": "^19.3.0",
"ngx-clipboard": "^16.0.0",
Expand All @@ -55,21 +55,22 @@
"popper.js": "^1.16.1",
"requirejs": "^2.3.6",
"rxjs": "^7.8.1",
"sm-crypto": "^0.4.0",
"tslib": "^2.6.2",
"xterm-theme": "^1.1.0",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.0.0",
"@angular-devkit/build-angular": "^19.2.20",
"@angular-eslint/builder": "^19.5.0",
"@angular-eslint/eslint-plugin": "^19.5.0",
"@angular-eslint/eslint-plugin-template": "^19.5.0",
"@angular-eslint/schematics": "^19.5.0",
"@angular-eslint/template-parser": "^19.5.0",
"@angular/build": "^19.0.0",
"@angular/cli": "^19.0.0",
"@angular/compiler-cli": "^19.0.0",
"@angular/language-service": "^19.0.0",
"@angular/build": "^19.2.20",
"@angular/cli": "^19.2.20",
"@angular/compiler-cli": "^19.2.20",
"@angular/language-service": "^19.2.20",
"@types/jasmine": "^5.1.4",
"@types/jasminewd2": "^2.0.13",
"@types/node": "^20.11.19",
Expand All @@ -88,5 +89,9 @@
"ts-node": "^10.9.2",
"typescript": "~5.5.0",
"vite": "^5.0.0"
},
"resolutions": {
"seroval": "1.4.1",
"fast-uri": "3.1.2"
}
}
21 changes: 21 additions & 0 deletions scripts/generate-build-info.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Generates src/environments/build-info.ts with the current build time.
// Runs before `ng build` / `ng serve` (see package.json scripts). Because
// `yarn build` runs inside the Docker build, the value equals the Docker build
// moment in production, and the dev-server start time in development.
// The container defaults to UTC, so the time is formatted as Asia/Shanghai.
import { mkdirSync, writeFileSync } from 'node:fs';
import { dirname } from 'node:path';

const buildTime = new Date().toLocaleString('zh-CN', {
timeZone: 'Asia/Shanghai',
hour12: false
});

const target = 'src/environments/build-info.ts';
mkdirSync(dirname(target), { recursive: true });
writeFileSync(
target,
`// AUTO-GENERATED by scripts/generate-build-info.mjs. Do not edit or commit.\nexport const buildTime = '${buildTime}';\n`
);

console.log(`[build-info] buildTime = ${buildTime}`);
13 changes: 5 additions & 8 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,19 @@ import { AppComponent } from './pages/app.component';
import { ElementComponents } from './elements/elements.component';
import { PluginModules } from './plugins/plugins';
import { ClipboardService } from 'ngx-clipboard';
import { environment, version } from '../environments/environment';
import { version } from '../environments/environment';
import { BehaviorSubject, forkJoin, Observable, of } from 'rxjs';
import { FileInputAccessorModule } from 'file-input-accessor';
import { catchError, mergeMap } from 'rxjs/operators';
import { PagesComponents } from './pages/pages.component';
import { getAppBasePath, withAppBase, withSitePrefix } from '@app/utils/path';

export class CustomLoader implements TranslateLoader {
constructor(private http: HttpClient) {}

public getTranslation(lang: String): Observable<any> {
const remote = '/api/v1/settings/i18n/luna/?lang=' + lang + '&v=' + version;
let local = '/assets/i18n/' + lang + '.json';
const isProd = environment.production;
if (isProd) {
local = '/luna' + local;
}
const remote = withSitePrefix('/api/v1/settings/i18n/luna/?lang=' + lang + '&v=' + version);
const local = withAppBase('/assets/i18n/' + lang + '.json');

return forkJoin([
this.http.get(remote).pipe(catchError(() => of({}))),
Expand Down Expand Up @@ -74,7 +71,7 @@ export class CustomLoader implements TranslateLoader {
bootstrap: [AppComponent],
providers: [
...AllServices,
{ provide: APP_BASE_HREF, useValue: '/luna/' },
{ provide: APP_BASE_HREF, useFactory: getAppBasePath },
CookieService,
NGXLogger,
ClipboardService,
Expand Down
41 changes: 37 additions & 4 deletions src/app/elements/asset-tree/asset-tree.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
</a>
<i
(click)="toggleTreeCheckable($event, tree)"
*ngIf="tree.checkbox"
[nzTooltipTitle]="'Batch actions(select and right click)' | translate"
nz-tooltip
[ngClass]="isTreeCheckEnabled(tree) ? 'fa-check-square' : 'fa-square-o'"
Expand Down Expand Up @@ -64,16 +65,48 @@
>
<table>
<tbody>
<tr *ngFor="let menu of rMenuList; let i = index" class="view-menu__item">
<tr
*ngFor="let menu of rMenuList; let i = index"
[class.view-menu__item--has-submenu]="menu.children?.length"
[ngStyle]="{ display: menu.hide ? 'none' : '' }"
class="view-menu__item"
>
<td
(click)="handleMenuClick(menu)"
(click)="!menu.children?.length && handleMenuClick(menu, $event)"
[attr.data-num]="i"
[ngStyle]="{ display: menu.hide ? 'none' : '' }"
[ngStyle]="{ opacity: menu.disabled ? 0.4 : 1 }"
class="view-menu__data"
>
<span [ngClass]="menu.fa" class="view-menu__icon fa"></span> {{ menu.name | translate }}
<span [ngClass]="menu.fa" class="view-menu__icon fa"></span>
<span class="view-menu__label">{{ menu.name | translate }}</span>
<i *ngIf="menu.children?.length" class="fa fa-angle-right view-menu__submenu-arrow"></i>
<div *ngIf="menu.children?.length" class="view-menu__submenu">
<table>
<tbody>
<tr *ngFor="let child of menu.children" class="view-menu__item">
<td
(click)="handleSubmenuClick($event, child)"
class="view-menu__data view-menu__submenu-data"
>
<span class="view-menu__submenu-label">{{ child.name }}</span>
<i *ngIf="child.checked" class="fa fa-check view-menu__submenu-check"></i>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</div>

<!-- New favorite folder dialog content template -->
<ng-template #folderModalContent>
<input
nz-input
[(ngModel)]="folderNameInput"
[placeholder]="'Folder name' | translate"
type="text"
/>
</ng-template>
57 changes: 56 additions & 1 deletion src/app/elements/asset-tree/asset-tree.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@

.tree-type-content {
position: relative;
padding: 5px 10px;
padding: 1px;
min-height: 40px;
height: calc(100% - 31px);
background-color: var(--el-asset-tree-bg-color);
Expand Down Expand Up @@ -286,9 +286,64 @@ tr:hover {
}

.view-menu__data {
position: relative;
padding: 0 6px;
}

.view-menu__label {
flex: 1;
}

.view-menu__submenu-arrow {
margin-left: 12px;
font-size: 12px;
opacity: 0.6;
}

.view-menu__item--has-submenu {
.view-menu__data {
display: flex;
align-items: center;
padding-right: 10px;
}

&:hover > .view-menu__data > .view-menu__submenu {
display: block;
}
}

.view-menu__submenu {
display: none;
position: absolute;
top: -6px;
left: 100%;
margin: 0;
padding: 6px 0;
min-width: 120px;
border-radius: 2px;
background-color: var(--el-dropdown-bg-color);
box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16);
z-index: 1001;

.view-menu__submenu-data {
display: flex;
align-items: center;
justify-content: space-between;
min-width: 140px;
padding-right: 10px;
}

.view-menu__submenu-label {
flex: 1;
padding-right: 8px;
}

.view-menu__submenu-check {
font-size: 12px;
color: #52c41a;
}
}

.open-tree {
flex: 1;
}
Loading
Loading