Compare commits

...

10 Commits

Author SHA1 Message Date
6cd935c959 Merge branch 'stable/2024.2' 2024-10-23 22:03:28 +00:00
16f6a084d0 Initial commit with Skyline console code 2024-10-23 22:00:27 +00:00
zhangjingwei
5501bad74a feat: add Turkish language to the default config
1. add Turkish language in the default config.yaml
2. fix the tr key in the locales

Change-Id: I9e23d14e5b5114c8d827770b33b8254b9d7a3be2
(cherry picked from commit 23ea22a1de)
2024-09-25 04:10:49 +00:00
zhangjingwei
23ea22a1de feat: add Turkish language to the default config
1. add Turkish language in the default config.yaml
2. fix the tr key in the locales

Change-Id: I9e23d14e5b5114c8d827770b33b8254b9d7a3be2
2024-09-24 16:01:10 +08:00
zhangjingwei
d037b061f4 fix: fix user/group column
1. fix the user column in the project manage user form
2. fix the user group column in the project manage user group form
3. fix the user group column in the user creation form
4. fix the user column in the group manage user form

Change-Id: I66caec013023320de557d4b85fe1704d7d1f4b6f
2024-09-06 01:16:05 +00:00
zhuboxiang
6b85304c01 Upgrade to use node 16 instead of node 14
Failed to update apt cache: W:The repository
'https://deb.nodesource.com/node_14.x noble Release'
does not have a Release file.

So Upgrade to use node 16 instead of node 14

Change-Id: I81411ec4824f19b1eaf03c2b1c469f6bfb16d82a
2024-09-05 10:52:10 +08:00
zhangjingwei
7513e64f7c fix: fix edit instance
fix edit instance in the instance detail page for the non-admin user

Change-Id: I300a3020b8402ca9638e1139a14c460a6a0a2660
2024-07-25 10:52:58 +08:00
zhuboxiang
f70772ecc8 Lock setuptools version as 69.2.0
Lock setuptools version as 69.2.0. We need package like
skyline-console tar.gz. If we use higher version, we will
get skyline_console tar.gz package.

Change-Id: Id93fe64e83c2951b069d97177f6da851271a7ba8
2024-07-15 16:35:02 +08:00
zhangjingwei
3d9d596c67 feat: update tip for the user-domain input
update the tips for the user-domain input in the login form

Change-Id: I51fbab2888710346b8590683bf245af9f7dbdc85
2024-07-15 11:26:41 +08:00
zhangjingwei
a28eedf973 feat: update login form
1. Change the domain option to input, requiring the user to enter <username>@<domain name>
2. update e2e case to support new login form

Change-Id: I55611abfc4d58278bddab24a958a1ec2de57e442
2024-07-12 09:53:46 +08:00
23 changed files with 173 additions and 90 deletions

View File

@ -502,31 +502,34 @@
/opt/stack/skyline-console/test/e2e/videos: logs
- job:
name: skyline-nodejs14-run-lint-src
name: skyline-nodejs16-run-lint-src
parent: nodejs-run-lint
description: |
Run lint using Node 14 for skyline-console src directory.
Run lint using Node 16 for skyline-console src directory.
vars:
node_version: 14
node_version: 16
js_build_command: lint
nodeset: ubuntu-jammy
- job:
name: skyline-nodejs14-run-lint-test
name: skyline-nodejs16-run-lint-test
parent: nodejs-run-lint
description: |
Run lint using Node 14 for skyline-console test directory.
Run lint using Node 16 for skyline-console test directory.
vars:
node_version: 14
node_version: 16
js_build_command: lint:test
nodeset: ubuntu-jammy
- job:
name: skyline-nodejs14-run-unit-test
name: skyline-nodejs16-run-unit-test
parent: nodejs-run-test
description: |
Run unit test using Node 14 for skyline-console.
Run unit test using Node 16 for skyline-console.
vars:
node_version: 14
node_version: 16
js_build_command: test:unit
nodeset: ubuntu-jammy
- job:
name: publish-skyline-console-python-branch-tarball
@ -545,9 +548,9 @@
- publish-openstack-docs-pti
check:
jobs:
- skyline-nodejs14-run-lint-src
- skyline-nodejs14-run-lint-test
- skyline-nodejs14-run-unit-test
- skyline-nodejs16-run-lint-src
- skyline-nodejs16-run-lint-test
- skyline-nodejs16-run-unit-test
- skyline-console-devstack-e2etests-compute:
irrelevant-files: &e2etests-compute-irrelevant-files
# network
@ -780,9 +783,9 @@
- ^skyline_console/.*$
gate:
jobs:
- skyline-nodejs14-run-lint-src
- skyline-nodejs14-run-lint-test
- skyline-nodejs14-run-unit-test
- skyline-nodejs16-run-lint-src
- skyline-nodejs16-run-lint-test
- skyline-nodejs16-run-unit-test
- skyline-console-devstack-e2etests-compute:
irrelevant-files: *e2etests-compute-irrelevant-files
- skyline-console-devstack-e2etests-network:

View File

@ -76,6 +76,9 @@ package: install
rm -rf $(ROOT_DIR)/skyline_console/static
yarn run build
echo `git rev-parse --verify HEAD` > $(ROOT_DIR)/skyline_console/static/commit_id.txt
# fix setuptools version as 69.2.0
# if we use higher version of this, we will get skyline_console tar.gz package
pip install --upgrade setuptools==69.2.0
python setup.py sdist
python setup.py bdist_wheel

View File

@ -10,4 +10,5 @@ globalVariables:
- en
- zh-hans
- ko-kr
- tr-tr
- ru

View File

@ -82,10 +82,7 @@ module.exports = {
},
},
],
include: [
root('src/asset/image/cloud-logo.svg'),
root('src/asset/image/cloud-logo-white.svg'),
],
include: [root('src/asset/image/FelCloud_website_white-07-01.png')],
},
{
test: /\.(woff|woff2|ttf|eot|svg)$/,

View File

@ -0,0 +1,8 @@
---
features:
- |
Update login form:
* Change the domain selector to input, requiring the user to enter <username>@<domain name>, such as: admin@Default.
* If the user enters only <username>, the "Default" domain will be used, such as: admin.

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -14,8 +14,8 @@
import React from 'react';
import { Link } from 'react-router-dom';
import cloudLogo from 'asset/image/cloud-logo.svg';
import cloudLogoWhite from 'asset/image/cloud-logo-white.svg';
import cloudLogo from 'asset/image/FelCloud_website_white-07-01.png';
import { getPath } from 'utils/route-map';
import classnames from 'classnames';
import GlobalNav from '../GlobalNav';
@ -37,11 +37,12 @@ export default function HeaderContent(props) {
const renderLogo = () => {
const homeUrl = getRoutePath('overview');
const logoSrc =
GLOBAL_VARIABLES.skylineThemeName === 'default'
? cloudLogo
: cloudLogoWhite;
GLOBAL_VARIABLES.skylineThemeName === 'default' ? cloudLogo : cloudLogo;
return (
<div className={classnames(styles.logo)}>
<div
className={classnames(styles.logo)}
style={{ backgroundColor: '#26262B' }}
>
<Link to={homeUrl}>
<img src={logoSrc} alt="logo" className={styles['logo-image']} />
</Link>

View File

@ -17,9 +17,8 @@ import { inject, observer } from 'mobx-react';
import renderRoutes from 'utils/RouterConfig';
import SelectLang from 'components/SelectLang';
import logo from 'asset/image/logo.png';
import logo from 'asset/image/FelCloud_website_white-07-01.png';
import loginFullImage from 'asset/image/login-full.png';
import loginRightLogo from 'asset/image/loginRightLogo.png';
import styles from './index.less';
export class AuthLayout extends Component {
@ -39,9 +38,10 @@ export class AuthLayout extends Component {
/>
<div className={styles['full-image-front']} />
<img
src={loginRightLogo}
src={logo}
alt=""
className={styles['login-right-logo']}
style={{ maxWidth: '200px' }}
/>
</div>
);
@ -56,7 +56,10 @@ export class AuthLayout extends Component {
</div>
<div className={styles.main}>
<div className={styles.top}>
<div className={styles.header}>
<div
className={styles.header}
style={{ backgroundColor: '#26262b;', width: 'fit-content' }}
>
<img alt="logo" className={styles.logo} src={logo} />
</div>
</div>

View File

@ -29,6 +29,7 @@
"5min": "5min",
"8 to 16 characters, at least one uppercase letter, one lowercase letter, one number.": "8 to 16 characters, at least one uppercase letter, one lowercase letter, one number.",
"8 to 32 characters, at least one uppercase letter, one lowercase letter, one number and one special character.": "8 to 32 characters, at least one uppercase letter, one lowercase letter, one number and one special character.",
"<username> or <username>@<domain>": "<username> or <username>@<domain>",
"A command that will be sent to the container": "A command that will be sent to the container",
"A container with the same name already exists": "A container with the same name already exists",
"A dynamic scheduling algorithm that estimates the server load based on the number of currently active connections. The system allocates new connection requests to the server with the least number of current connections. Commonly used for long connection services, such as database connections and other services.": "A dynamic scheduling algorithm that estimates the server load based on the number of currently active connections. The system allocates new connection requests to the server with the least number of current connections. Commonly used for long connection services, such as database connections and other services.",
@ -1881,6 +1882,7 @@
"Please enter the server id to be reduced, and separate different id with \",\"": "Please enter the server id to be reduced, and separate different id with \",\"",
"Please fill in the peer network segment and subnet mask of CIDR format, the written subnets should be under the same router, one per line.": "Please fill in the peer network segment and subnet mask of CIDR format, the written subnets should be under the same router, one per line.",
"Please input": "Please input",
"Please input <username> or <username>@<domain name>!": "Please input <username> or <username>@<domain name>!",
"Please input ICMP code(0-255)": "Please input ICMP code(0-255)",
"Please input ICMP type(0-255)": "Please input ICMP type(0-255)",
"Please input IPv4 or IPv6 cidr": "Please input IPv4 or IPv6 cidr",
@ -1913,6 +1915,7 @@
"Please input protocol number if it absent in select list.": "Please input protocol number if it absent in select list.",
"Please input provider": "Please input provider",
"Please input snapshot name": "Please input snapshot name",
"Please input the correct format: <username> or <username>@<domain name>.": "Please input the correct format: <username> or <username>@<domain name>.",
"Please input transfer id": "Please input transfer id",
"Please input user name": "Please input user name",
"Please input value": "Please input value",
@ -1942,7 +1945,6 @@
"Please select source": "Please select source",
"Please select type": "Please select type",
"Please select volume type": "Please select volume type",
"Please select your Domain!": "Please select your Domain!",
"Please select your Region!": "Please select your Region!",
"Please select {label}!": "Please select {label}!",
"Please select {name} first": "Please select {name} first",
@ -2263,7 +2265,6 @@
"Select User Group": "Select User Group",
"Select Volume Snapshot": "Select Volume Snapshot",
"Select a QoS Policy": "Select a QoS Policy",
"Select a domain": "Select a domain",
"Select a login type": "Select a login type",
"Select a network": "Select a network",
"Select a project": "Select a project",
@ -2648,6 +2649,7 @@
"Time between running the check in seconds": "Time between running the check in seconds",
"Timeout(Minute)": "Timeout(Minute)",
"Timeout(s)": "Timeout(s)",
"Tips: without domain means \"Default\" domain.": "Tips: without domain means \"Default\" domain.",
"To open": "To open",
"Today CPU usage > 80% alert": "Today CPU usage > 80% alert",
"Today Memory usage > 80% alert": "Today Memory usage > 80% alert",

View File

@ -22,6 +22,6 @@ export default {
'zh-hans': zhHansData,
en: enData,
'ko-kr': krData,
tr: trData,
'tr-tr': trData,
ru: ruData,
};

View File

@ -29,6 +29,7 @@
"5min": "5분",
"8 to 16 characters, at least one uppercase letter, one lowercase letter, one number.": "8 ~ 16 문자, 최소 대문자 한개, 소문자 한개, 숫자 한개, 특수 문자 한개",
"8 to 32 characters, at least one uppercase letter, one lowercase letter, one number and one special character.": "8 ~ 32 문자, 최소 대문자 한개, 소문자 한개, 숫자 한개, 특수 문자 한개",
"<username> or <username>@<domain>": "<사용자 이름> 또는 <사용자 이름>@<도메인>",
"A command that will be sent to the container": "컨테이너로 전송될 명령어",
"A container with the same name already exists": "동일한 이름의 컨테이너가 존재합니다.",
"A dynamic scheduling algorithm that estimates the server load based on the number of currently active connections. The system allocates new connection requests to the server with the least number of current connections. Commonly used for long connection services, such as database connections and other services.": "동적 스케쥴링 알고리즘은 현재 연결된 커넥션 수로 서버 로드를 예측합니다. 시스템은 최소 연결을 가진 서버로 새로운 연결을 할당합니다. 데이터베이스 연결 및 다른 서비스 처럼 오래 지속되는 연결을 갖는 서비스에 활용됩니다.",
@ -1881,6 +1882,7 @@
"Please enter the server id to be reduced, and separate different id with \",\"": "",
"Please fill in the peer network segment and subnet mask of CIDR format, the written subnets should be under the same router, one per line.": "",
"Please input": "",
"Please input <username> or <username>@<domain name>!": "<사용자 이름> 또는 <사용자 이름>@<도메인 이름>을 입력해주세요!",
"Please input ICMP code(0-255)": "",
"Please input ICMP type(0-255)": "",
"Please input IPv4 or IPv6 cidr": "",
@ -1913,6 +1915,7 @@
"Please input protocol number if it absent in select list.": "선택 목록에 없으면 프로토콜 번호를 입력하세요.",
"Please input provider": "제공자를 입력하세요.",
"Please input snapshot name": "snapshot 이름을 입력하세요.",
"Please input the correct format: <username> or <username>@<domain name>.": "올바른 형식(<사용자 이름> 또는 <사용자 이름>@<도메인 이름>)을 입력하십시오.",
"Please input transfer id": "전송 ID를 입력하세요.",
"Please input user name": "사용자 이름을 입력하세요.",
"Please input value": "값을 입력하세요.",
@ -1942,7 +1945,6 @@
"Please select source": "소스를 선택하세요.",
"Please select type": "유형을 선택하세요.",
"Please select volume type": "볼륨 유형을 선택하세요.",
"Please select your Domain!": "도메인을 선택하세요!",
"Please select your Region!": "지역을 선택하세요!",
"Please select {label}!": "{label}을(를) 선택하세요!",
"Please select {name} first": "{name}을(를) 먼저 선택하세요.",
@ -2263,7 +2265,6 @@
"Select User Group": "",
"Select Volume Snapshot": "",
"Select a QoS Policy": "",
"Select a domain": "도메인 선택",
"Select a login type": "로그인 유형 선택",
"Select a network": "",
"Select a project": "",
@ -2648,6 +2649,7 @@
"Time between running the check in seconds": "검사 간격(초)",
"Timeout(Minute)": "타임아웃(분)",
"Timeout(s)": "타임아웃(초)",
"Tips: without domain means \"Default\" domain.": "팁: 도메인이 없으면 \"Default\" 도메인을 의미합니다.",
"To open": "열기",
"Today CPU usage > 80% alert": "오늘 CPU 사용량 > 80% 경고",
"Today Memory usage > 80% alert": "오늘 메모리 사용량 > 80% 경고",

View File

@ -29,6 +29,7 @@
"5min": "5 минут",
"8 to 16 characters, at least one uppercase letter, one lowercase letter, one number.": "8 до 16 символов, как минимум одна заглавная буква, одна строчная буква и одна цифра.",
"8 to 32 characters, at least one uppercase letter, one lowercase letter, one number and one special character.": "",
"<username> or <username>@<domain>": "<имя пользователя> или <имя пользователя>@<домен>",
"A command that will be sent to the container": "Команда, которая будет отправлена в контейнер",
"A container with the same name already exists": "Контейнер с таким же именем уже существует",
"A dynamic scheduling algorithm that estimates the server load based on the number of currently active connections. The system allocates new connection requests to the server with the least number of current connections. Commonly used for long connection services, such as database connections and other services.": "Динамический алгоритм планирования, который оценивает нагрузку сервера на основе количества активных соединений. Система выделяет новые запросы на соединение серверу с наименьшим количеством текущих соединений. Часто используется для долгосрочных сервисов с соединением, таких как подключения к базам данных и другие сервисы.",
@ -1881,6 +1882,7 @@
"Please enter the server id to be reduced, and separate different id with \",\"": "Пожалуйста, введите идентификатор сервера, который необходимо уменьшить, и разделите разные идентификаторы запятой \",\"",
"Please fill in the peer network segment and subnet mask of CIDR format, the written subnets should be under the same router, one per line.": "Пожалуйста, заполните сегмент сети пира и маску подсети в формате CIDR, написанные подсети должны быть под одним маршрутизатором, по одной на строку.",
"Please input": "Пожалуйста, введите",
"Please input <username> or <username>@<domain name>!": "Пожалуйста, введите <имя пользователя> или <имя пользователя>@<имя домена>!",
"Please input ICMP code(0-255)": "Пожалуйста, введите код ICMP (0-255)",
"Please input ICMP type(0-255)": "Пожалуйста, введите тип ICMP (0-255)",
"Please input IPv4 or IPv6 cidr": "Пожалуйста, введите CIDR IPv4 или IPv6",
@ -1913,6 +1915,7 @@
"Please input protocol number if it absent in select list.": "Пожалуйста, введите номер протокола, если его нет в списке выбора.",
"Please input provider": "Пожалуйста, введите провайдера",
"Please input snapshot name": "Пожалуйста, введите имя снимка",
"Please input the correct format: <username> or <username>@<domain name>.": "Пожалуйста, введите правильный формат: <имя пользователя> или <имя пользователя>@<имя домена>.",
"Please input transfer id": "Пожалуйста, введите идентификатор передачи",
"Please input user name": "Пожалуйста, введите имя пользователя",
"Please input value": "Пожалуйста, введите значение",
@ -1942,7 +1945,6 @@
"Please select source": "Пожалуйста, выберите источник",
"Please select type": "Пожалуйста, выберите тип",
"Please select volume type": "Пожалуйста, выберите тип диска",
"Please select your Domain!": "Пожалуйста, выберите ваш домен!",
"Please select your Region!": "Пожалуйста, выберите ваш регион!",
"Please select {label}!": "Пожалуйста, выберите {label}!",
"Please select {name} first": "Пожалуйста, сначала выберите {name}",
@ -2263,7 +2265,6 @@
"Select User Group": "Выберите группу пользователей",
"Select Volume Snapshot": "Выберите снимок диска",
"Select a QoS Policy": "",
"Select a domain": "Выберите домен",
"Select a login type": "Выберите тип входа",
"Select a network": "",
"Select a project": "",
@ -2648,6 +2649,7 @@
"Time between running the check in seconds": "Интервал выполнения проверки в секундах",
"Timeout(Minute)": "Тайм-аут (минуты)",
"Timeout(s)": "Тайм-аут (секунды)",
"Tips: without domain means \"Default\" domain.": "Советы: отсутствие домена означает домен «Default».",
"To open": "Открыть",
"Today CPU usage > 80% alert": "Сегодня предупреждение: использование CPU > 80%",
"Today Memory usage > 80% alert": "Сегодня предупреждение: использование памяти > 80%",

View File

@ -29,6 +29,7 @@
"5min": "5 Dk",
"8 to 16 characters, at least one uppercase letter, one lowercase letter, one number.": "8 ile 16 karakter, en az bir büyük harf, en az bir küçük harf, en az bir rakam.",
"8 to 32 characters, at least one uppercase letter, one lowercase letter, one number and one special character.": "",
"<username> or <username>@<domain>": "<kullanıcı adı> veya <kullanıcı adı>@<etki alanı>",
"A command that will be sent to the container": "Konteyner'a gönderilecek bir komut",
"A container with the same name already exists": "Aynı isme sahip bir konteyner bulunmaktadır.",
"A dynamic scheduling algorithm that estimates the server load based on the number of currently active connections. The system allocates new connection requests to the server with the least number of current connections. Commonly used for long connection services, such as database connections and other services.": "Dinamik zamanlama algoritması, sunucu yükünü o anda açık olan bağlantı sayısından tahmin eder. Sistem, o anda en az sayıda bağlantıya sahip sunucuya yeni bağlantılar tahsis eder. Veritabanı bağlantıları gibi uzun ömürlü bağlantılara sahip hizmetler için kullanılır.",
@ -1881,6 +1882,7 @@
"Please enter the server id to be reduced, and separate different id with \",\"": "Azaltılacak sunucu ID'sini girin ve farklı ID'leri \",\" ile ayırın",
"Please fill in the peer network segment and subnet mask of CIDR format, the written subnets should be under the same router, one per line.": "CIDR biçimindeki eş ağ segmenti ve alt ağ maskesini doldurun, yazılı alt ağlar aynı yönlendirici altında satır başına bir adet olmalıdır.",
"Please input": "Lütfen girin",
"Please input <username> or <username>@<domain name>!": "Lütfen <kullanıcı adı> veya <kullanıcı adı>@<etki alanı adı> girin!",
"Please input ICMP code(0-255)": "Lütfen ICMP kodu girin (0-255)",
"Please input ICMP type(0-255)": "Lütfen ICMP türü girin (0-255)",
"Please input IPv4 or IPv6 cidr": "Lütfen IPv4 veya IPv6 cidr girin",
@ -1913,6 +1915,7 @@
"Please input protocol number if it absent in select list.": "Eğer seçim listesinde yoksa, lütfen protokol numarasını girin.",
"Please input provider": "Lütfen sağlayıcı girin",
"Please input snapshot name": "Lütfen anlık görüntü adı girin",
"Please input the correct format: <username> or <username>@<domain name>.": "Lütfen doğru biçimi girin: <kullanıcı adı> veya <kullanıcı adı>@<etki alanı adı>.",
"Please input transfer id": "Lütfen transfer ID girin",
"Please input user name": "Lütfen kullanıcı adı girin",
"Please input value": "Lütfen değer girin",
@ -1942,7 +1945,6 @@
"Please select source": "Lütfen kaynak seçin",
"Please select type": "Lütfen tür seçin",
"Please select volume type": "Lütfen disk türü seçin",
"Please select your Domain!": "Lütfen alan adınızı seçin!",
"Please select your Region!": "Lütfen bölgenizi seçin!",
"Please select {label}!": "Lütfen {label} seçin!",
"Please select {name} first": "Lütfen önce {name} seçin",
@ -2263,7 +2265,6 @@
"Select User Group": "Kullanıcı Grubu Seçin",
"Select Volume Snapshot": "Disk Anlık Görüntüsü Seçin",
"Select a QoS Policy": "",
"Select a domain": "Bir etki alanı seçin",
"Select a login type": "Bir giriş türü seçin",
"Select a network": "",
"Select a project": "",
@ -2648,6 +2649,7 @@
"Time between running the check in seconds": "Saniye cinsinden kontrol çalıştırma aralığı",
"Timeout(Minute)": "Zaman Aşımı(Dakika)",
"Timeout(s)": "Zaman Aşımı(Saniye)",
"Tips: without domain means \"Default\" domain.": "İpuçları: Alan adı olmadan \"Default\" alan adı anlamına gelir.",
"To open": "Açmak için",
"Today CPU usage > 80% alert": "Bugünkü CPU kullanımı > 80% uyarısı",
"Today Memory usage > 80% alert": "Bugünkü bellek kullanımı > 80% uyarısı",

View File

@ -29,6 +29,7 @@
"5min": "5分钟",
"8 to 16 characters, at least one uppercase letter, one lowercase letter, one number.": "8个到16个字符至少一个大写字母一个小写字母一个数字。",
"8 to 32 characters, at least one uppercase letter, one lowercase letter, one number and one special character.": "8个到32个字符至少一个大写字母一个小写字母一个数字和一个特殊字符。",
"<username> or <username>@<domain>": "<用户名> 或 <用户名>@<用户域名>",
"A command that will be sent to the container": "将发送到容器的命令",
"A container with the same name already exists": "已存在同名容器",
"A dynamic scheduling algorithm that estimates the server load based on the number of currently active connections. The system allocates new connection requests to the server with the least number of current connections. Commonly used for long connection services, such as database connections and other services.": "通过当前活跃的连接数来估计服务器负载情况的一种动态调度算法,系统把新的连接请求分配给当前连接数目最少的服务器。常用于长连接服务,例如数据库连接等服务。",
@ -1881,6 +1882,7 @@
"Please enter the server id to be reduced, and separate different id with \",\"": "请输入指定缩减的server ID并且不同ID之间用 ',' 分隔",
"Please fill in the peer network segment and subnet mask of CIDR format, the written subnets should be under the same router, one per line.": "请填写CIDR格式的对端网段且填写的网段需在同一个路由下每行一个。",
"Please input": "请输入",
"Please input <username> or <username>@<domain name>!": "请输入<用户名> 或 <用户名>@<用户域名>",
"Please input ICMP code(0-255)": "请输入ICMP编码(0-255)",
"Please input ICMP type(0-255)": "请输入ICMP类型(0-255)",
"Please input IPv4 or IPv6 cidr": "请输入IPv4或IPv6网段地址",
@ -1913,6 +1915,7 @@
"Please input protocol number if it absent in select list.": "如果选择列表中没有,请输入协议号。",
"Please input provider": "请输入提供者",
"Please input snapshot name": "请输入快照名称",
"Please input the correct format: <username> or <username>@<domain name>.": "请输入正确格式:<用户名> 或 <用户名>@<用户域名>",
"Please input transfer id": "请输入转让Id",
"Please input user name": "请输入用户名称",
"Please input value": "请输入值",
@ -1942,7 +1945,6 @@
"Please select source": "请选择源",
"Please select type": "请选择类型",
"Please select volume type": "请选择云硬盘类型",
"Please select your Domain!": "请选择Domain",
"Please select your Region!": "请选择Region",
"Please select {label}!": "请选择{label}",
"Please select {name} first": "请先选择{name}",
@ -2263,7 +2265,6 @@
"Select User Group": "选择用户组",
"Select Volume Snapshot": "选择云硬盘快照",
"Select a QoS Policy": "请选择Qos策略",
"Select a domain": "请选择Domain",
"Select a login type": "请选择登录方式",
"Select a network": "请选择网络",
"Select a project": "请选择项目",
@ -2648,6 +2649,7 @@
"Time between running the check in seconds": "运行检查之间的时间(以秒为单位)",
"Timeout(Minute)": "创建超时(分钟)",
"Timeout(s)": "检查超时时间(秒)",
"Tips: without domain means \"Default\" domain.": "提示不输入域名则默认为“Default”域名。",
"To open": "去开通",
"Today CPU usage > 80% alert": "今日CPU使用率大于80%的告警",
"Today Memory usage > 80% alert": "今日内存使用率大于80%的告警",

View File

@ -36,16 +36,10 @@ export class Login extends Component {
}
componentDidMount() {
this.getDomains();
this.getRegions();
this.getSSO();
}
async getDomains() {
await this.store.fetchDomainList();
this.updateDefaultValue();
}
async getRegions() {
await this.store.fetchRegionList();
this.updateDefaultValue();
@ -78,13 +72,6 @@ export class Login extends Component {
return t('Welcome, {name}', { name });
}
get domains() {
return (this.store.domains || []).map((it) => ({
label: it,
value: it,
}));
}
get regions() {
return (this.store.regions || []).map((it) => ({
label: it,
@ -92,6 +79,10 @@ export class Login extends Component {
}));
}
get domains() {
return [];
}
get nextPage() {
const { location = {} } = this.props;
const { search } = location;
@ -165,9 +156,6 @@ export class Login extends Component {
if (this.regions.length === 1) {
data.region = this.regions[0].value;
}
if (this.domains.length === 1) {
data.domain = this.domains[0].value;
}
return data;
}
@ -200,16 +188,18 @@ export class Login extends Component {
const domainItem = {
name: 'domain',
required: true,
message: t('Please select your Domain!'),
render: () => (
<Select placeholder={t('Select a domain')} options={this.domains} />
<Input placeholder={t('<username> or <username>@<domain>')} />
),
extra: t('Tips: without domain means "Default" domain.'),
rules: [{ required: true, validator: this.usernameDomainValidator }],
};
const usernameItem = {
name: 'username',
required: true,
required: false,
message: t('Please input your Username!'),
render: () => <Input placeholder={t('Username')} />,
hidden: true,
};
const passwordItem = {
name: 'password',
@ -327,8 +317,11 @@ export class Login extends Component {
message: '',
error: false,
});
const { domain, password, region, username } = values;
const body = { domain, password, region, username };
const { password, region, domain } = values;
const usernameDomain = this.getUsernameAndDomain({
usernameDomain: domain,
});
const body = { password, region, ...usernameDomain };
this.rootStore.login(body).then(
() => {
this.onLoginSuccess();
@ -359,6 +352,37 @@ export class Login extends Component {
return t('Username or password is incorrect');
}
getUsernameAndDomain = (values) => {
const { usernameDomain } = values;
const tmp = usernameDomain.trim().split('@');
return {
username: tmp[0],
domain: tmp[1] || 'Default',
};
};
usernameDomainValidator = (rule, value) => {
if (!value || !value.trim()) {
return Promise.reject(
t('Please input <username> or <username>@<domain name>!')
);
}
const tmp = value.trim().split('@');
const message = t(
'Please input the correct format: <username> or <username>@<domain name>.'
);
if (tmp.length > 2) {
return Promise.reject(new Error(message));
}
const { username, domain } = this.getUsernameAndDomain({
usernameDomain: value,
});
if (!username || !domain) {
return Promise.reject(new Error(message));
}
return Promise.resolve();
};
dealWithChangePassword = (detail, values) => {
const userId = this.getUserId(detail);
const data = {

View File

@ -20,7 +20,7 @@ import { UserStore } from 'stores/keystone/user';
import { RoleStore } from 'stores/keystone/role';
import { ModalAction } from 'containers/Action';
import {
nameDomainColumns,
userDomainColumns,
transferFilterOption,
} from 'resources/keystone/domain';
import { roleFilterOption } from 'resources/keystone/role';
@ -116,12 +116,12 @@ export class ManageUser extends ModalAction {
static allowed = () => Promise.resolve(true);
get leftUserTable() {
return nameDomainColumns;
return userDomainColumns;
}
get rightUserTable() {
return [
...nameDomainColumns,
...userDomainColumns,
{
title: t('Select Project Role'),
dataIndex: 'id',

View File

@ -20,7 +20,7 @@ import { GroupStore } from 'stores/keystone/user-group';
import globalRoleStore from 'stores/keystone/role';
import { ModalAction } from 'containers/Action';
import {
nameDomainColumns,
groupDomainColumns,
transferFilterOption,
} from 'resources/keystone/domain';
import { roleFilterOption } from 'resources/keystone/role';
@ -115,7 +115,7 @@ export class ManageUserGroup extends ModalAction {
static allowed = () => Promise.resolve(true);
get leftGroupGroupTable() {
return nameDomainColumns;
return groupDomainColumns;
}
onClickSelect = (e) => {
@ -142,7 +142,7 @@ export class ManageUserGroup extends ModalAction {
get rightGroupGroupTable() {
return [
...nameDomainColumns,
...groupDomainColumns,
{
title: t('Select Project Role'),
dataIndex: 'id',

View File

@ -29,8 +29,9 @@ import {
import {
statusTypes,
getDomainFormItem,
nameDomainColumns,
projectDomainColumns,
transferFilterOption,
groupDomainColumns,
} from 'resources/keystone/domain';
import { roleFilterOption } from 'resources/keystone/role';
@ -135,7 +136,7 @@ export class Create extends FormAction {
static allowed = () => Promise.resolve(true);
get leftProjectTable() {
return nameDomainColumns;
return projectDomainColumns;
}
get projectRoleList() {
@ -185,7 +186,7 @@ export class Create extends FormAction {
get rightProjectTable() {
return [
...nameDomainColumns,
...projectDomainColumns,
{
title: t('Select Project Role'),
dataIndex: 'id',
@ -210,11 +211,11 @@ export class Create extends FormAction {
};
get leftUserGroupTable() {
return nameDomainColumns;
return groupDomainColumns;
}
get rightUserGroupTable() {
return nameDomainColumns;
return groupDomainColumns;
}
checkName = (rule, value) => {

View File

@ -17,7 +17,7 @@ import { UserStore } from 'stores/keystone/user';
import { GroupStore } from 'stores/keystone/user-group';
import { ModalAction } from 'containers/Action';
import {
nameDomainColumns,
userDomainColumns,
transferFilterOption,
} from 'resources/keystone/domain';
@ -79,11 +79,11 @@ export class ManageUser extends ModalAction {
static allowed = () => Promise.resolve(true);
get leftUserTable() {
return nameDomainColumns;
return userDomainColumns;
}
get rightUserTable() {
return nameDomainColumns;
return userDomainColumns;
}
get defaultValue() {

View File

@ -71,7 +71,20 @@ export const enabledColumn = {
stringify: (val) => (val ? t('Yes') : t('No')),
};
export const nameDomainColumns = [
export const domainColumn = {
dataIndex: 'domainName',
title: t('Domain ID/Name'),
render: (value, record) => {
return (
<>
<div>{getIdRender(record.domain_id, true, false)}</div>
<div>{value}</div>
</>
);
},
};
export const projectDomainColumns = [
{
dataIndex: 'name',
title: t('Project ID/Name'),
@ -84,18 +97,39 @@ export const nameDomainColumns = [
);
},
},
domainColumn,
];
export const userDomainColumns = [
{
dataIndex: 'domainName',
title: t('Domain ID/Name'),
dataIndex: 'name',
title: t('User ID/Name'),
render: (value, record) => {
return (
<>
<div>{getIdRender(record.domain_id, true, false)}</div>
<div>{getIdRender(record.id, true, false)}</div>
<div>{value}</div>
</>
);
},
},
domainColumn,
];
export const groupDomainColumns = [
{
dataIndex: 'name',
title: t('User Group ID/Name'),
render: (value, record) => {
return (
<>
<div>{getIdRender(record.id, true, false)}</div>
<div>{value}</div>
</>
);
},
},
domainColumn,
];
export const transferFilterOption = (inputValue, record) => {

View File

@ -116,11 +116,14 @@ export class ServerStore extends Base {
noReminder: true,
all_projects,
});
item.itemInList = result[0];
item.itemInList = result.find((it) => it.id === id);
} else {
const store = new RecycleBinStore();
const result = await store.fetchList({ uuid: id, all_projects });
item.itemInList = result[0];
const result = await store.fetchList({
uuid: id,
all_projects,
});
item.itemInList = result.find((it) => it.id === id);
}
} catch (e) {
// eslint-disable-next-line no-console

View File

@ -14,20 +14,17 @@
describe('The Login Page', () => {
it('successfully loads', () => {
cy.intercept('GET', '/domains').as('domains');
cy.intercept('GET', '/regions').as('regions');
cy.visit('/');
cy.waitLoginFormLoading();
cy.wait('@domains');
cy.wait('@regions');
});
it('successfully error username and password', () => {
cy.wait(5000);
cy.loginFormSelect(0, 'RegionOne')
.loginFormSelect(1, 'Default')
.loginFormInput('username', `${Cypress.env('username')}1`)
.loginFormInput('domain', `${Cypress.env('username')}1`)
.loginFormInput('password', `${Cypress.env('password')}1`)
.loginFormSubmit()
.get('#normal_login_error')
@ -37,8 +34,7 @@ describe('The Login Page', () => {
it('successfully login and check menu', () => {
cy.wait(5000);
cy.loginFormSelect(0, 'RegionOne')
.loginFormSelect(1, 'Default')
.loginFormInput('username', Cypress.env('username'))
.loginFormInput('domain', Cypress.env('username'))
.loginFormInput('password', Cypress.env('password'))
.loginFormSubmit()
.wait(2000)

View File

@ -124,8 +124,7 @@ Cypress.Commands.add('loginByPage', (username, password) => {
cy.visit('/');
cy.waitLoginFormLoading().wait(5000);
cy.loginFormSelect(0, 'RegionOne')
.loginFormSelect(1, 'Default')
.loginFormInput('username', username || Cypress.env('username'))
.loginFormInput('domain', username || Cypress.env('username'))
.loginFormInput('password', password || Cypress.env('password'))
.loginFormSubmit();
});