mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-22 18:25:47 +08:00
feat: add transaction pages (#2761)
This commit is contained in:
parent
ba1ddc7e50
commit
12acb24dbc
167
controllers/transaction.go
Normal file
167
controllers/transaction.go
Normal file
@ -0,0 +1,167 @@
|
||||
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/beego/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetTransactions
|
||||
// @Title GetTransactions
|
||||
// @Tag Transaction API
|
||||
// @Description get transactions
|
||||
// @Param owner query string true "The owner of transactions"
|
||||
// @Success 200 {array} object.Transaction The Response object
|
||||
// @router /get-transactions [get]
|
||||
func (c *ApiController) GetTransactions() {
|
||||
owner := c.Input().Get("owner")
|
||||
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 == "" {
|
||||
transactions, err := object.GetTransactions(owner)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(transactions)
|
||||
} else {
|
||||
limit := util.ParseInt(limit)
|
||||
count, err := object.GetTransactionCount(owner, field, value)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||
transactions, err := object.GetPaginationTransactions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(transactions, paginator.Nums())
|
||||
}
|
||||
}
|
||||
|
||||
// GetUserTransactions
|
||||
// @Title GetUserTransaction
|
||||
// @Tag Transaction API
|
||||
// @Description get transactions for a user
|
||||
// @Param owner query string true "The owner of transactions"
|
||||
// @Param organization query string true "The organization of the user"
|
||||
// @Param user query string true "The username of the user"
|
||||
// @Success 200 {array} object.Transaction The Response object
|
||||
// @router /get-user-transactions [get]
|
||||
func (c *ApiController) GetUserTransactions() {
|
||||
owner := c.Input().Get("owner")
|
||||
user := c.Input().Get("user")
|
||||
|
||||
transactions, err := object.GetUserTransactions(owner, user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(transactions)
|
||||
}
|
||||
|
||||
// GetTransaction
|
||||
// @Title GetTransaction
|
||||
// @Tag Transaction API
|
||||
// @Description get transaction
|
||||
// @Param id query string true "The id ( owner/name ) of the transaction"
|
||||
// @Success 200 {object} object.Transaction The Response object
|
||||
// @router /get-transaction [get]
|
||||
func (c *ApiController) GetTransaction() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
transaction, err := object.GetTransaction(id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.ResponseOk(transaction)
|
||||
}
|
||||
|
||||
// UpdateTransaction
|
||||
// @Title UpdateTransaction
|
||||
// @Tag Transaction API
|
||||
// @Description update transaction
|
||||
// @Param id query string true "The id ( owner/name ) of the transaction"
|
||||
// @Param body body object.Transaction true "The details of the transaction"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /update-transaction [post]
|
||||
func (c *ApiController) UpdateTransaction() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
var transaction object.Transaction
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.UpdateTransaction(id, &transaction))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// AddTransaction
|
||||
// @Title AddTransaction
|
||||
// @Tag Transaction API
|
||||
// @Description add transaction
|
||||
// @Param body body object.Transaction true "The details of the transaction"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /add-transaction [post]
|
||||
func (c *ApiController) AddTransaction() {
|
||||
var transaction object.Transaction
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.AddTransaction(&transaction))
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// DeleteTransaction
|
||||
// @Title DeleteTransaction
|
||||
// @Tag Transaction API
|
||||
// @Description delete transaction
|
||||
// @Param body body object.Transaction true "The details of the transaction"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /delete-transaction [post]
|
||||
func (c *ApiController) DeleteTransaction() {
|
||||
var transaction object.Transaction
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = wrapActionResponse(object.DeleteTransaction(&transaction))
|
||||
c.ServeJSON()
|
||||
}
|
@ -388,6 +388,11 @@ func (a *Ormer) createTable() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Transaction))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = a.Engine.Sync2(new(Syncer))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -221,6 +221,12 @@ func initAPI() {
|
||||
beego.Router("/api/add-subscription", &controllers.ApiController{}, "POST:AddSubscription")
|
||||
beego.Router("/api/delete-subscription", &controllers.ApiController{}, "POST:DeleteSubscription")
|
||||
|
||||
beego.Router("/api/get-transactions", &controllers.ApiController{}, "GET:GetTransactions")
|
||||
beego.Router("/api/get-transaction", &controllers.ApiController{}, "GET:GetTransaction")
|
||||
beego.Router("/api/update-transaction", &controllers.ApiController{}, "POST:UpdateTransaction")
|
||||
beego.Router("/api/add-transaction", &controllers.ApiController{}, "POST:AddTransaction")
|
||||
beego.Router("/api/delete-transaction", &controllers.ApiController{}, "POST:DeleteTransaction")
|
||||
|
||||
beego.Router("/api/get-system-info", &controllers.ApiController{}, "GET:GetSystemInfo")
|
||||
beego.Router("/api/get-version-info", &controllers.ApiController{}, "GET:GetVersionInfo")
|
||||
beego.Router("/api/health", &controllers.ApiController{}, "GET:Health")
|
||||
|
@ -90,6 +90,8 @@ import AccountAvatar from "./account/AccountAvatar";
|
||||
import {Content, Header} from "antd/es/layout/layout";
|
||||
import * as AuthBackend from "./auth/AuthBackend";
|
||||
import {clearWeb3AuthToken} from "./auth/Web3Auth";
|
||||
import TransactionListPage from "./TransactionListPage";
|
||||
import TransactionEditPage from "./TransactionEditPage";
|
||||
|
||||
function ManagementPage(props) {
|
||||
|
||||
@ -279,6 +281,7 @@ function ManagementPage(props) {
|
||||
Setting.getItem(<Link to="/plans">{i18next.t("general:Plans")}</Link>, "/plans"),
|
||||
Setting.getItem(<Link to="/pricings">{i18next.t("general:Pricings")}</Link>, "/pricings"),
|
||||
Setting.getItem(<Link to="/subscriptions">{i18next.t("general:Subscriptions")}</Link>, "/subscriptions"),
|
||||
Setting.getItem(<Link to="/transactions">{i18next.t("general:Transactions")}</Link>, "/transactions"),
|
||||
]));
|
||||
|
||||
if (Setting.isAdminUser(props.account)) {
|
||||
@ -365,6 +368,8 @@ function ManagementPage(props) {
|
||||
<Route exact path="/sysinfo" render={(props) => renderLoginIfNotLoggedIn(<SystemInfo account={account} {...props} />)} />
|
||||
<Route exact path="/syncers" render={(props) => renderLoginIfNotLoggedIn(<SyncerListPage account={account} {...props} />)} />
|
||||
<Route exact path="/syncers/:syncerName" render={(props) => renderLoginIfNotLoggedIn(<SyncerEditPage account={account} {...props} />)} />
|
||||
<Route exact path="/transactions" render={(props) => renderLoginIfNotLoggedIn(<TransactionListPage account={account} {...props} />)} />
|
||||
<Route exact path="/transactions/:organizationName/:transactionName" render={(props) => renderLoginIfNotLoggedIn(<TransactionEditPage account={account} {...props} />)} />
|
||||
<Route exact path="/webhooks" render={(props) => renderLoginIfNotLoggedIn(<WebhookListPage account={account} {...props} />)} />
|
||||
<Route exact path="/webhooks/:webhookName" render={(props) => renderLoginIfNotLoggedIn(<WebhookEditPage account={account} {...props} />)} />
|
||||
<Route exact path="/ldap/:organizationName/:ldapId" render={(props) => renderLoginIfNotLoggedIn(<LdapEditPage account={account} {...props} />)} />
|
||||
|
324
web/src/TransactionEditPage.js
Normal file
324
web/src/TransactionEditPage.js
Normal file
@ -0,0 +1,324 @@
|
||||
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import * as TransactionBackend from "./backend/TransactionBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import * as ApplicationBackend from "./backend/ApplicationBackend";
|
||||
import {Button, Card, Col, Input, Row} from "antd";
|
||||
import i18next from "i18next";
|
||||
|
||||
class TransactionEditPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
classes: props,
|
||||
organizationName: props.organizationName !== undefined ? props.organizationName : props.match.params.organizationName,
|
||||
transactionName: props.match.params.transactionName,
|
||||
application: null,
|
||||
transaction: null,
|
||||
providers: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
};
|
||||
}
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getTransaction();
|
||||
}
|
||||
|
||||
getTransaction() {
|
||||
TransactionBackend.getTransaction(this.state.organizationName, this.state.transactionName)
|
||||
.then((res) => {
|
||||
if (res.data === null) {
|
||||
this.props.history.push("/404");
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
transaction: res.data,
|
||||
});
|
||||
|
||||
Setting.scrollToDiv("invoice-area");
|
||||
});
|
||||
}
|
||||
|
||||
submitTransactionEdit(exitAfterSave) {
|
||||
const transaction = Setting.deepCopy(this.state.transaction);
|
||||
TransactionBackend.updateTransaction(this.state.transaction.owner, this.state.transactionName, transaction)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
this.setState({
|
||||
transactionName: this.state.transaction.name,
|
||||
});
|
||||
|
||||
if (exitAfterSave) {
|
||||
this.props.history.push("/transactions");
|
||||
} else {
|
||||
this.props.history.push(`/transactions/${this.state.organizationName}/${this.state.transaction.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
this.updatePaymentField("name", this.state.transactionName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
deleteTransaction() {
|
||||
TransactionBackend.deleteTransaction(this.state.transaction)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push("/transactions");
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
parseTransactionField(key, value) {
|
||||
if ([""].includes(key)) {
|
||||
value = Setting.myParseInt(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
getApplication() {
|
||||
ApplicationBackend.getApplication("admin", this.state.applicationName)
|
||||
.then((res) => {
|
||||
if (res.data === null) {
|
||||
this.props.history.push("/404");
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.status === "error") {
|
||||
Setting.showMessage("error", res.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
const application = res.data;
|
||||
if (application.grantTypes === null || application.grantTypes === undefined || application.grantTypes.length === 0) {
|
||||
application.grantTypes = ["authorization_code"];
|
||||
}
|
||||
|
||||
if (application.tags === null || application.tags === undefined) {
|
||||
application.tags = [];
|
||||
}
|
||||
|
||||
this.setState({
|
||||
application: application,
|
||||
});
|
||||
|
||||
this.getCerts(application.organization);
|
||||
|
||||
this.getSamlMetadata(application.enableSamlPostBinding);
|
||||
});
|
||||
}
|
||||
|
||||
renderTransaction() {
|
||||
return (
|
||||
<Card size="small" title={
|
||||
<div>
|
||||
{this.state.mode === "add" ? i18next.t("transaction:New Transaction") : i18next.t("transaction:Edit Transaction")}
|
||||
<Button onClick={() => this.submitTransactionEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitTransactionEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteTransaction()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.owner} onChange={e => {
|
||||
// this.updatePaymentField('organization', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.name} onChange={e => {
|
||||
// this.updatePaymentField('name', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.displayName} onChange={e => {
|
||||
this.updatePaymentField("displayName", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Provider"), i18next.t("general:Provider - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.provider} onChange={e => {
|
||||
// this.updatePaymentField('provider', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Category"), i18next.t("provider:Category - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.category} onChange={e => {
|
||||
this.updatePaymentField("displayName", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Type"), i18next.t("payment:Type - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.type} onChange={e => {
|
||||
// this.updatePaymentField('type', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("payment:Product"), i18next.t("payment:Product - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.productName} onChange={e => {
|
||||
// this.updatePaymentField('productName', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Detail"), i18next.t("product:Detail - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.detail} onChange={e => {
|
||||
// this.updatePaymentField('currency', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("user:Tag"), i18next.t("transaction:Tag - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.tag} onChange={e => {
|
||||
// this.updatePaymentField('currency', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("payment:Currency"), i18next.t("payment:Currency - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.currency} onChange={e => {
|
||||
// this.updatePaymentField('currency', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("transaction:Amount"), i18next.t("transaction:Amount - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.amount} onChange={e => {
|
||||
// this.updatePaymentField('amount', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("product:Return URL"), i18next.t("product:Return URL - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.user} onChange={e => {
|
||||
// this.updatePaymentField('amount', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:User"), i18next.t("general:User - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.user} onChange={e => {
|
||||
// this.updatePaymentField('amount', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Application"), i18next.t("general:Application - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.application} onChange={e => {
|
||||
// this.updatePaymentField('amount', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Payment"), i18next.t("general:Payment - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.payment} onChange={e => {
|
||||
// this.updatePaymentField('amount', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:State"), i18next.t("general:State - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input disabled={true} value={this.state.transaction.state} onChange={e => {
|
||||
// this.updatePaymentField('state', e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
this.state.transaction !== null ? this.renderTransaction() : null
|
||||
}
|
||||
<div style={{marginTop: "20px", marginLeft: "40px"}}>
|
||||
<Button size="large" onClick={() => this.submitTransactionEdit(false)}>{i18next.t("general:Save")}</Button>
|
||||
<Button style={{marginLeft: "20px"}} type="primary" size="large" onClick={() => this.submitTransactionEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} size="large" onClick={() => this.deleteTransaction()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TransactionEditPage;
|
333
web/src/TransactionListPage.js
Normal file
333
web/src/TransactionListPage.js
Normal file
@ -0,0 +1,333 @@
|
||||
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import i18next from "i18next";
|
||||
import {Link} from "react-router-dom";
|
||||
import * as Setting from "./Setting";
|
||||
import * as Provider from "./auth/Provider";
|
||||
import {Button, Table} from "antd";
|
||||
import PopconfirmModal from "./common/modal/PopconfirmModal";
|
||||
import React from "react";
|
||||
import * as TransactionBackend from "./backend/TransactionBackend";
|
||||
import moment from "moment/moment";
|
||||
|
||||
class TransactionListPage extends BaseListPage {
|
||||
newTransaction() {
|
||||
const randomName = Setting.getRandomName();
|
||||
const organizationName = Setting.getRequestOrganization(this.props.account);
|
||||
return {
|
||||
owner: organizationName,
|
||||
name: `transaction_${randomName}`,
|
||||
createdTime: moment().format(),
|
||||
displayName: `New Transaction - ${randomName}`,
|
||||
provider: "provider_pay_paypal",
|
||||
category: "",
|
||||
type: "PayPal",
|
||||
productName: "computer-1",
|
||||
productDisplayName: "A notebook computer",
|
||||
detail: "This is a computer with excellent CPU, memory and disk",
|
||||
tag: "Promotion-1",
|
||||
currency: "USD",
|
||||
amount: 0,
|
||||
returnUrl: "https://door.casdoor.com/transactions",
|
||||
user: "admin",
|
||||
application: "",
|
||||
payment: "payment_bhn1ra",
|
||||
state: "Paid",
|
||||
};
|
||||
}
|
||||
|
||||
deleteTransaction(i) {
|
||||
TransactionBackend.deleteTransaction(this.state.data[i])
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully deleted"));
|
||||
this.setState({
|
||||
data: Setting.deleteRow(this.state.data, i),
|
||||
pagination: {total: this.state.pagination.total - 1},
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
addTransaction() {
|
||||
const newTransaction = this.newTransaction();
|
||||
TransactionBackend.addTransaction(newTransaction)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/transactions/${newTransaction.owner}/${newTransaction.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
}
|
||||
}
|
||||
)
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}: ${error}`);
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(transactions) {
|
||||
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={`/transactions/${record.owner}/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Organization"),
|
||||
dataIndex: "owner",
|
||||
key: "owner",
|
||||
width: "120px",
|
||||
fixed: "left",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("owner"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/organizations/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Provider"),
|
||||
dataIndex: "provider",
|
||||
key: "provider",
|
||||
width: "150px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("provider"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/providers/${record.owner}/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:User"),
|
||||
dataIndex: "user",
|
||||
key: "user",
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("user"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/users/${record.owner}/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
dataIndex: "createdTime",
|
||||
key: "createdTime",
|
||||
width: "160px",
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("provider:Type"),
|
||||
dataIndex: "type",
|
||||
key: "type",
|
||||
width: "140px",
|
||||
align: "center",
|
||||
filterMultiple: false,
|
||||
filters: Setting.getProviderTypeOptions("Payment").map((o) => {return {text: o.id, value: o.name};}),
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
record.category = "Payment";
|
||||
return Provider.getProviderLogoWidget(record);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("payment:Product"),
|
||||
dataIndex: "productDisplayName",
|
||||
key: "productDisplayName",
|
||||
// width: '160px',
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("productDisplayName"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/products/${record.owner}/${record.productName}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("payment:Currency"),
|
||||
dataIndex: "currency",
|
||||
key: "currency",
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("currency"),
|
||||
},
|
||||
{
|
||||
title: i18next.t("transaction:Amount"),
|
||||
dataIndex: "amount",
|
||||
key: "amount",
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("amount"),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:User"),
|
||||
dataIndex: "user",
|
||||
key: "user",
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("user"),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Application"),
|
||||
dataIndex: "application",
|
||||
key: "application",
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("application"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/applications/${record.owner}/${record.application}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Payment"),
|
||||
dataIndex: "payment",
|
||||
key: "payment",
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("payment"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/payments/${record.owner}/${record.payment}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:State"),
|
||||
dataIndex: "state",
|
||||
key: "state",
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("state"),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
dataIndex: "",
|
||||
key: "op",
|
||||
width: "240px",
|
||||
fixed: (Setting.isMobile()) ? "false" : "right",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/transactions/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<PopconfirmModal
|
||||
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
|
||||
onConfirm={() => this.deleteTransaction(index)}
|
||||
>
|
||||
</PopconfirmModal>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const paginationProps = {
|
||||
total: this.state.pagination.total,
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table scroll={{x: "max-content"}} columns={columns} dataSource={transactions} rowKey={(record) => `${record.owner}/${record.name}`} size="middle" bordered pagination={paginationProps}
|
||||
title={() => (
|
||||
<div>
|
||||
{i18next.t("general:Transactions")}
|
||||
<Button type="primary" size="small" onClick={this.addTransaction.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||
</div>
|
||||
)}
|
||||
loading={this.state.loading}
|
||||
onChange={this.handleTableChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.type !== undefined && params.type !== null) {
|
||||
field = "type";
|
||||
value = params.type;
|
||||
}
|
||||
this.setState({loading: true});
|
||||
TransactionBackend.getTransactions(Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
});
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
data: res.data,
|
||||
pagination: {
|
||||
...params.pagination,
|
||||
total: res.data2,
|
||||
},
|
||||
searchText: params.searchText,
|
||||
searchedColumn: params.searchedColumn,
|
||||
});
|
||||
} else {
|
||||
if (Setting.isResponseDenied(res)) {
|
||||
this.setState({
|
||||
isAuthorized: false,
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default TransactionListPage;
|
71
web/src/backend/TransactionBackend.js
Normal file
71
web/src/backend/TransactionBackend.js
Normal file
@ -0,0 +1,71 @@
|
||||
// Copyright 2024 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as Setting from "../Setting";
|
||||
|
||||
export function getTransactions(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-transactions?owner=${owner}&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 getTransaction(owner, name) {
|
||||
return fetch(`${Setting.ServerUrl}/api/get-transaction?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function updateTransaction(owner, name, transaction) {
|
||||
const newTransaction = Setting.deepCopy(transaction);
|
||||
return fetch(`${Setting.ServerUrl}/api/update-transaction?id=${owner}/${encodeURIComponent(name)}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(newTransaction),
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function addTransaction(transaction) {
|
||||
const newTransaction = Setting.deepCopy(transaction);
|
||||
return fetch(`${Setting.ServerUrl}/api/add-transaction`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(newTransaction),
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function deleteTransaction(transaction) {
|
||||
const newTransaction = Setting.deepCopy(transaction);
|
||||
return fetch(`${Setting.ServerUrl}/api/delete-transaction`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
body: JSON.stringify(newTransaction),
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "Dies ist eine schreibgeschützte Demo-Seite!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Token",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token-Typ",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "Drittanbieter-Logins",
|
||||
"3rd-party logins - Tooltip": "Drittanbieter-Anmeldungen, die mit dem Benutzer verknüpft sind",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "¡Este es un sitio de demostración solo de lectura!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "Dirección URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Tipo de token",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "Inicio de sesión de terceros",
|
||||
"3rd-party logins - Tooltip": "Accesos sociales ligados por el usuario",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "Ceci est un site de démonstration en lecture seule !",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Jetons",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Infobulle",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Type de jeton",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "Services de connexions tiers",
|
||||
"3rd-party logins - Tooltip": "Service de connexions tiers liés au compte",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "Ini adalah situs demo hanya untuk dibaca saja!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Token-token",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Jenis token",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "Masuk pihak ketiga",
|
||||
"3rd-party logins - Tooltip": "Masuk sosial yang terhubung oleh pengguna",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "これは読み取り専用のデモサイトです!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "トークン",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "トークンタイプ",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "サードパーティログイン",
|
||||
"3rd-party logins - Tooltip": "ユーザーによってリンクされたソーシャルログイン",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "이것은 읽기 전용 데모 사이트입니다!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "토큰",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "토큰 유형",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "제3자 로그인",
|
||||
"3rd-party logins - Tooltip": "사용자가 연결한 소셜 로그인",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "Este é um site de demonstração apenas para leitura!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Tipo",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Tipo de Token",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "Logins de terceiros",
|
||||
"3rd-party logins - Tooltip": "Logins sociais vinculados pelo usuário",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "Это демонстрационный сайт только для чтения!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Токены",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Тип токена",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "Авторизация сторонних участников",
|
||||
"3rd-party logins - Tooltip": "Социальные логины, связанные пользователем",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "Bu site sadece görüntüleme amaçlıdır!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "This is a read-only demo site!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Tokens",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Token type",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "3rd-party logins",
|
||||
"3rd-party logins - Tooltip": "Social logins linked by the user",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "Đây là trang web giới thiệu chỉ có chức năng đọc!",
|
||||
"Timestamp": "Timestamp",
|
||||
"Tokens": "Mã thông báo",
|
||||
"Transactions": "Transactions",
|
||||
"Type": "Type",
|
||||
"Type - Tooltip": "Type - Tooltip",
|
||||
"URL": "URL",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "Loại mã thông báo",
|
||||
"Token type - Tooltip": "Token type - Tooltip"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "Amount",
|
||||
"Amount - Tooltip": "The amount of traded products",
|
||||
"Edit Transaction": "Edit Transaction",
|
||||
"New Transaction": "New Transaction",
|
||||
"Tag - Tooltip": "The tag of the transaction"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "Đăng nhập bên thứ ba",
|
||||
"3rd-party logins - Tooltip": "Đăng nhập xã hội liên kết bởi người dùng",
|
||||
|
@ -367,6 +367,7 @@
|
||||
"This is a read-only demo site!": "这是一个只读演示站点!",
|
||||
"Timestamp": "时间",
|
||||
"Tokens": "令牌",
|
||||
"Transactions": "交易",
|
||||
"Type": "类型",
|
||||
"Type - Tooltip": "类型",
|
||||
"URL": "链接",
|
||||
@ -1031,6 +1032,13 @@
|
||||
"Token type": "令牌类型",
|
||||
"Token type - Tooltip": "令牌类型"
|
||||
},
|
||||
"transaction": {
|
||||
"Amount": "数量",
|
||||
"Amount - Tooltip": "交易产品的数量",
|
||||
"Edit Transaction": "编辑交易",
|
||||
"New Transaction": "添加交易",
|
||||
"Tag - Tooltip": "交易的标签"
|
||||
},
|
||||
"user": {
|
||||
"3rd-party logins": "第三方登录",
|
||||
"3rd-party logins - Tooltip": "用户所绑定的社会化登录",
|
||||
|
Loading…
x
Reference in New Issue
Block a user