Compare commits

...

2 Commits

Author SHA1 Message Date
Yaodong Yu
8d686411ee feat: support add providers inside the Organization scope (#1250)
* feat: support add providers inside the Organization scope

Signed-off-by: magicwind <2814461814@qq.com>

* Update ProviderListPage.js

* fix: gloabal admin can see all providers

* fix: table fixed column warning

* fix: edit application page can get all providers

Signed-off-by: magicwind <2814461814@qq.com>
Co-authored-by: hsluoyz <hsluoyz@qq.com>
2022-11-04 21:31:08 +08:00
Yaodong Yu
ce722897f1 feat: support prefix path for storage files (#1258) 2022-11-04 21:08:39 +08:00
23 changed files with 291 additions and 170 deletions

View File

@@ -48,6 +48,30 @@ func (c *ApiController) GetProviders() {
}
}
// GetGlobalProviders
// @Title GetGlobalProviders
// @Tag Provider API
// @Description get Global providers
// @Success 200 {array} object.Provider The Response object
// @router /get-global-providers [get]
func (c *ApiController) GetGlobalProviders() {
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
c.Data["json"] = object.GetMaskedProviders(object.GetGlobalProviders())
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetGlobalProviderCount(field, value)))
providers := object.GetMaskedProviders(object.GetPaginationGlobalProviders(paginator.Offset(), limit, field, value, sortField, sortOrder))
c.ResponseOk(providers, paginator.Nums())
}
}
// GetProvider
// @Title GetProvider
// @Tag Provider API

View File

@@ -60,6 +60,7 @@ type Provider struct {
IntranetEndpoint string `xorm:"varchar(100)" json:"intranetEndpoint"`
Domain string `xorm:"varchar(100)" json:"domain"`
Bucket string `xorm:"varchar(100)" json:"bucket"`
PathPrefix string `xorm:"varchar(100)" json:"pathPrefix"`
Metadata string `xorm:"mediumtext" json:"metadata"`
IdP string `xorm:"mediumtext" json:"idP"`
@@ -101,6 +102,16 @@ func GetProviderCount(owner, field, value string) int {
return int(count)
}
func GetGlobalProviderCount(field, value string) int {
session := GetSession("", -1, -1, field, value, "", "")
count, err := session.Count(&Provider{})
if err != nil {
panic(err)
}
return int(count)
}
func GetProviders(owner string) []*Provider {
providers := []*Provider{}
err := adapter.Engine.Desc("created_time").Find(&providers, &Provider{Owner: owner})
@@ -111,8 +122,18 @@ func GetProviders(owner string) []*Provider {
return providers
}
func GetPaginationProviders(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Provider {
func GetGlobalProviders() []*Provider {
providers := []*Provider{}
err := adapter.Engine.Desc("created_time").Find(&providers)
if err != nil {
panic(err)
}
return providers
}
func GetPaginationProviders(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Provider {
var providers []*Provider
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&providers)
if err != nil {
@@ -122,6 +143,17 @@ func GetPaginationProviders(owner string, offset, limit int, field, value, sortF
return providers
}
func GetPaginationGlobalProviders(offset, limit int, field, value, sortField, sortOrder string) []*Provider {
var providers []*Provider
session := GetSession("", offset, limit, field, value, sortField, sortOrder)
err := session.Find(&providers)
if err != nil {
panic(err)
}
return providers
}
func getProvider(owner string, name string) *Provider {
if owner == "" || name == "" {
return nil

View File

@@ -55,7 +55,7 @@ func escapePath(path string) string {
}
func getUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) {
escapedPath := escapePath(fullFilePath)
escapedPath := util.UrlJoin(provider.PathPrefix, escapePath(fullFilePath))
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)
host := ""
@@ -70,7 +70,7 @@ func getUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
host = util.UrlJoin(provider.Domain, "/files")
}
if provider.Type == "Azure Blob" {
host = fmt.Sprintf("%s/%s", host, provider.Bucket)
host = util.UrlJoin(host, provider.Bucket)
}
fileUrl := util.UrlJoin(host, escapePath(objectKey))

View File

@@ -123,6 +123,7 @@ func initAPI() {
beego.Router("/api/get-providers", &controllers.ApiController{}, "GET:GetProviders")
beego.Router("/api/get-provider", &controllers.ApiController{}, "GET:GetProvider")
beego.Router("/api/get-global-providers", &controllers.ApiController{}, "GET:GetGlobalProviders")
beego.Router("/api/update-provider", &controllers.ApiController{}, "POST:UpdateProvider")
beego.Router("/api/add-provider", &controllers.ApiController{}, "POST:AddProvider")
beego.Router("/api/delete-provider", &controllers.ApiController{}, "POST:DeleteProvider")

View File

@@ -70,21 +70,6 @@ class AdapterListPage extends BaseListPage {
renderTable(adapters) {
const columns = [
{
title: i18next.t("general:Organization"),
dataIndex: "organization",
key: "organization",
width: "120px",
sorter: true,
...this.getColumnSearchProps("organization"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
@@ -101,6 +86,21 @@ class AdapterListPage extends BaseListPage {
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "organization",
key: "organization",
width: "120px",
sorter: true,
...this.getColumnSearchProps("organization"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",

View File

@@ -420,13 +420,6 @@ class App extends Component {
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/providers">
<Link to="/providers">
{i18next.t("general:Providers")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/applications">
<Link to="/applications">
@@ -437,6 +430,13 @@ class App extends Component {
}
if (Setting.isLocalAdminUser(this.state.account)) {
res.push(
<Menu.Item key="/providers">
<Link to="/providers">
{i18next.t("general:Providers")}
</Link>
</Menu.Item>
);
res.push(
<Menu.Item key="/resources">
<Link to="/resources">
@@ -566,6 +566,7 @@ class App extends Component {
<Route exact path="/adapters/:organizationName/:adapterName" render={(props) => this.renderLoginIfNotLoggedIn(<AdapterEditPage account={this.state.account} {...props} />)} />
<Route exact path="/providers" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderListPage account={this.state.account} {...props} />)} />
<Route exact path="/providers/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)} />
<Route exact path="/providers/:organizationName/:providerName" render={(props) => this.renderLoginIfNotLoggedIn(<ProviderEditPage account={this.state.account} {...props} />)} />
<Route exact path="/applications" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationListPage account={this.state.account} {...props} />)} />
<Route exact path="/applications/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<ApplicationEditPage account={this.state.account} {...props} />)} />
<Route exact path="/resources" render={(props) => this.renderLoginIfNotLoggedIn(<ResourceListPage account={this.state.account} {...props} />)} />

View File

@@ -91,6 +91,7 @@ class ApplicationEditPage extends React.Component {
super(props);
this.state = {
classes: props,
owner: props.account.owner,
applicationName: props.match.params.applicationName,
application: null,
organizations: [],
@@ -141,12 +142,21 @@ class ApplicationEditPage extends React.Component {
}
getProviders() {
ProviderBackend.getProviders("admin")
.then((res) => {
this.setState({
providers: res,
if (Setting.isAdminUser(this.props.account)) {
ProviderBackend.getGlobalProviders()
.then((res) => {
this.setState({
providers: res,
});
});
});
} else {
ProviderBackend.getProviders(this.state.owner)
.then((res) => {
this.setState({
providers: res,
});
});
}
}
getSamlMetadata() {

View File

@@ -63,21 +63,6 @@ class ModelListPage extends BaseListPage {
renderTable(models) {
const columns = [
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
@@ -94,6 +79,21 @@ class ModelListPage extends BaseListPage {
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",

View File

@@ -76,6 +76,38 @@ class PaymentListPage extends BaseListPage {
renderTable(payments) {
const columns = [
{
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "180px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("name"),
render: (text, record, index) => {
return (
<Link to={`/payments/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Provider"),
dataIndex: "provider",
key: "provider",
width: "150px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("provider"),
render: (text, record, index) => {
return (
<Link to={`/providers/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "organization",
@@ -106,22 +138,7 @@ class PaymentListPage extends BaseListPage {
);
},
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "180px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("name"),
render: (text, record, index) => {
return (
<Link to={`/payments/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",
@@ -140,22 +157,6 @@ class PaymentListPage extends BaseListPage {
// sorter: true,
// ...this.getColumnSearchProps('displayName'),
// },
{
title: i18next.t("general:Provider"),
dataIndex: "provider",
key: "provider",
width: "150px",
fixed: "left",
sorter: true,
...this.getColumnSearchProps("provider"),
render: (text, record, index) => {
return (
<Link to={`/providers/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("payment:Type"),
dataIndex: "type",

View File

@@ -77,21 +77,7 @@ class PermissionListPage extends BaseListPage {
renderTable(permissions) {
const columns = [
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
// https://github.com/ant-design/ant-design/issues/22184
{
title: i18next.t("general:Name"),
dataIndex: "name",
@@ -108,6 +94,21 @@ class PermissionListPage extends BaseListPage {
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",

View File

@@ -32,6 +32,7 @@ class ProviderEditPage extends React.Component {
this.state = {
classes: props,
providerName: props.match.params.providerName,
owner: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
provider: null,
mode: props.location.mode !== undefined ? props.location.mode : "edit",
};
@@ -42,7 +43,7 @@ class ProviderEditPage extends React.Component {
}
getProvider() {
ProviderBackend.getProvider("admin", this.state.providerName)
ProviderBackend.getProvider(this.state.owner, this.state.providerName)
.then((provider) => {
this.setState({
provider: provider,
@@ -469,6 +470,16 @@ class ProviderEditPage extends React.Component {
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Path prefix"), i18next.t("provider:The prefix path of the file - Tooltip"))} :
</Col>
<Col span={22} >
<Input value={this.state.provider.pathPrefix} onChange={e => {
this.updateProviderField("pathPrefix", e.target.value);
}} />
</Col>
</Row>
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :

View File

@@ -23,10 +23,25 @@ import i18next from "i18next";
import BaseListPage from "./BaseListPage";
class ProviderListPage extends BaseListPage {
constructor(props) {
super(props);
this.state = {
classes: props,
owner: Setting.isAdminUser(props.account) ? "admin" : props.account.organization.name,
data: [],
pagination: {
current: 1,
pageSize: 10,
},
loading: false,
searchText: "",
searchedColumn: "",
};
}
newProvider() {
const randomName = Setting.getRandomName();
return {
owner: "admin", // this.props.account.providername,
owner: this.state.owner,
name: `provider_${randomName}`,
createdTime: moment().format(),
displayName: `New Provider - ${randomName}`,
@@ -46,7 +61,7 @@ class ProviderListPage extends BaseListPage {
const newProvider = this.newProvider();
ProviderBackend.addProvider(newProvider)
.then((res) => {
this.props.history.push({pathname: `/providers/${newProvider.name}`, mode: "add"});
this.props.history.push({pathname: `/providers/${newProvider.owner}/${newProvider.name}`, mode: "add"});
}
)
.catch(error => {
@@ -177,7 +192,7 @@ class ProviderListPage extends BaseListPage {
render: (text, record, index) => {
return (
<div>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/providers/${record.name}`)}>{i18next.t("general:Edit")}</Button>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/providers/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
<Popconfirm
title={`Sure to delete provider: ${record.name} ?`}
onConfirm={() => this.deleteProvider(index)}
@@ -224,7 +239,8 @@ class ProviderListPage extends BaseListPage {
value = params.type;
}
this.setState({loading: true});
ProviderBackend.getProviders("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
(Setting.isAdminUser(this.props.account) ? ProviderBackend.getGlobalProviders(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
: ProviderBackend.getProviders(this.state.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder))
.then((res) => {
if (res.status === "ok") {
this.setState({

View File

@@ -65,21 +65,6 @@ class RoleListPage extends BaseListPage {
renderTable(roles) {
const columns = [
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
@@ -96,6 +81,21 @@ class RoleListPage extends BaseListPage {
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",

View File

@@ -88,21 +88,6 @@ class SyncerListPage extends BaseListPage {
renderTable(syncers) {
const columns = [
{
title: i18next.t("general:Organization"),
dataIndex: "organization",
key: "organization",
width: "120px",
sorter: true,
...this.getColumnSearchProps("organization"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
@@ -119,6 +104,21 @@ class SyncerListPage extends BaseListPage {
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "organization",
key: "organization",
width: "120px",
sorter: true,
...this.getColumnSearchProps("organization"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",

View File

@@ -67,21 +67,6 @@ class WebhookListPage extends BaseListPage {
renderTable(webhooks) {
const columns = [
{
title: i18next.t("general:Organization"),
dataIndex: "organization",
key: "organization",
width: "110px",
sorter: true,
...this.getColumnSearchProps("organization"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Name"),
dataIndex: "name",
@@ -98,6 +83,21 @@ class WebhookListPage extends BaseListPage {
);
},
},
{
title: i18next.t("general:Organization"),
dataIndex: "organization",
key: "organization",
width: "110px",
sorter: true,
...this.getColumnSearchProps("organization"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Created time"),
dataIndex: "createdTime",

View File

@@ -24,6 +24,16 @@ export function getProviders(owner, page = "", pageSize = "", field = "", value
}).then(res => res.json());
}
export function getGlobalProviders(page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
return fetch(`${Setting.ServerUrl}/api/get-global-providers?p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, {
method: "GET",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}
export function getProvider(owner, name) {
return fetch(`${Setting.ServerUrl}/api/get-provider?id=${owner}/${encodeURIComponent(name)}`, {
method: "GET",

View File

@@ -13,6 +13,7 @@
"Sync": "Sync"
},
"application": {
"Always": "Always",
"Auto signin": "Auto signin",
"Auto signin - Tooltip": "Auto signin - Tooltip",
"Background URL": "Background URL",
@@ -43,6 +44,7 @@
"Grant types - Tooltip": "Grant types - Tooltip",
"Left": "Left",
"New Application": "New Application",
"None": "None",
"Password ON": "Passwort AN",
"Password ON - Tooltip": "Whether to allow password login",
"Please select a HTML file": "Bitte wählen Sie eine HTML-Datei",
@@ -53,6 +55,7 @@
"Refresh token expire": "Aktualisierungs-Token läuft ab",
"Refresh token expire - Tooltip": "Aktualisierungs-Token läuft ab - Tooltip",
"Right": "Right",
"Rule": "Rule",
"SAML metadata": "SAML metadata",
"SAML metadata - Tooltip": "SAML metadata - Tooltip",
"SAML metadata URL copied to clipboard successfully": "SAML metadata URL copied to clipboard successfully",
@@ -67,10 +70,7 @@
"Token expire": "Token läuft ab",
"Token expire - Tooltip": "Token läuft ab - Tooltip",
"Token format": "Token-Format",
"Token format - Tooltip": "Token-Format - Tooltip",
"Rule": "Rule",
"None": "None",
"Always": "Always"
"Token format - Tooltip": "Token-Format - Tooltip"
},
"cert": {
"Bit size": "Bitgröße",
@@ -491,6 +491,7 @@
"New Provider": "New Provider",
"Parse": "Parse",
"Parse Metadata successfully": "Metadaten erfolgreich analysieren",
"Path prefix": "Path prefix",
"Port": "Port",
"Port - Tooltip": "Unique string-style identifier",
"Provider URL": "Provider-URL",
@@ -535,6 +536,7 @@
"Test Connection": "Test Smtp Connection",
"Test Email": "Test email config",
"Test Email - Tooltip": "Email Address",
"The prefix path of the file - Tooltip": "The prefix path of the file - Tooltip",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL - Tooltip",
"Type": "Typ",

View File

@@ -13,6 +13,7 @@
"Sync": "Sync"
},
"application": {
"Always": "Always",
"Auto signin": "Auto signin",
"Auto signin - Tooltip": "Auto signin - Tooltip",
"Background URL": "Background URL",
@@ -43,6 +44,7 @@
"Grant types - Tooltip": "Grant types - Tooltip",
"Left": "Left",
"New Application": "New Application",
"None": "None",
"Password ON": "Password ON",
"Password ON - Tooltip": "Password ON - Tooltip",
"Please select a HTML file": "Please select a HTML file",
@@ -53,6 +55,7 @@
"Refresh token expire": "Refresh token expire",
"Refresh token expire - Tooltip": "Refresh token expire - Tooltip",
"Right": "Right",
"Rule": "Rule",
"SAML metadata": "SAML metadata",
"SAML metadata - Tooltip": "SAML metadata - Tooltip",
"SAML metadata URL copied to clipboard successfully": "SAML metadata URL copied to clipboard successfully",
@@ -67,10 +70,7 @@
"Token expire": "Token expire",
"Token expire - Tooltip": "Token expire - Tooltip",
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip",
"Rule": "Rule",
"None": "None",
"Always": "Always"
"Token format - Tooltip": "Token format - Tooltip"
},
"cert": {
"Bit size": "Bit size",
@@ -491,6 +491,7 @@
"New Provider": "New Provider",
"Parse": "Parse",
"Parse Metadata successfully": "Parse Metadata successfully",
"Path prefix": "Path prefix",
"Port": "Port",
"Port - Tooltip": "Port - Tooltip",
"Provider URL": "Provider URL",
@@ -535,6 +536,7 @@
"Test Connection": "Test Connection",
"Test Email": "Test Email",
"Test Email - Tooltip": "Test Email - Tooltip",
"The prefix path of the file - Tooltip": "The prefix path of the file - Tooltip",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL - Tooltip",
"Type": "Type",

View File

@@ -13,6 +13,7 @@
"Sync": "Sync"
},
"application": {
"Always": "Always",
"Auto signin": "Auto signin",
"Auto signin - Tooltip": "Auto signin - Tooltip",
"Background URL": "Background URL",
@@ -43,6 +44,7 @@
"Grant types - Tooltip": "Grant types - Tooltip",
"Left": "Left",
"New Application": "New Application",
"None": "None",
"Password ON": "Mot de passe activé",
"Password ON - Tooltip": "Whether to allow password login",
"Please select a HTML file": "Veuillez sélectionner un fichier HTML",
@@ -53,6 +55,7 @@
"Refresh token expire": "Expiration du jeton d'actualisation",
"Refresh token expire - Tooltip": "Expiration du jeton d'actualisation - infobulle",
"Right": "Right",
"Rule": "Rule",
"SAML metadata": "SAML metadata",
"SAML metadata - Tooltip": "SAML metadata - Tooltip",
"SAML metadata URL copied to clipboard successfully": "SAML metadata URL copied to clipboard successfully",
@@ -67,10 +70,7 @@
"Token expire": "Expiration du jeton",
"Token expire - Tooltip": "Expiration du jeton - Info-bulle",
"Token format": "Format du jeton",
"Token format - Tooltip": "Format du jeton - infobulle",
"Rule": "Rule",
"None": "None",
"Always": "Always"
"Token format - Tooltip": "Format du jeton - infobulle"
},
"cert": {
"Bit size": "Taille du bit",
@@ -491,6 +491,7 @@
"New Provider": "New Provider",
"Parse": "Parse",
"Parse Metadata successfully": "Analyse des métadonnées réussie",
"Path prefix": "Path prefix",
"Port": "Port",
"Port - Tooltip": "Unique string-style identifier",
"Provider URL": "URL du fournisseur",
@@ -535,6 +536,7 @@
"Test Connection": "Test Smtp Connection",
"Test Email": "Test email config",
"Test Email - Tooltip": "Email Address",
"The prefix path of the file - Tooltip": "The prefix path of the file - Tooltip",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL - Tooltip",
"Type": "Type de texte",

View File

@@ -13,6 +13,7 @@
"Sync": "Sync"
},
"application": {
"Always": "Always",
"Auto signin": "Auto signin",
"Auto signin - Tooltip": "Auto signin - Tooltip",
"Background URL": "Background URL",
@@ -43,6 +44,7 @@
"Grant types - Tooltip": "Grant types - Tooltip",
"Left": "Left",
"New Application": "New Application",
"None": "None",
"Password ON": "パスワードON",
"Password ON - Tooltip": "Whether to allow password login",
"Please select a HTML file": "HTMLファイルを選択してください",
@@ -53,6 +55,7 @@
"Refresh token expire": "トークンの更新の期限が切れます",
"Refresh token expire - Tooltip": "トークンの有効期限を更新する - ツールチップ",
"Right": "Right",
"Rule": "Rule",
"SAML metadata": "SAML metadata",
"SAML metadata - Tooltip": "SAML metadata - Tooltip",
"SAML metadata URL copied to clipboard successfully": "SAML metadata URL copied to clipboard successfully",
@@ -67,10 +70,7 @@
"Token expire": "トークンの有効期限",
"Token expire - Tooltip": "トークンの有効期限 - ツールチップ",
"Token format": "トークンのフォーマット",
"Token format - Tooltip": "トークンフォーマット - ツールチップ",
"Rule": "Rule",
"None": "None",
"Always": "Always"
"Token format - Tooltip": "トークンフォーマット - ツールチップ"
},
"cert": {
"Bit size": "ビットサイズ",
@@ -491,6 +491,7 @@
"New Provider": "New Provider",
"Parse": "Parse",
"Parse Metadata successfully": "メタデータの解析に成功",
"Path prefix": "Path prefix",
"Port": "ポート",
"Port - Tooltip": "Unique string-style identifier",
"Provider URL": "プロバイダー URL",
@@ -535,6 +536,7 @@
"Test Connection": "Test Smtp Connection",
"Test Email": "Test email config",
"Test Email - Tooltip": "Email Address",
"The prefix path of the file - Tooltip": "The prefix path of the file - Tooltip",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL - Tooltip",
"Type": "タイプ",

View File

@@ -13,6 +13,7 @@
"Sync": "Sync"
},
"application": {
"Always": "Always",
"Auto signin": "Auto signin",
"Auto signin - Tooltip": "Auto signin - Tooltip",
"Background URL": "Background URL",
@@ -43,6 +44,7 @@
"Grant types - Tooltip": "Grant types - Tooltip",
"Left": "Left",
"New Application": "New Application",
"None": "None",
"Password ON": "Password ON",
"Password ON - Tooltip": "Whether to allow password login",
"Please select a HTML file": "Please select a HTML file",
@@ -53,6 +55,7 @@
"Refresh token expire": "Refresh token expire",
"Refresh token expire - Tooltip": "Refresh token expire - Tooltip",
"Right": "Right",
"Rule": "Rule",
"SAML metadata": "SAML metadata",
"SAML metadata - Tooltip": "SAML metadata - Tooltip",
"SAML metadata URL copied to clipboard successfully": "SAML metadata URL copied to clipboard successfully",
@@ -67,10 +70,7 @@
"Token expire": "Token expire",
"Token expire - Tooltip": "Token expire - Tooltip",
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip",
"Rule": "Rule",
"None": "None",
"Always": "Always"
"Token format - Tooltip": "Token format - Tooltip"
},
"cert": {
"Bit size": "Bit size",
@@ -491,6 +491,7 @@
"New Provider": "New Provider",
"Parse": "Parse",
"Parse Metadata successfully": "Parse Metadata successfully",
"Path prefix": "Path prefix",
"Port": "Port",
"Port - Tooltip": "Unique string-style identifier",
"Provider URL": "Provider URL",
@@ -535,6 +536,7 @@
"Test Connection": "Test Smtp Connection",
"Test Email": "Test email config",
"Test Email - Tooltip": "Email Address",
"The prefix path of the file - Tooltip": "The prefix path of the file - Tooltip",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL - Tooltip",
"Type": "Type",

View File

@@ -13,6 +13,7 @@
"Sync": "Sync"
},
"application": {
"Always": "Always",
"Auto signin": "Auto signin",
"Auto signin - Tooltip": "Auto signin - Tooltip",
"Background URL": "Background URL",
@@ -43,6 +44,7 @@
"Grant types - Tooltip": "Виды грантов - Подсказка",
"Left": "Left",
"New Application": "Новое приложение",
"None": "None",
"Password ON": "Пароль ВКЛ",
"Password ON - Tooltip": "Whether to allow password login",
"Please select a HTML file": "Пожалуйста, выберите HTML-файл",
@@ -53,6 +55,7 @@
"Refresh token expire": "Срок действия обновления токена истекает",
"Refresh token expire - Tooltip": "Срок обновления токена истекает - Подсказка",
"Right": "Right",
"Rule": "правило",
"SAML metadata": "Метаданные SAML",
"SAML metadata - Tooltip": "Метаданные SAML - Подсказка",
"SAML metadata URL copied to clipboard successfully": "Адрес метаданных SAML скопирован в буфер обмена",
@@ -67,10 +70,7 @@
"Token expire": "Токен истекает",
"Token expire - Tooltip": "Истек токен - Подсказка",
"Token format": "Формат токена",
"Token format - Tooltip": "Формат токена - Подсказка",
"Rule": "правило",
"None": "None",
"Always": "Always"
"Token format - Tooltip": "Формат токена - Подсказка"
},
"cert": {
"Bit size": "Размер бита",
@@ -491,6 +491,7 @@
"New Provider": "New Provider",
"Parse": "Parse",
"Parse Metadata successfully": "Анализ метаданных успешно завершен",
"Path prefix": "Path prefix",
"Port": "Порт",
"Port - Tooltip": "Unique string-style identifier",
"Provider URL": "URL провайдера",
@@ -535,6 +536,7 @@
"Test Connection": "Test Smtp Connection",
"Test Email": "Test email config",
"Test Email - Tooltip": "Email Address",
"The prefix path of the file - Tooltip": "The prefix path of the file - Tooltip",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL - Tooltip",
"Type": "Тип",

View File

@@ -13,6 +13,7 @@
"Sync": "同步"
},
"application": {
"Always": "始终开启",
"Auto signin": "启用自动登录",
"Auto signin - Tooltip": "当Casdoor存在已登录会话时自动采用该会话进行应用端的登录",
"Background URL": "背景图URL",
@@ -43,6 +44,7 @@
"Grant types - Tooltip": "选择允许哪些OAuth协议中的Grant types",
"Left": "居左",
"New Application": "添加应用",
"None": "关闭",
"Password ON": "开启密码",
"Password ON - Tooltip": "是否允许密码登录",
"Please select a HTML file": "请选择一个HTML文件",
@@ -53,6 +55,7 @@
"Refresh token expire": "Refresh Token过期",
"Refresh token expire - Tooltip": "Refresh Token过期时间",
"Right": "居右",
"Rule": "规则",
"SAML metadata": "SAML元数据",
"SAML metadata - Tooltip": "SAML协议的元数据Metadata信息",
"SAML metadata URL copied to clipboard successfully": "SAML元数据URL已成功复制到剪贴板",
@@ -67,10 +70,7 @@
"Token expire": "Access Token过期",
"Token expire - Tooltip": "Access Token过期时间",
"Token format": "Access Token格式",
"Token format - Tooltip": "Access Token格式",
"Rule": "规则",
"None": "关闭",
"Always": "始终开启"
"Token format - Tooltip": "Access Token格式"
},
"cert": {
"Bit size": "位大小",
@@ -491,6 +491,7 @@
"New Provider": "添加提供商",
"Parse": "Parse",
"Parse Metadata successfully": "解析元数据成功",
"Path prefix": "路径前缀",
"Port": "端口",
"Port - Tooltip": "端口号",
"Provider URL": "提供商URL",
@@ -535,6 +536,7 @@
"Test Connection": "测试SMTP连接",
"Test Email": "测试Email配置",
"Test Email - Tooltip": "邮箱地址",
"The prefix path of the file - Tooltip": "文件的路径前缀 - 工具提示",
"Token URL": "Token URL",
"Token URL - Tooltip": "Token URL - 工具提示",
"Type": "类型",