From eee9b8b9fe059850ff31cf109148f6010cd53408 Mon Sep 17 00:00:00 2001 From: Denis Plynskiy Date: Thu, 29 Jun 2023 20:32:34 +0300 Subject: [PATCH] feat: add organization context select box for admin (#2013) * feat: organization as context * feat: organization as context with backend filtration * Update app.conf * update app.conf and hide organization select for mobile. --------- Co-authored-by: dplynsky Co-authored-by: hsluoyz --- controllers/organization.go | 3 +- controllers/record.go | 4 +++ object/organization.go | 9 ++++-- web/src/AdapterListPage.js | 7 +++-- web/src/App.js | 17 +++++++++-- web/src/ApplicationListPage.js | 13 +++------ web/src/BaseListPage.js | 19 ++++++++++++ web/src/CertListPage.js | 8 ++++-- web/src/ChatListPage.js | 3 +- web/src/Conf.js | 5 ++++ web/src/GroupList.js | 5 ++-- web/src/MessageListPage.js | 5 ++-- web/src/ModelListPage.js | 5 ++-- web/src/OrganizationEditPage.js | 2 ++ web/src/OrganizationListPage.js | 9 ++++-- web/src/PaymentListPage.js | 5 ++-- web/src/PermissionListPage.js | 5 ++-- web/src/PlanListPage.js | 5 ++-- web/src/PricingListPage.js | 5 ++-- web/src/ProductEditPage.js | 15 ++++++++-- web/src/ProductListPage.js | 15 +++++----- web/src/ProviderListPage.js | 8 ++++-- web/src/RecordListPage.js | 2 +- web/src/ResourceListPage.js | 2 +- web/src/RoleListPage.js | 5 ++-- web/src/SessionListPage.js | 3 +- web/src/Setting.js | 25 ++++++++++++++++ web/src/SubscriptionListPage.js | 4 +-- web/src/SyncerListPage.js | 5 ++-- web/src/TokenListPage.js | 5 ++-- web/src/UserListPage.js | 4 +-- web/src/WebhookListPage.js | 5 ++-- web/src/backend/OrganizationBackend.js | 4 +-- web/src/backend/RecordBackend.js | 4 +-- web/src/common/select/OrganizationSelect.js | 32 +++++++++++++++++---- web/src/locales/de/data.json | 1 + web/src/locales/en/data.json | 1 + web/src/locales/es/data.json | 1 + web/src/locales/fr/data.json | 1 + web/src/locales/id/data.json | 1 + web/src/locales/ja/data.json | 1 + web/src/locales/ko/data.json | 1 + web/src/locales/pt/data.json | 1 + web/src/locales/ru/data.json | 1 + web/src/locales/vi/data.json | 1 + web/src/locales/zh/data.json | 1 + 46 files changed, 207 insertions(+), 76 deletions(-) diff --git a/controllers/organization.go b/controllers/organization.go index 7454f106..eb0c4f23 100644 --- a/controllers/organization.go +++ b/controllers/organization.go @@ -37,6 +37,7 @@ func (c *ApiController) GetOrganizations() { value := c.Input().Get("value") sortField := c.Input().Get("sortField") sortOrder := c.Input().Get("sortOrder") + organizationName := c.Input().Get("organizationName") isGlobalAdmin := c.IsGlobalAdmin() if limit == "" || page == "" { @@ -73,7 +74,7 @@ func (c *ApiController) GetOrganizations() { } paginator := pagination.SetPaginator(c.Ctx, limit, count) - organizations, err := object.GetMaskedOrganizations(object.GetPaginationOrganizations(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)) + organizations, err := object.GetMaskedOrganizations(object.GetPaginationOrganizations(owner, organizationName, paginator.Offset(), limit, field, value, sortField, sortOrder)) if err != nil { c.ResponseError(err.Error()) return diff --git a/controllers/record.go b/controllers/record.go index 046efac1..2a338291 100644 --- a/controllers/record.go +++ b/controllers/record.go @@ -42,6 +42,7 @@ func (c *ApiController) GetRecords() { value := c.Input().Get("value") sortField := c.Input().Get("sortField") sortOrder := c.Input().Get("sortOrder") + organizationName := c.Input().Get("organizationName") if limit == "" || page == "" { records, err := object.GetRecords() @@ -54,6 +55,9 @@ func (c *ApiController) GetRecords() { c.ServeJSON() } else { limit := util.ParseInt(limit) + if c.IsGlobalAdmin() && organizationName != "" { + organization = organizationName + } filterRecord := &object.Record{Organization: organization} count, err := object.GetRecordCount(field, value, filterRecord) if err != nil { diff --git a/object/organization.go b/object/organization.go index f00865b1..f0752544 100644 --- a/object/organization.go +++ b/object/organization.go @@ -104,10 +104,15 @@ func GetOrganizationsByFields(owner string, fields ...string) ([]*Organization, return organizations, nil } -func GetPaginationOrganizations(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Organization, error) { +func GetPaginationOrganizations(owner string, name string, offset, limit int, field, value, sortField, sortOrder string) ([]*Organization, error) { organizations := []*Organization{} session := GetSession(owner, offset, limit, field, value, sortField, sortOrder) - err := session.Find(&organizations) + var err error + if name != "" { + err = session.Find(&organizations, &Organization{Name: name}) + } else { + err = session.Find(&organizations) + } if err != nil { return nil, err } diff --git a/web/src/AdapterListPage.js b/web/src/AdapterListPage.js index adf6a9cd..094ca42a 100644 --- a/web/src/AdapterListPage.js +++ b/web/src/AdapterListPage.js @@ -25,8 +25,9 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class AdapterListPage extends BaseListPage { newAdapter() { const randomName = Setting.getRandomName(); + const owner = Setting.getRequestOrganization(this.props.account); return { - owner: this.props.account.owner, + owner: owner, name: `adapter_${randomName}`, createdTime: moment().format(), type: "Database", @@ -87,7 +88,7 @@ class AdapterListPage extends BaseListPage { ...this.getColumnSearchProps("name"), render: (text, record, index) => { return ( - + {text} ); @@ -246,7 +247,7 @@ class AdapterListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - AdapterBackend.getAdapters(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + AdapterBackend.getAdapters(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, diff --git a/web/src/App.js b/web/src/App.js index a0571fd5..77d04ade 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -86,6 +86,7 @@ import {withTranslation} from "react-i18next"; import ThemeSelect from "./common/select/ThemeSelect"; import SessionListPage from "./SessionListPage"; import MfaSetupPage from "./auth/MfaSetupPage"; +import OrganizationSelect from "./common/select/OrganizationSelect"; const {Header, Footer, Content} = Layout; @@ -398,6 +399,17 @@ class App extends Component { }); }} /> + {Setting.isAdminUser(this.state.account) && !Setting.isMobile() && + { + Setting.setOrganization(value); + }} + className="select-box" + /> + } ); } @@ -611,7 +623,7 @@ class App extends Component { this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> - this.renderLoginIfNotLoggedIn()} /> + this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> @@ -651,6 +663,7 @@ class App extends Component { this.props.history.push(key); } }; + const menuStyleRight = Setting.isAdminUser(this.state.account) && !Setting.isMobile() ? "calc(15% + 260px)" : "260px"; return (
@@ -680,7 +693,7 @@ class App extends Component { items={this.getMenuItems()} mode={"horizontal"} selectedKeys={[this.state.selectedMenuKey]} - style={{position: "absolute", left: "145px", right: "260px"}} + style={{position: "absolute", left: "145px", right: menuStyleRight}} /> } { diff --git a/web/src/ApplicationListPage.js b/web/src/ApplicationListPage.js index ffd303e6..79ecc472 100644 --- a/web/src/ApplicationListPage.js +++ b/web/src/ApplicationListPage.js @@ -28,18 +28,13 @@ class ApplicationListPage extends BaseListPage { super(props); } - componentDidMount() { - this.setState({ - organizationName: this.props.account.owner, - }); - } - newApplication() { const randomName = Setting.getRandomName(); + const organizationName = Setting.getRequestOrganization(this.props.account); return { owner: "admin", // this.props.account.applicationName, name: `application_${randomName}`, - organization: this.state.organizationName, + organization: organizationName, createdTime: moment().format(), displayName: `New Application - ${randomName}`, logo: `${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png`, @@ -273,8 +268,8 @@ class ApplicationListPage extends BaseListPage { const field = params.searchedColumn, value = params.searchText; const sortField = params.sortField, sortOrder = params.sortOrder; this.setState({loading: true}); - (Setting.isAdminUser(this.props.account) ? ApplicationBackend.getApplications("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) : - ApplicationBackend.getApplicationsByOrganization("admin", this.props.account.organization.name, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)) + (Setting.isDefaultOrganizationSelected(this.props.account) ? ApplicationBackend.getApplications("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) : + ApplicationBackend.getApplicationsByOrganization("admin", Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)) .then((res) => { this.setState({ loading: false, diff --git a/web/src/BaseListPage.js b/web/src/BaseListPage.js index f84b4837..d3596011 100644 --- a/web/src/BaseListPage.js +++ b/web/src/BaseListPage.js @@ -17,6 +17,9 @@ import {Button, Input, Result, Space} from "antd"; import {SearchOutlined} from "@ant-design/icons"; import Highlighter from "react-highlight-words"; import i18next from "i18next"; +import * as Setting from "./Setting"; +import * as Conf from "./Conf"; +import {DefaultOrganization} from "./Conf"; class BaseListPage extends React.Component { constructor(props) { @@ -35,6 +38,22 @@ class BaseListPage extends React.Component { }; } + handleOrganizationChange = () => { + const {pagination} = this.state; + this.fetch({pagination}); + }; + + componentDidMount() { + window.addEventListener(Conf.StorageOrganizationChangedEvent, this.handleOrganizationChange); + if (!Setting.isAdminUser(this.props.account)) { + Setting.setOrganization(DefaultOrganization); + } + } + + componentWillUnmount() { + window.removeEventListener(Conf.StorageOrganizationChangedEvent, this.handleOrganizationChange); + } + UNSAFE_componentWillMount() { const {pagination} = this.state; this.fetch({pagination}); diff --git a/web/src/CertListPage.js b/web/src/CertListPage.js index e8fcda01..4ae94cdc 100644 --- a/web/src/CertListPage.js +++ b/web/src/CertListPage.js @@ -28,6 +28,7 @@ class CertListPage extends BaseListPage { } componentDidMount() { + super.componentDidMount(); this.setState({ owner: Setting.isAdminUser(this.props.account) ? "admin" : this.props.account.owner, }); @@ -35,8 +36,9 @@ class CertListPage extends BaseListPage { newCert() { const randomName = Setting.getRandomName(); + const owner = Setting.isDefaultOrganizationSelected(this.props.account) ? this.state.owner : Setting.getRequestOrganization(this.props.account); return { - owner: this.state.owner, + owner: owner, name: `cert_${randomName}`, createdTime: moment().format(), displayName: `New Cert - ${randomName}`, @@ -236,8 +238,8 @@ class CertListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - (Setting.isAdminUser(this.props.account) ? CertBackend.getGlobleCerts(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) - : CertBackend.getCerts(this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)) + (Setting.isDefaultOrganizationSelected(this.props.account) ? CertBackend.getGlobleCerts(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + : CertBackend.getCerts(Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)) .then((res) => { this.setState({ loading: false, diff --git a/web/src/ChatListPage.js b/web/src/ChatListPage.js index 9d67cc01..cc4305cd 100644 --- a/web/src/ChatListPage.js +++ b/web/src/ChatListPage.js @@ -25,12 +25,13 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class ChatListPage extends BaseListPage { newChat() { const randomName = Setting.getRandomName(); + const organizationName = Setting.getRequestOrganization(this.props.account); return { owner: "admin", // this.props.account.applicationName, name: `chat_${randomName}`, createdTime: moment().format(), updatedTime: moment().format(), - organization: this.props.account.owner, + organization: organizationName, displayName: `New Chat - ${randomName}`, type: "Single", category: "Chat Category - 1", diff --git a/web/src/Conf.js b/web/src/Conf.js index facd254a..0f7fc335 100644 --- a/web/src/Conf.js +++ b/web/src/Conf.js @@ -32,3 +32,8 @@ export const ThemeDefault = { }; export const CustomFooter = null; + +export const DefaultOrganization = "All"; // i18next.t("organization:All") + +export const StorageOrganizationChangedEvent = "storageOrganizationChanged"; +export const StorageOrganizationsChangedEvent = "storageOrganizationsChanged"; diff --git a/web/src/GroupList.js b/web/src/GroupList.js index 32b13a4a..bf1ee389 100644 --- a/web/src/GroupList.js +++ b/web/src/GroupList.js @@ -49,8 +49,9 @@ class GroupListPage extends BaseListPage { newGroup() { const randomName = Setting.getRandomName(); + const owner = Setting.getRequestOrganization(this.props.account); return { - owner: this.props.account.owner, + owner: owner, name: `group_${randomName}`, createdTime: moment().format(), updatedTime: moment().format(), @@ -251,7 +252,7 @@ class GroupListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - GroupBackend.getGroups(this.state.owner, false, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + GroupBackend.getGroups(Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), false, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) .then((res) => { this.setState({ loading: false, diff --git a/web/src/MessageListPage.js b/web/src/MessageListPage.js index b46f14d6..b45ae312 100644 --- a/web/src/MessageListPage.js +++ b/web/src/MessageListPage.js @@ -25,11 +25,12 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class MessageListPage extends BaseListPage { newMessage() { const randomName = Setting.getRandomName(); + const organizationName = Setting.getRequestOrganization(this.props.account); return { owner: "admin", // this.props.account.messagename, name: `message_${randomName}`, createdTime: moment().format(), - organization: this.props.account.owner, + organization: organizationName, chat: "", replyTo: "", author: `${this.props.account.owner}/${this.props.account.name}`, @@ -208,7 +209,7 @@ class MessageListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - MessageBackend.getMessages("admin", Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + MessageBackend.getMessages("admin", 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, diff --git a/web/src/ModelListPage.js b/web/src/ModelListPage.js index 9e01aa9b..5d72e6a4 100644 --- a/web/src/ModelListPage.js +++ b/web/src/ModelListPage.js @@ -40,8 +40,9 @@ m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`; class ModelListPage extends BaseListPage { newModel() { const randomName = Setting.getRandomName(); + const owner = Setting.getRequestOrganization(this.props.account); return { - owner: this.props.account.owner, + owner: owner, name: `model_${randomName}`, createdTime: moment().format(), displayName: `New Model - ${randomName}`, @@ -202,7 +203,7 @@ class ModelListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - ModelBackend.getModels(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + ModelBackend.getModels(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, diff --git a/web/src/OrganizationEditPage.js b/web/src/OrganizationEditPage.js index 7e4fbab1..f63076b9 100644 --- a/web/src/OrganizationEditPage.js +++ b/web/src/OrganizationEditPage.js @@ -427,6 +427,7 @@ class OrganizationEditPage extends React.Component { this.setState({ organizationName: this.state.organization.name, }); + window.dispatchEvent(new Event(Conf.StorageOrganizationsChangedEvent)); if (willExist) { this.props.history.push("/organizations"); @@ -448,6 +449,7 @@ class OrganizationEditPage extends React.Component { .then((res) => { if (res.status === "ok") { this.props.history.push("/organizations"); + window.dispatchEvent(new Event(Conf.StorageOrganizationsChangedEvent)); } else { Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`); } diff --git a/web/src/OrganizationListPage.js b/web/src/OrganizationListPage.js index 5a121fb8..e7f3d2d6 100644 --- a/web/src/OrganizationListPage.js +++ b/web/src/OrganizationListPage.js @@ -21,6 +21,7 @@ import * as OrganizationBackend from "./backend/OrganizationBackend"; import i18next from "i18next"; import BaseListPage from "./BaseListPage"; import PopconfirmModal from "./common/modal/PopconfirmModal"; +import * as Conf from "./Conf"; class OrganizationListPage extends BaseListPage { newOrganization() { @@ -83,6 +84,7 @@ class OrganizationListPage extends BaseListPage { if (res.status === "ok") { this.props.history.push({pathname: `/organizations/${newOrganization.name}`, mode: "add"}); Setting.showMessage("success", i18next.t("general:Successfully added")); + window.dispatchEvent(new Event(Conf.StorageOrganizationsChangedEvent)); } else { Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`); } @@ -99,8 +101,11 @@ class OrganizationListPage extends BaseListPage { Setting.showMessage("success", i18next.t("general:Successfully deleted")); this.setState({ data: Setting.deleteRow(this.state.data, i), - pagination: {total: this.state.pagination.total - 1}, + pagination: { + ...this.state.pagination, + total: this.state.pagination.total - 1}, }); + window.dispatchEvent(new Event(Conf.StorageOrganizationsChangedEvent)); } else { Setting.showMessage("error", `${i18next.t("general:Failed to delete")}: ${res.msg}`); } @@ -275,7 +280,7 @@ class OrganizationListPage extends BaseListPage { value = params.passwordType; } this.setState({loading: true}); - OrganizationBackend.getOrganizations("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + OrganizationBackend.getOrganizations("admin", 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, diff --git a/web/src/PaymentListPage.js b/web/src/PaymentListPage.js index e4fc2baf..fdd7ec84 100644 --- a/web/src/PaymentListPage.js +++ b/web/src/PaymentListPage.js @@ -26,6 +26,7 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class PaymentListPage extends BaseListPage { newPayment() { const randomName = Setting.getRandomName(); + const organizationName = Setting.getRequestOrganization(this.props.account); return { owner: "admin", name: `payment_${randomName}`, @@ -33,7 +34,7 @@ class PaymentListPage extends BaseListPage { displayName: `New Payment - ${randomName}`, provider: "provider_pay_paypal", type: "PayPal", - organization: this.props.account.owner, + organization: organizationName, user: "admin", productName: "computer-1", productDisplayName: "A notebook computer", @@ -265,7 +266,7 @@ class PaymentListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - PaymentBackend.getPayments("admin", Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + PaymentBackend.getPayments("admin", 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, diff --git a/web/src/PermissionListPage.js b/web/src/PermissionListPage.js index 00bbddaf..a1b9951b 100644 --- a/web/src/PermissionListPage.js +++ b/web/src/PermissionListPage.js @@ -26,8 +26,9 @@ import {UploadOutlined} from "@ant-design/icons"; class PermissionListPage extends BaseListPage { newPermission() { const randomName = Setting.getRandomName(); + const owner = Setting.getRequestOrganization(this.props.account); return { - owner: this.props.account.owner, + owner: owner, name: `permission_${randomName}`, createdTime: moment().format(), displayName: `New Permission - ${randomName}`, @@ -383,7 +384,7 @@ class PermissionListPage extends BaseListPage { this.setState({loading: true}); const getPermissions = Setting.isLocalAdminUser(this.props.account) ? PermissionBackend.getPermissions : PermissionBackend.getPermissionsBySubmitter; - getPermissions(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + getPermissions(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, diff --git a/web/src/PlanListPage.js b/web/src/PlanListPage.js index 2ff5ecd3..cdcae64c 100644 --- a/web/src/PlanListPage.js +++ b/web/src/PlanListPage.js @@ -25,8 +25,7 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class PlanListPage extends BaseListPage { newPlan() { const randomName = Setting.getRandomName(); - const owner = (this.state.organizationName !== undefined) ? this.state.organizationName : this.props.account.owner; - + const owner = Setting.getRequestOrganization(this.props.account); return { owner: owner, name: `plan_${randomName}`, @@ -219,7 +218,7 @@ class PlanListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - PlanBackend.getPlans(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + PlanBackend.getPlans(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, diff --git a/web/src/PricingListPage.js b/web/src/PricingListPage.js index 8a4c43b8..a6317921 100644 --- a/web/src/PricingListPage.js +++ b/web/src/PricingListPage.js @@ -25,8 +25,7 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class PricingListPage extends BaseListPage { newPricing() { const randomName = Setting.getRandomName(); - const owner = (this.state.organizationName !== undefined) ? this.state.organizationName : this.props.account.owner; - + const owner = Setting.getRequestOrganization(this.props.account); return { owner: owner, name: `pricing_${randomName}`, @@ -188,7 +187,7 @@ class PricingListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - PricingBackend.getPricings(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + PricingBackend.getPricings(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, diff --git a/web/src/ProductEditPage.js b/web/src/ProductEditPage.js index c7b22eeb..2ca26b96 100644 --- a/web/src/ProductEditPage.js +++ b/web/src/ProductEditPage.js @@ -20,6 +20,7 @@ import i18next from "i18next"; import {LinkOutlined} from "@ant-design/icons"; import * as ProviderBackend from "./backend/ProviderBackend"; import ProductBuyPage from "./ProductBuyPage"; +import * as OrganizationBackend from "./backend/OrganizationBackend"; const {Option} = Select; @@ -39,11 +40,12 @@ class ProductEditPage extends React.Component { UNSAFE_componentWillMount() { this.getProduct(); + this.getOrganizations(); this.getPaymentProviders(); } getProduct() { - ProductBackend.getProduct(this.props.account.owner, this.state.productName) + ProductBackend.getProduct(this.state.organizationName, this.state.productName) .then((product) => { if (product === null) { this.props.history.push("/404"); @@ -56,6 +58,15 @@ class ProductEditPage extends React.Component { }); } + getOrganizations() { + OrganizationBackend.getOrganizations("admin") + .then((res) => { + this.setState({ + organizations: (res.msg === undefined) ? res : [], + }); + }); + } + getPaymentProviders() { ProviderBackend.getProviders(this.props.account.owner) .then((res) => { @@ -312,7 +323,7 @@ class ProductEditPage extends React.Component { if (willExist) { this.props.history.push("/products"); } else { - this.props.history.push(`/products/${this.state.product.name}`); + this.props.history.push(`/products/${this.state.product.owner}/${this.state.product.name}`); } } else { Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`); diff --git a/web/src/ProductListPage.js b/web/src/ProductListPage.js index 2ea02b32..9966bb7b 100644 --- a/web/src/ProductListPage.js +++ b/web/src/ProductListPage.js @@ -26,8 +26,9 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class ProductListPage extends BaseListPage { newProduct() { const randomName = Setting.getRandomName(); + const owner = Setting.getRequestOrganization(this.props.account); return { - owner: this.props.account.owner, + owner: owner, name: `product_${randomName}`, createdTime: moment().format(), displayName: `New Product - ${randomName}`, @@ -47,7 +48,7 @@ class ProductListPage extends BaseListPage { ProductBackend.addProduct(newProduct) .then((res) => { if (res.status === "ok") { - this.props.history.push({pathname: `/products/${newProduct.name}`, mode: "add"}); + this.props.history.push({pathname: `/products/${newProduct.owner}/${newProduct.name}`, mode: "add"}); Setting.showMessage("success", i18next.t("general:Successfully added")); } else { Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`); @@ -88,7 +89,7 @@ class ProductListPage extends BaseListPage { ...this.getColumnSearchProps("name"), render: (text, record, index) => { return ( - + {text} ); @@ -201,7 +202,7 @@ class ProductListPage extends BaseListPage { size="small" locale={{emptyText: " "}} dataSource={providers} - renderItem={(providerName, i) => { + renderItem={(providerName, record, i) => { return (
@@ -247,7 +248,7 @@ class ProductListPage extends BaseListPage { return (
- + this.deleteProduct(index)} @@ -268,7 +269,7 @@ class ProductListPage extends BaseListPage { return (
- `${record.owner}/${record.name}`} size="middle" bordered pagination={paginationProps} title={() => (
{i18next.t("general:Products")}     @@ -290,7 +291,7 @@ class ProductListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - ProductBackend.getProducts(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + ProductBackend.getProducts(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, diff --git a/web/src/ProviderListPage.js b/web/src/ProviderListPage.js index 136e3efb..ad604e69 100644 --- a/web/src/ProviderListPage.js +++ b/web/src/ProviderListPage.js @@ -29,6 +29,7 @@ class ProviderListPage extends BaseListPage { } componentDidMount() { + super.componentDidMount(); this.setState({ owner: Setting.isAdminUser(this.props.account) ? "admin" : this.props.account.owner, }); @@ -36,8 +37,9 @@ class ProviderListPage extends BaseListPage { newProvider() { const randomName = Setting.getRandomName(); + const owner = Setting.isDefaultOrganizationSelected(this.props.account) ? this.state.owner : Setting.getRequestOrganization(); return { - owner: this.state.owner, + owner: owner, name: `provider_${randomName}`, createdTime: moment().format(), displayName: `New Provider - ${randomName}`, @@ -256,8 +258,8 @@ class ProviderListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - (Setting.isAdminUser(this.props.account) ? ProviderBackend.getGlobalProviders(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) - : ProviderBackend.getProviders(this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)) + (Setting.isDefaultOrganizationSelected(this.props.account) ? ProviderBackend.getGlobalProviders(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + : ProviderBackend.getProviders(Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)) .then((res) => { this.setState({ loading: false, diff --git a/web/src/RecordListPage.js b/web/src/RecordListPage.js index 8966dc3e..f2b2b41e 100644 --- a/web/src/RecordListPage.js +++ b/web/src/RecordListPage.js @@ -209,7 +209,7 @@ class RecordListPage extends BaseListPage { value = params.method; } this.setState({loading: true}); - RecordBackend.getRecords(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + RecordBackend.getRecords(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, diff --git a/web/src/ResourceListPage.js b/web/src/ResourceListPage.js index 2923ee2d..6e8da11d 100644 --- a/web/src/ResourceListPage.js +++ b/web/src/ResourceListPage.js @@ -309,7 +309,7 @@ class ResourceListPage extends BaseListPage { const field = params.searchedColumn, value = params.searchText; const sortField = params.sortField, sortOrder = params.sortOrder; this.setState({loading: true}); - ResourceBackend.getResources(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, this.props.account.name, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + ResourceBackend.getResources(Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), this.props.account.name, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) .then((res) => { this.setState({ loading: false, diff --git a/web/src/RoleListPage.js b/web/src/RoleListPage.js index 987a6bb1..2ff9798b 100644 --- a/web/src/RoleListPage.js +++ b/web/src/RoleListPage.js @@ -26,8 +26,9 @@ import {UploadOutlined} from "@ant-design/icons"; class RoleListPage extends BaseListPage { newRole() { const randomName = Setting.getRandomName(); + const owner = Setting.getRequestOrganization(this.props.account); return { - owner: this.props.account.owner, + owner: owner, name: `role_${randomName}`, createdTime: moment().format(), displayName: `New Role - ${randomName}`, @@ -258,7 +259,7 @@ class RoleListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - RoleBackend.getRoles(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + RoleBackend.getRoles(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, diff --git a/web/src/SessionListPage.js b/web/src/SessionListPage.js index bc1dd964..053c6865 100644 --- a/web/src/SessionListPage.js +++ b/web/src/SessionListPage.js @@ -22,7 +22,6 @@ import * as SessionBackend from "./backend/SessionBackend"; import PopconfirmModal from "./common/modal/PopconfirmModal"; class SessionListPage extends BaseListPage { - deleteSession(i) { SessionBackend.deleteSession(this.state.data[i]) .then((res) => { @@ -134,7 +133,7 @@ class SessionListPage extends BaseListPage { value = params.contentType; } this.setState({loading: true}); - SessionBackend.getSessions(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + SessionBackend.getSessions(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, diff --git a/web/src/Setting.js b/web/src/Setting.js index d924ade2..6219961d 100644 --- a/web/src/Setting.js +++ b/web/src/Setting.js @@ -25,6 +25,7 @@ import {Helmet} from "react-helmet"; import * as Conf from "./Conf"; import * as phoneNumber from "libphonenumber-js"; import moment from "moment"; +import {DefaultOrganization} from "./Conf"; const {Option} = Select; @@ -1164,3 +1165,27 @@ export function inIframe() { return true; } } + +export function getOrganization() { + const organization = localStorage.getItem("organization"); + return organization !== null ? organization : DefaultOrganization; +} + +export function setOrganization(organization) { + localStorage.setItem("organization", organization); + window.dispatchEvent(new Event(Conf.StorageOrganizationChangedEvent)); +} + +export function getRequestOrganization(account) { + if (isAdminUser(account)) { + return getOrganization() === DefaultOrganization ? account.owner : getOrganization(); + } + return account.owner; +} + +export function isDefaultOrganizationSelected(account) { + if (isAdminUser(account)) { + return getOrganization() === DefaultOrganization; + } + return false; +} diff --git a/web/src/SubscriptionListPage.js b/web/src/SubscriptionListPage.js index 10d0dd2d..92b4319b 100644 --- a/web/src/SubscriptionListPage.js +++ b/web/src/SubscriptionListPage.js @@ -25,7 +25,7 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class SubscriptionListPage extends BaseListPage { newSubscription() { const randomName = Setting.getRandomName(); - const owner = (this.state.organizationName !== undefined) ? this.state.organizationName : this.props.account.owner; + const owner = Setting.getRequestOrganization(this.props.account); const defaultDuration = 365; return { @@ -237,7 +237,7 @@ class SubscriptionListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - SubscriptionBackend.getSubscriptions(Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + SubscriptionBackend.getSubscriptions(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, diff --git a/web/src/SyncerListPage.js b/web/src/SyncerListPage.js index f62ab2a6..79c02647 100644 --- a/web/src/SyncerListPage.js +++ b/web/src/SyncerListPage.js @@ -25,11 +25,12 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class SyncerListPage extends BaseListPage { newSyncer() { const randomName = Setting.getRandomName(); + const organizationName = Setting.getRequestOrganization(this.props.account); return { owner: "admin", name: `syncer_${randomName}`, createdTime: moment().format(), - organization: this.props.account.owner, + organization: organizationName, type: "Database", host: "localhost", port: 3306, @@ -276,7 +277,7 @@ class SyncerListPage extends BaseListPage { value = params.type; } this.setState({loading: true}); - SyncerBackend.getSyncers("admin", Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + SyncerBackend.getSyncers("admin", 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, diff --git a/web/src/TokenListPage.js b/web/src/TokenListPage.js index 5b02f9cb..059c7948 100644 --- a/web/src/TokenListPage.js +++ b/web/src/TokenListPage.js @@ -25,12 +25,13 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class TokenListPage extends BaseListPage { newToken() { const randomName = Setting.getRandomName(); + const organizationName = Setting.getRequestOrganization(this.props.account); return { owner: "admin", // this.props.account.tokenname, name: `token_${randomName}`, createdTime: moment().format(), application: "app-built-in", - organization: this.props.account.owner, + organization: organizationName, user: "admin", accessToken: "", expiresIn: 7200, @@ -240,7 +241,7 @@ class TokenListPage extends BaseListPage { const field = params.searchedColumn, value = params.searchText; const sortField = params.sortField, sortOrder = params.sortOrder; this.setState({loading: true}); - TokenBackend.getTokens("admin", Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + TokenBackend.getTokens("admin", 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, diff --git a/web/src/UserListPage.js b/web/src/UserListPage.js index c2df6777..abf14e18 100644 --- a/web/src/UserListPage.js +++ b/web/src/UserListPage.js @@ -61,7 +61,7 @@ class UserListPage extends BaseListPage { newUser() { const randomName = Setting.getRandomName(); - const owner = this.state.organizationName; + const owner = Setting.isDefaultOrganizationSelected(this.props.account) ? this.state.organizationName : Setting.getRequestOrganization(this.props.account); return { owner: owner, name: `user_${randomName}`, @@ -456,7 +456,7 @@ class UserListPage extends BaseListPage { const sortField = params.sortField, sortOrder = params.sortOrder; this.setState({loading: true}); if (this.props.match?.path === "/users") { - (Setting.isAdminUser(this.props.account) ? UserBackend.getGlobalUsers(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) : UserBackend.getUsers(this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)) + (Setting.isDefaultOrganizationSelected(this.props.account) ? UserBackend.getGlobalUsers(params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) : UserBackend.getUsers(Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)) .then((res) => { this.setState({ loading: false, diff --git a/web/src/WebhookListPage.js b/web/src/WebhookListPage.js index 58a3b6e8..a409af55 100644 --- a/web/src/WebhookListPage.js +++ b/web/src/WebhookListPage.js @@ -25,11 +25,12 @@ import PopconfirmModal from "./common/modal/PopconfirmModal"; class WebhookListPage extends BaseListPage { newWebhook() { const randomName = Setting.getRandomName(); + const organizationName = Setting.getRequestOrganization(this.props.account); return { owner: "admin", // this.props.account.webhookname, name: `webhook_${randomName}`, createdTime: moment().format(), - organization: this.props.account.owner, + organization: organizationName, url: "https://example.com/callback", method: "POST", contentType: "application/json", @@ -240,7 +241,7 @@ class WebhookListPage extends BaseListPage { value = params.contentType; } this.setState({loading: true}); - WebhookBackend.getWebhooks("admin", Setting.isAdminUser(this.props.account) ? "" : this.props.account.owner, params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder) + WebhookBackend.getWebhooks("admin", 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, diff --git a/web/src/backend/OrganizationBackend.js b/web/src/backend/OrganizationBackend.js index d7655edf..d541b7a3 100644 --- a/web/src/backend/OrganizationBackend.js +++ b/web/src/backend/OrganizationBackend.js @@ -14,8 +14,8 @@ import * as Setting from "../Setting"; -export function getOrganizations(owner, page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") { - return fetch(`${Setting.ServerUrl}/api/get-organizations?owner=${owner}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, { +export function getOrganizations(owner, organizationName = "", page = "", pageSize = "", field = "", value = "", sortField = "", sortOrder = "") { + return fetch(`${Setting.ServerUrl}/api/get-organizations?owner=${owner}&organizationName=${organizationName}&p=${page}&pageSize=${pageSize}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, { method: "GET", credentials: "include", headers: { diff --git a/web/src/backend/RecordBackend.js b/web/src/backend/RecordBackend.js index fff5da4e..bcc5b574 100644 --- a/web/src/backend/RecordBackend.js +++ b/web/src/backend/RecordBackend.js @@ -14,8 +14,8 @@ import * as Setting from "../Setting"; -export function getRecords(page, pageSize, field = "", value = "", sortField = "", sortOrder = "") { - return fetch(`${Setting.ServerUrl}/api/get-records?pageSize=${pageSize}&p=${page}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, { +export function getRecords(organizationName, page, pageSize, field = "", value = "", sortField = "", sortOrder = "") { + return fetch(`${Setting.ServerUrl}/api/get-records?organizationName=${organizationName}&pageSize=${pageSize}&p=${page}&field=${field}&value=${value}&sortField=${sortField}&sortOrder=${sortOrder}`, { method: "GET", credentials: "include", headers: { diff --git a/web/src/common/select/OrganizationSelect.js b/web/src/common/select/OrganizationSelect.js index 06a7d0b8..b7102be9 100644 --- a/web/src/common/select/OrganizationSelect.js +++ b/web/src/common/select/OrganizationSelect.js @@ -17,9 +17,10 @@ import {Select} from "antd"; import i18next from "i18next"; import * as OrganizationBackend from "../../backend/OrganizationBackend"; import * as Setting from "../../Setting"; +import * as Conf from "../../Conf"; function OrganizationSelect(props) { - const {onChange, initValue, style, onSelect} = props; + const {onChange, initValue, style, onSelect, withAll, className} = props; const [organizations, setOrganizations] = React.useState([]); const [value, setValue] = React.useState(initValue); @@ -27,15 +28,20 @@ function OrganizationSelect(props) { if (props.organizations === undefined) { getOrganizations(); } - }, []); + window.addEventListener(Conf.StorageOrganizationsChangedEvent, getOrganizations); + return function() { + window.removeEventListener(Conf.StorageOrganizationsChangedEvent, getOrganizations); + }; + }, [value]); const getOrganizations = () => { OrganizationBackend.getOrganizationNames("admin") .then((res) => { if (res.status === "ok") { setOrganizations(res.data); - if (initValue === undefined) { - setValue(organizations.length > 0 ? organizations[0] : ""); + const selectedValueExist = res.data.filter(organization => organization.name === value).length > 0; + if (initValue === undefined || !selectedValueExist) { + handleOnChange(getOrganizationItems().length > 0 ? getOrganizationItems()[0].value : ""); } } }); @@ -46,9 +52,24 @@ function OrganizationSelect(props) { onChange?.(value); }; + const getOrganizationItems = () => { + const items = []; + + organizations.forEach((organization) => items.push(Setting.getOption(organization.displayName, organization.name))); + + if (withAll) { + items.unshift({ + label: i18next.t(`organization:${Conf.DefaultOrganization}`), + value: Conf.DefaultOrganization, + }); + } + + return items; + }; + return ( ); diff --git a/web/src/locales/de/data.json b/web/src/locales/de/data.json index 7b8cf1bd..c28b5d2c 100644 --- a/web/src/locales/de/data.json +++ b/web/src/locales/de/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "Konto Items", "Account items - Tooltip": "Elemente auf der persönlichen Einstellungsseite", + "All": "Alle", "Edit Organization": "Organisation bearbeiten", "Follow global theme": "Folge dem globalen Theme", "Init score": "Initialer Score", diff --git a/web/src/locales/en/data.json b/web/src/locales/en/data.json index 302c478a..9614254f 100644 --- a/web/src/locales/en/data.json +++ b/web/src/locales/en/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "Account items", "Account items - Tooltip": "Items in the Personal settings page", + "All": "All", "Edit Organization": "Edit Organization", "Follow global theme": "Follow global theme", "Init score": "Init score", diff --git a/web/src/locales/es/data.json b/web/src/locales/es/data.json index 30051940..9303daea 100644 --- a/web/src/locales/es/data.json +++ b/web/src/locales/es/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "Elementos de la cuenta", "Account items - Tooltip": "Elementos en la página de configuración personal", + "All": "Toda", "Edit Organization": "Editar organización", "Follow global theme": "Seguir el tema global", "Init score": "Puntuación de inicio", diff --git a/web/src/locales/fr/data.json b/web/src/locales/fr/data.json index 6ca30999..2f029445 100644 --- a/web/src/locales/fr/data.json +++ b/web/src/locales/fr/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "Articles de compte", "Account items - Tooltip": "Éléments de la page des paramètres personnels", + "All": "Tout", "Edit Organization": "Modifier l'organisation", "Follow global theme": "Suivre le thème global", "Init score": "Score initial", diff --git a/web/src/locales/id/data.json b/web/src/locales/id/data.json index dc8b9bdd..a1aef057 100644 --- a/web/src/locales/id/data.json +++ b/web/src/locales/id/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "Item akun", "Account items - Tooltip": "Item pada halaman pengaturan personal", + "All": "Semua", "Edit Organization": "Edit Organisasi", "Follow global theme": "Ikuti tema global", "Init score": "Skor awal", diff --git a/web/src/locales/ja/data.json b/web/src/locales/ja/data.json index 388ebe99..c531a142 100644 --- a/web/src/locales/ja/data.json +++ b/web/src/locales/ja/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "アカウントアイテム", "Account items - Tooltip": "個人設定ページのアイテム", + "All": "全て", "Edit Organization": "組織の編集", "Follow global theme": "グローバルテーマに従ってください", "Init score": "イニットスコア", diff --git a/web/src/locales/ko/data.json b/web/src/locales/ko/data.json index f95ed65b..62d40868 100644 --- a/web/src/locales/ko/data.json +++ b/web/src/locales/ko/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "계정 항목들", "Account items - Tooltip": "개인 설정 페이지의 항목들", + "All": "모두", "Edit Organization": "단체 수정", "Follow global theme": "글로벌 테마를 따르세요", "Init score": "처음 점수", diff --git a/web/src/locales/pt/data.json b/web/src/locales/pt/data.json index f00b170c..e6ea369d 100644 --- a/web/src/locales/pt/data.json +++ b/web/src/locales/pt/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "Itens da Conta", "Account items - Tooltip": "Itens na página de Configurações Pessoais", + "All": "Todos", "Edit Organization": "Editar Organização", "Follow global theme": "Seguir tema global", "Init score": "Pontuação inicial", diff --git a/web/src/locales/ru/data.json b/web/src/locales/ru/data.json index 6ceebd89..482f393d 100644 --- a/web/src/locales/ru/data.json +++ b/web/src/locales/ru/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "Элементы учета", "Account items - Tooltip": "Элементы на странице личных настроек", + "All": "Все", "Edit Organization": "Редактировать организацию", "Follow global theme": "Следуйте глобальной теме", "Init score": "Начальный балл", diff --git a/web/src/locales/vi/data.json b/web/src/locales/vi/data.json index c20b4855..180255c0 100644 --- a/web/src/locales/vi/data.json +++ b/web/src/locales/vi/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "Mục tài khoản", "Account items - Tooltip": "Các mục trong trang Cài đặt cá nhân", + "All": "Tất cả", "Edit Organization": "Chỉnh sửa tổ chức", "Follow global theme": "Theo chủ đề toàn cầu", "Init score": "Điểm khởi tạo", diff --git a/web/src/locales/zh/data.json b/web/src/locales/zh/data.json index 42ebcda6..cae0e6a5 100644 --- a/web/src/locales/zh/data.json +++ b/web/src/locales/zh/data.json @@ -467,6 +467,7 @@ "organization": { "Account items": "个人页设置项", "Account items - Tooltip": "用户的个人设置页面中可配置的选项", + "All": "全部", "Edit Organization": "编辑组织", "Follow global theme": "使用全局默认主题", "Init score": "初始积分",