From b7ee9c6bcfb3d0858936eb4e1e179aa553f9d081 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Fri, 30 May 2025 23:30:19 +0500 Subject: [PATCH 01/13] Add trasns for Environments List and Table --- .../packages/lowcoder/src/i18n/locales/en.ts | 34 +++++++++++++++++- .../setting/environments/EnvironmentsList.tsx | 17 ++++----- .../components/EnvironmentsTable.tsx | 35 ++++++++++--------- 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 190fa053a..fe02321f5 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2551,8 +2551,40 @@ export const en = { "EnvironmentsFeature2": "Deployment of applications, data sources, and configurations between environments, directly from the UI.", "EnvironmentsFeature3": "Environment-specific access controls and visibility rules.", "EnvironmentsFeature5": "Clear separation of concerns for staging, sandbox, and production operations.", - }, + // Environments page translations + "environments": { + "title": "Environments", + "search": "Search", + "refresh": "Refresh", + "addEnvironment": "Add Environment", + "errorLoadingEnvironments": "Error loading environments", + "noEnvironmentsFoundMatching": "No environments found matching \"{searchText}\"", + "noEnvironmentsFound": "No environments found. Create your first environment to get started.", + "environmentsTypeLabel": "{type} Environments", + "showingAllEnvironments": "Showing all {count} environments", + "unnamedEnvironment": "Unnamed Environment", + "masterEnvironment": "Master Environment", + "viewAuditLogs": "View Audit Logs", + "id": "ID", + "domain": "Domain", + "master": "Master", + "license": "License", + "apiCalls": "API Calls", + "yes": "Yes", + "no": "No", + "copyId": "Copy ID", + "copied": "Copied!", + "percentUsed": "{percent}% used", + "licenseStatus": { + "checking": "Checking...", + "licensed": "Licensed", + "unlicensed": "License Required", + "error": "Setup Required", + "unknown": "Unknown" + } + } + }, "subscription": { "details": "Subscription Details", "productDetails": "Product Details", diff --git a/client/packages/lowcoder/src/pages/setting/environments/EnvironmentsList.tsx b/client/packages/lowcoder/src/pages/setting/environments/EnvironmentsList.tsx index 36be33166..b46381511 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/EnvironmentsList.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/EnvironmentsList.tsx @@ -13,6 +13,7 @@ import StatsCard from "./components/StatsCard"; import { buildEnvironmentId } from "@lowcoder-ee/constants/routesURL"; import { createEnvironment } from "./services/environments.service"; import { getEnvironmentTagColor } from "./utils/environmentUtils"; +import { trans } from "i18n"; import styled from "styled-components"; const EnvironmentsWrapper = styled.div` @@ -157,9 +158,9 @@ const EnvironmentsList: React.FC = () => { return ( - Environments + {trans("enterprise.environments.title")} setSearchText(e.target.value)} style={{ width: "192px", height: "32px", margin: "0 12px 0 0" }} @@ -169,14 +170,14 @@ const EnvironmentsList: React.FC = () => { icon={} onClick={handleRefresh} > - Refresh + {trans("enterprise.environments.refresh")} } onClick={() => setIsCreateModalVisible(true)} > - Add Environment + {trans("enterprise.environments.addEnvironment")} @@ -187,7 +188,7 @@ const EnvironmentsList: React.FC = () => { {environmentStats.map(([type, count]) => ( { {error && ( { {!isLoading && !error && filteredEnvironments.length === 0 && searchText && ( )} {!isLoading && !error && environments.length === 0 && !searchText && ( )} diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx index 2336c8d5d..81f777188 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentsTable.tsx @@ -4,6 +4,7 @@ import { EditOutlined, AuditOutlined, LinkOutlined, EnvironmentOutlined, StarFil import { Environment } from '../types/environment.types'; import { getEnvironmentTagColor, formatEnvironmentType } from '../utils/environmentUtils'; import { getAPICallsStatusColor } from '../services/license.service'; +import { trans } from 'i18n'; const { Text, Title } = Typography; @@ -56,35 +57,35 @@ const EnvironmentsTable: React.FC = ({ return { icon: , color: '#40a9ff', - text: 'Checking...', + text: trans("enterprise.environments.licenseStatus.checking"), status: 'processing' as const }; case 'licensed': return { icon: , color: '#73d13d', - text: 'Licensed', + text: trans("enterprise.environments.licenseStatus.licensed"), status: 'success' as const }; case 'unlicensed': return { icon: , color: '#ff7875', - text: 'License Required', + text: trans("enterprise.environments.licenseStatus.unlicensed"), status: 'warning' as const }; case 'error': return { icon: , color: '#ffc53d', - text: 'Setup Required', + text: trans("enterprise.environments.licenseStatus.error"), status: 'warning' as const }; default: return { icon: , color: '#d9d9d9', - text: 'Unknown', + text: trans("enterprise.environments.licenseStatus.unknown"), status: 'default' as const }; } @@ -163,9 +164,9 @@ const EnvironmentsTable: React.FC = ({ />
- {env.environmentName || 'Unnamed Environment'} + {env.environmentName || trans("enterprise.environments.unnamedEnvironment")} {env.isMaster && ( - <Tooltip title="Master Environment"> + <Tooltip title={trans("enterprise.environments.masterEnvironment")}> <StarFilled style={{ color: '#faad14', marginLeft: '6px', fontSize: '12px' }} /> </Tooltip> )} @@ -192,7 +193,7 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({ {/* Only show audit button for licensed environments */} {isAccessible && ( <div> - <Tooltip title="View Audit Logs" placement="top"> + <Tooltip title={trans("enterprise.environments.viewAuditLogs")} placement="top"> <Button type="text" icon={<AuditOutlined />} @@ -214,9 +215,9 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({ <div style={{ padding: '8px 0', borderTop: '1px solid #f5f5f5' }}> <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> - <Text type="secondary" style={{ fontSize: '12px' }}>ID:</Text> + <Text type="secondary" style={{ fontSize: '12px' }}>{trans("enterprise.environments.id")}:</Text> {isAccessible ? ( - <Text style={{ fontSize: '12px', fontFamily: 'monospace' }} copyable={{ tooltips: ['Copy ID', 'Copied!'] }}> + <Text style={{ fontSize: '12px', fontFamily: 'monospace' }} copyable={{ tooltips: [trans("enterprise.environments.copyId"), trans("enterprise.environments.copied")] }}> {env.environmentId} </Text> ) : ( @@ -227,7 +228,7 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({ </div> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> - <Text type="secondary" style={{ fontSize: '12px' }}>Domain:</Text> + <Text type="secondary" style={{ fontSize: '12px' }}>{trans("enterprise.environments.domain")}:</Text> {env.environmentFrontendUrl ? ( isAccessible ? ( <a @@ -251,14 +252,14 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({ </div> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> - <Text type="secondary" style={{ fontSize: '12px' }}>Master:</Text> + <Text type="secondary" style={{ fontSize: '12px' }}>{trans("enterprise.environments.master")}:</Text> <Text style={{ fontSize: '12px' }}> - {env.isMaster ? 'Yes' : 'No'} + {env.isMaster ? trans("enterprise.environments.yes") : trans("enterprise.environments.no")} </Text> </div> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}> - <Text type="secondary" style={{ fontSize: '12px' }}>License:</Text> + <Text type="secondary" style={{ fontSize: '12px' }}>{trans("enterprise.environments.license")}:</Text> <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}> <span style={{ color: licenseDisplay.color, fontSize: '12px' }}> {licenseDisplay.icon} @@ -275,7 +276,7 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '6px' }}> <Text type="secondary" style={{ fontSize: '11px' }}> <ApiOutlined style={{ marginRight: '4px' }} /> - API Calls + {trans("enterprise.environments.apiCalls")} </Text> </div> @@ -295,7 +296,7 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({ fontSize: '10px', color: '#8c8c8c' }}> - <span>{env.licenseDetails.apiCallsUsage || 0}% used</span> + <span>{trans("enterprise.environments.percentUsed", { percent: env.licenseDetails.apiCallsUsage || 0 })}</span> </div> </div> )} @@ -310,7 +311,7 @@ const EnvironmentsTable: React.FC<EnvironmentsTableProps> = ({ {environments.length > 10 && ( <div style={{ textAlign: 'center', margin: '16px 0' }}> <Text type="secondary" style={{ fontSize: '13px' }}> - Showing all {environments.length} environments + {trans("enterprise.environments.showingAllEnvironments", { count: environments.length })} </Text> </div> )} From e920c684d8fa9a159effbb364f3d210b1901ed6d Mon Sep 17 00:00:00 2001 From: Faran Javed <faran1997@outlook.com> Date: Fri, 30 May 2025 23:38:02 +0500 Subject: [PATCH 02/13] Add trans for Create Env Modal --- .../packages/lowcoder/src/i18n/locales/en.ts | 84 ++++++++++++++++++- .../components/CreateEnvironmentModal.tsx | 59 ++++++------- 2 files changed, 112 insertions(+), 31 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index fe02321f5..85b72168f 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2499,7 +2499,7 @@ export const en = { "API100k": "100,000 API Calls — $100", "API1M": "1,000,000 API Calls — $1,000", "API10M": "10,000,000 API Calls — $10,000", - "UsageOverrunDesc": "When your API package runs low, we’ll alert you. Once the package is consumed, your instance remains functional but will operate at a reduced speed to prevent abuse and maintain fairness.", + "UsageOverrunDesc": "When your API package runs low, we'll alert you. Once the package is consumed, your instance remains functional but will operate at a reduced speed to prevent abuse and maintain fairness.", "UsageTopUpInfo": "You can seamlessly add additional packages anytime to ensure continuous, fast access — no service interruptions.", "AppUsageTitle": "App Usage Logs", "AppUsageIntroTitle": "Understand how your apps are used", @@ -2531,7 +2531,7 @@ export const en = { "BrandingPagesIntro2": "These touchpoints help deliver a fully branded experience even during unexpected scenarios or account transitions.", "BrandingMetaIntro": "Define standard metadata like page title and description to improve your SEO presence and brand messaging.", "BrandingHelpLinksIntro": "Add context-sensitive documentation links directly inside the app, providing just-in-time help to your users.", - "BrandingWhatsNewIntro": "Activate the 'What’s New' section to highlight updates and product announcements in a branded and visible manner.", + "BrandingWhatsNewIntro": "Activate the 'What's New' section to highlight updates and product announcements in a branded and visible manner.", "EnvironmentsIntroTitle": "Lowcoder Staging", "EnvironmentsTitle" : "Multi-Environment Infrastructure", @@ -2582,6 +2582,86 @@ export const en = { "unlicensed": "License Required", "error": "Setup Required", "unknown": "Unknown" + }, + "detail": { + "environmentNotFound": "Environment Not Found", + "returnToEnvironmentsList": "Return to Environments List", + "environmentDetail": "Environment Detail", + "environmentOverview": "Environment Overview", + "noDomainSet": "No domain set", + "environmentId": "Environment ID", + "licenseStatus": "License Status", + "licenseNeeded": "License Needed", + "setupRequired": "Setup Required", + "created": "Created", + "unknown": "Unknown", + "licenseDetails": "License Details", + "apiCallsRemaining": "API Calls Remaining", + "totalApiCallsLimit": "Total API Calls Limit", + "enterpriseEdition": "Enterprise Edition", + "active": "Active", + "inactive": "Inactive", + "licenseInformation": "License Information", + "calls": "calls", + "licenses": "Licenses", + "license": "License", + "workspaces": "Workspaces", + "userGroups": "User Groups", + "type": "Type", + "status": "Status", + "licensed": "Licensed", + "unlicensed": "Unlicensed", + "apiKey": "API Key", + "configured": "Configured", + "notSet": "Not Set", + "masterEnv": "Master Env" + }, + "unlicensed": { + "unlicensedDescription": "This environment needs a valid license to unlock its full capabilities and features. Please make sure your API Service URL is correctly configured and Plugin is installed.", + "errorDescription": "We encountered an issue while checking the license. Please review the configuration settings.", + "defaultDescription": "This environment requires license configuration to proceed.", + "contactLowcoderTeam": "Contact Lowcoder Team", + "editEnvironment": "Edit Environment", + "backToEnvironments": "Back to Environments", + "helpText": "Need assistance? Contact our team for licensing support or edit the environment configuration to resolve this issue.", + "type": "Type", + "status": "Status", + "masterEnv": "Master Env", + "licenseIssue": "License Issue", + "error": "Error", + "missing": "Missing" + }, + "error": { + "itemNotFound": "The item you're looking for doesn't exist or you don't have permission to view it." + }, + "modal": { + "createNewEnvironment": "Create New Environment", + "cancel": "Cancel", + "createEnvironment": "Create Environment", + "environmentName": "Environment Name", + "pleaseEnterName": "Please enter a name", + "nameMinLength": "Name must be at least 2 characters", + "enterEnvironmentName": "Enter environment name", + "description": "Description", + "enterDescription": "Enter description", + "stage": "Stage", + "pleaseSelectStage": "Please select a stage", + "selectStage": "Select stage", + "development": "Development (DEV)", + "testing": "Testing (TEST)", + "preProduction": "Pre-Production (PREPROD)", + "production": "Production (PROD)", + "frontendUrl": "Frontend URL", + "pleaseEnterValidUrl": "Please enter a valid URL", + "apiServiceUrl": "API Service URL", + "nodeServiceUrl": "Node Service URL", + "apiKey": "API Key", + "enterApiKey": "Enter API key", + "masterEnvironment": "Master Environment", + "alreadyMasterEnvironment": "{name} is already the Master environment", + "willBeMaster": "Will be Master", + "configurationRequirements": "Configuration Requirements", + "configurationRequirementsDesc": "Ensure that the API Service URL is configured and correct, the API key is valid, and for license verification make sure you have both the license and plugin properly installed." } } }, diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/CreateEnvironmentModal.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/CreateEnvironmentModal.tsx index 8a6132c0a..170128f7a 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/CreateEnvironmentModal.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/CreateEnvironmentModal.tsx @@ -3,6 +3,7 @@ import { Modal, Form, Input, Select, Switch, Button, Alert, Tooltip } from 'antd import { useSelector } from 'react-redux'; import { selectMasterEnvironment, selectHasMasterEnvironment } from 'redux/selectors/enterpriseSelectors'; import { Environment } from '../types/environment.types'; +import { trans } from 'i18n'; const { Option } = Select; @@ -66,14 +67,14 @@ const CreateEnvironmentModal: React.FC<CreateEnvironmentModalProps> = ({ return ( <Modal - title="Create New Environment" + title={trans("enterprise.environments.modal.createNewEnvironment")} open={visible} onCancel={handleCancel} maskClosable={true} destroyOnHidden={true} footer={[ <Button key="back" onClick={handleCancel}> - Cancel + {trans("enterprise.environments.modal.cancel")} </Button>, <Button key="submit" @@ -81,7 +82,7 @@ const CreateEnvironmentModal: React.FC<CreateEnvironmentModalProps> = ({ loading={loading || submitLoading} onClick={handleSubmit} > - Create Environment + {trans("enterprise.environments.modal.createEnvironment")} </Button> ]} > @@ -95,43 +96,43 @@ const CreateEnvironmentModal: React.FC<CreateEnvironmentModalProps> = ({ > <Form.Item name="environmentName" - label="Environment Name" + label={trans("enterprise.environments.modal.environmentName")} rules={[ - { required: true, message: 'Please enter a name' }, - { min: 2, message: 'Name must be at least 2 characters' } + { required: true, message: trans("enterprise.environments.modal.pleaseEnterName") }, + { min: 2, message: trans("enterprise.environments.modal.nameMinLength") } ]} > - <Input placeholder="Enter environment name" /> + <Input placeholder={trans("enterprise.environments.modal.enterEnvironmentName")} /> </Form.Item> <Form.Item name="environmentDescription" - label="Description" + label={trans("enterprise.environments.modal.description")} > <Input.TextArea - placeholder="Enter description" + placeholder={trans("enterprise.environments.modal.enterDescription")} rows={3} /> </Form.Item> <Form.Item name="environmentType" - label="Stage" - rules={[{ required: true, message: 'Please select a stage' }]} + label={trans("enterprise.environments.modal.stage")} + rules={[{ required: true, message: trans("enterprise.environments.modal.pleaseSelectStage") }]} > - <Select placeholder="Select stage"> - <Option value="DEV">Development (DEV)</Option> - <Option value="TEST">Testing (TEST)</Option> - <Option value="PREPROD">Pre-Production (PREPROD)</Option> - <Option value="PROD">Production (PROD)</Option> + <Select placeholder={trans("enterprise.environments.modal.selectStage")}> + <Option value="DEV">{trans("enterprise.environments.modal.development")}</Option> + <Option value="TEST">{trans("enterprise.environments.modal.testing")}</Option> + <Option value="PREPROD">{trans("enterprise.environments.modal.preProduction")}</Option> + <Option value="PROD">{trans("enterprise.environments.modal.production")}</Option> </Select> </Form.Item> <Form.Item name="environmentFrontendUrl" - label="Frontend URL" + label={trans("enterprise.environments.modal.frontendUrl")} rules={[ - { type: 'url', message: 'Please enter a valid URL' } + { type: 'url', message: trans("enterprise.environments.modal.pleaseEnterValidUrl") } ]} > <Input placeholder="https://example.com" /> @@ -139,9 +140,9 @@ const CreateEnvironmentModal: React.FC<CreateEnvironmentModalProps> = ({ <Form.Item name="environmentApiServiceUrl" - label="API Service URL" + label={trans("enterprise.environments.modal.apiServiceUrl")} rules={[ - { type: 'url', message: 'Please enter a valid URL' } + { type: 'url', message: trans("enterprise.environments.modal.pleaseEnterValidUrl") } ]} > <Input placeholder="https://api.example.com" /> @@ -149,9 +150,9 @@ const CreateEnvironmentModal: React.FC<CreateEnvironmentModalProps> = ({ <Form.Item name="environmentNodeServiceUrl" - label="Node Service URL" + label={trans("enterprise.environments.modal.nodeServiceUrl")} rules={[ - { type: 'url', message: 'Please enter a valid URL' } + { type: 'url', message: trans("enterprise.environments.modal.pleaseEnterValidUrl") } ]} > <Input placeholder="https://node.example.com" /> @@ -159,20 +160,20 @@ const CreateEnvironmentModal: React.FC<CreateEnvironmentModalProps> = ({ <Form.Item name="environmentApikey" - label="API Key" + label={trans("enterprise.environments.modal.apiKey")} > <Input.TextArea - placeholder="Enter API key" + placeholder={trans("enterprise.environments.modal.enterApiKey")} rows={2} /> </Form.Item> - <Form.Item label="Master Environment"> + <Form.Item label={trans("enterprise.environments.modal.masterEnvironment")}> <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}> <Tooltip title={ hasMasterEnvironment - ? `${masterEnvironment?.environmentName} is already the Master environment` + ? trans("enterprise.environments.modal.alreadyMasterEnvironment", { name: masterEnvironment?.environmentName }) : '' } > @@ -185,15 +186,15 @@ const CreateEnvironmentModal: React.FC<CreateEnvironmentModalProps> = ({ </Tooltip> {isMaster && ( <span style={{ color: '#52c41a', fontSize: '12px' }}> - Will be Master + {trans("enterprise.environments.modal.willBeMaster")} </span> )} </div> </Form.Item> <Alert - message="Configuration Requirements" - description="Ensure that the API Service URL is configured and correct, the API key is valid, and for license verification make sure you have both the license and plugin properly installed." + message={trans("enterprise.environments.modal.configurationRequirements")} + description={trans("enterprise.environments.modal.configurationRequirementsDesc")} type="warning" showIcon style={{ marginTop: '16px' }} From 7fc77166393568f48a116edbdc4e392066278af5 Mon Sep 17 00:00:00 2001 From: Faran Javed <faran1997@outlook.com> Date: Fri, 30 May 2025 23:38:27 +0500 Subject: [PATCH 03/13] add trans for error component --- .../pages/setting/environments/components/ErrorComponent.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/ErrorComponent.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/ErrorComponent.tsx index 2f4d5fbac..e2015059d 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/ErrorComponent.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/ErrorComponent.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { Card, Button, Typography } from 'antd'; import { HomeOutlined } from '@ant-design/icons'; import history from '@lowcoder-ee/util/history'; +import { trans } from 'i18n'; const { Title, Text } = Typography; @@ -20,7 +21,7 @@ const ErrorComponent: React.FC<ErrorComponentProps> = ({ errorMessage, returnPat {errorMessage} - The item you're looking for doesn't exist or you don't have permission to view it. + {trans("enterprise.environments.error.itemNotFound")}
@@ -233,7 +234,7 @@ const UnlicensedEnvironmentView: React.FC = ({ display: 'block', lineHeight: '1.5' }}> - Need assistance? Contact our team for licensing support or edit the environment configuration to resolve this issue. + {trans("enterprise.environments.unlicensed.helpText")} From 352d715d5c6032bb24d80defaab94a5b656788ed Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Fri, 30 May 2025 23:42:42 +0500 Subject: [PATCH 05/13] Add trans for Environment Detail Page --- .../environments/EnvironmentDetail.tsx | 73 ++++++++++--------- .../components/EnvironmentHeader.tsx | 11 +-- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx b/client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx index 2a52b1826..f9495a05d 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/EnvironmentDetail.tsx @@ -46,6 +46,7 @@ import { getEnvironmentTagColor } from "./utils/environmentUtils"; import { formatAPICalls, getAPICallsStatusColor } from "./services/license.service"; import ErrorComponent from './components/ErrorComponent'; import { Level1SettingPageContent } from "../styled"; +import { trans } from "i18n"; /** * Environment Detail Page Component @@ -105,9 +106,9 @@ const EnvironmentDetail: React.FC = () => { if (error || !environment) { return ( ); } @@ -138,26 +139,26 @@ const EnvironmentDetail: React.FC = () => { // Stats data for the cards const statsData = [ { - title: "Type", - value: environment.environmentType || "Unknown", + title: trans("enterprise.environments.detail.type"), + value: environment.environmentType || trans("enterprise.environments.detail.unknown"), icon: , color: getEnvironmentTagColor(environment.environmentType) }, { - title: "Status", - value: environment.isLicensed ? "Licensed" : "Unlicensed", + title: trans("enterprise.environments.detail.status"), + value: environment.isLicensed ? trans("enterprise.environments.detail.licensed") : trans("enterprise.environments.detail.unlicensed"), icon: environment.isLicensed ? : , color: environment.isLicensed ? "#52c41a" : "#ff4d4f" }, { - title: "API Key", - value: environment.environmentApikey ? "Configured" : "Not Set", + title: trans("enterprise.environments.detail.apiKey"), + value: environment.environmentApikey ? trans("enterprise.environments.detail.configured") : trans("enterprise.environments.detail.notSet"), icon: , color: environment.environmentApikey ? "#1890ff" : "#faad14" }, { - title: "Master Env", - value: environment.isMaster ? "Yes" : "No", + title: trans("enterprise.environments.detail.masterEnv"), + value: environment.isMaster ? trans("enterprise.environments.yes") : trans("enterprise.environments.no"), icon: , color: environment.isMaster ? "#722ed1" : "#8c8c8c" } @@ -168,7 +169,7 @@ const EnvironmentDetail: React.FC = () => { key: 'workspaces', label: ( - Workspaces + {trans("enterprise.environments.detail.workspaces")} ), children: @@ -177,7 +178,7 @@ const EnvironmentDetail: React.FC = () => { key: 'userGroups', label: ( - User Groups + {trans("enterprise.environments.detail.userGroups")} ), children: @@ -192,12 +193,12 @@ const EnvironmentDetail: React.FC = () => { items={[ { key: 'environments', - title: 'Environments', + title: trans("enterprise.environments.title"), onClick: () => history.push('/setting/environments') }, { key: 'current', - title: environment.environmentName || "Environment Detail" + title: environment.environmentName || trans("enterprise.environments.detail.environmentDetail") } ]} /> @@ -224,7 +225,7 @@ const EnvironmentDetail: React.FC = () => { {/* Basic Environment Information Card */} { column={{ xxl: 4, xl: 3, lg: 3, md: 2, sm: 1, xs: 1 }} size="small" > - + {environment.environmentFrontendUrl ? ( { {environment.environmentFrontendUrl} ) : ( - "No domain set" + trans("enterprise.environments.detail.noDomainSet") )} - + {environment.environmentId} - + {(() => { switch (environment.licenseStatus) { case 'checking': - return } color="blue" style={{ borderRadius: '4px' }}>Checking...; + return } color="blue" style={{ borderRadius: '4px' }}>{trans("enterprise.environments.licenseStatus.checking")}; case 'licensed': - return } color="green" style={{ borderRadius: '4px' }}>Licensed; + return } color="green" style={{ borderRadius: '4px' }}>{trans("enterprise.environments.licenseStatus.licensed")}; case 'unlicensed': - return } color="orange" style={{ borderRadius: '4px' }}>License Needed; + return } color="orange" style={{ borderRadius: '4px' }}>{trans("enterprise.environments.detail.licenseNeeded")}; case 'error': - return } color="orange" style={{ borderRadius: '4px' }}>Setup Required; + return } color="orange" style={{ borderRadius: '4px' }}>{trans("enterprise.environments.detail.setupRequired")}; default: - return Unknown; + return {trans("enterprise.environments.detail.unknown")}; } })()} - - {environment.createdAt ? new Date(environment.createdAt).toLocaleDateString() : "Unknown"} + + {environment.createdAt ? new Date(environment.createdAt).toLocaleDateString() : trans("enterprise.environments.detail.unknown")} @@ -285,7 +286,7 @@ const EnvironmentDetail: React.FC = () => { title={ - License Details + {trans("enterprise.environments.detail.licenseDetails")} } style={{ @@ -304,7 +305,7 @@ const EnvironmentDetail: React.FC = () => { styles={{ body: { padding: '16px' } }} > ( { color: '#8c8c8c', marginTop: '4px' }}> - {environment.licenseDetails.apiCallsUsage || 0}% used + {trans("enterprise.environments.percentUsed", { percent: environment.licenseDetails.apiCallsUsage || 0 })} @@ -347,7 +348,7 @@ const EnvironmentDetail: React.FC = () => { styles={{ body: { padding: '16px' } }} > value?.toLocaleString()} prefix={} @@ -356,7 +357,7 @@ const EnvironmentDetail: React.FC = () => { color="blue" style={{ marginTop: '12px' }} > - {environment.licenseDetails.eeLicenses.length} License{environment.licenseDetails.eeLicenses.length !== 1 ? 's' : ''} + {environment.licenseDetails.eeLicenses.length} {environment.licenseDetails.eeLicenses.length !== 1 ? trans("enterprise.environments.detail.licenses") : trans("enterprise.environments.detail.license")} @@ -369,8 +370,8 @@ const EnvironmentDetail: React.FC = () => { styles={{ body: { padding: '16px' } }} > ( {
- License Information + {trans("enterprise.environments.detail.licenseInformation")} @@ -408,13 +409,13 @@ const EnvironmentDetail: React.FC = () => {
- ID: {license.customerId} + {trans("enterprise.environments.id")}: {license.customerId}
UUID: {license.uuid.substring(0, 8)}...
- {license.apiCallsLimit.toLocaleString()} calls + {license.apiCallsLimit.toLocaleString()} {trans("enterprise.environments.detail.calls")} diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentHeader.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentHeader.tsx index 4b4c32209..caaa22c86 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentHeader.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/EnvironmentHeader.tsx @@ -3,6 +3,7 @@ import { Button, Tag, Typography, Row, Col } from 'antd'; import { EditOutlined, CloudServerOutlined } from '@ant-design/icons'; import { Environment } from '../types/environment.types'; import { getEnvironmentTagColor } from '../utils/environmentUtils'; +import { trans } from 'i18n'; const { Title, Text } = Typography; @@ -49,7 +50,7 @@ const EnvironmentHeader: React.FC = ({
- {environment.environmentName || "Unnamed Environment"} + {environment.environmentName || trans("enterprise.environments.unnamedEnvironment")}
= ({ fontSize: '14px', fontFamily: 'monospace' }}> - ID: {environment.environmentId} + {trans("enterprise.environments.id")}: {environment.environmentId} = ({ {environment.isMaster && ( - Master + {trans("enterprise.environments.master")} )} {environment.isLicensed === false && ( - Unlicensed + {trans("enterprise.environments.detail.unlicensed")} )}
@@ -93,7 +94,7 @@ const EnvironmentHeader: React.FC = ({ borderRadius: '4px' }} > - Edit Environment + {trans("enterprise.environments.unlicensed.editEnvironment")} From 4ea9653a06cbbe284b916602f7739fa333393058 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Fri, 30 May 2025 23:48:09 +0500 Subject: [PATCH 06/13] Add trans for Edit Environment Modal --- .../packages/lowcoder/src/i18n/locales/en.ts | 3 ++ .../components/EditEnvironmentModal.tsx | 51 ++++++++++--------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 85b72168f..721e8b3c6 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2636,8 +2636,10 @@ export const en = { }, "modal": { "createNewEnvironment": "Create New Environment", + "editEnvironment": "Edit Environment", "cancel": "Cancel", "createEnvironment": "Create Environment", + "saveChanges": "Save Changes", "environmentName": "Environment Name", "pleaseEnterName": "Please enter a name", "nameMinLength": "Name must be at least 2 characters", @@ -2660,6 +2662,7 @@ export const en = { "masterEnvironment": "Master Environment", "alreadyMasterEnvironment": "{name} is already the Master environment", "willBeMaster": "Will be Master", + "currentlyMaster": "Currently Master", "configurationRequirements": "Configuration Requirements", "configurationRequirementsDesc": "Ensure that the API Service URL is configured and correct, the API key is valid, and for license verification make sure you have both the license and plugin properly installed." } diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/EditEnvironmentModal.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/EditEnvironmentModal.tsx index 3b90bc826..37d1b0946 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/EditEnvironmentModal.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/EditEnvironmentModal.tsx @@ -3,6 +3,7 @@ import { Modal, Form, Input, Select, Switch, Button, Alert, Tooltip } from 'antd import { useSelector } from 'react-redux'; import { selectMasterEnvironment, selectHasMasterEnvironment } from 'redux/selectors/enterpriseSelectors'; import { Environment } from '../types/environment.types'; +import { trans } from 'i18n'; const { Option } = Select; @@ -81,14 +82,14 @@ const EditEnvironmentModal: React.FC = ({ return ( - Cancel + {trans("enterprise.environments.modal.cancel")} , ]} > @@ -107,72 +108,72 @@ const EditEnvironmentModal: React.FC = ({ > - + - + + + + - +
@@ -185,15 +186,15 @@ const EditEnvironmentModal: React.FC = ({ {isMaster && ( - Currently Master + {trans("enterprise.environments.modal.currentlyMaster")} )}
Date: Sat, 31 May 2025 00:02:52 +0500 Subject: [PATCH 07/13] add translations for workspace and usergroup tabs --- .../packages/lowcoder/src/i18n/locales/en.ts | 51 ++++++++++++++++++ .../environments/components/UserGroupsTab.tsx | 53 ++++++++++--------- .../environments/components/WorkspacesTab.tsx | 49 ++++++++--------- 3 files changed, 103 insertions(+), 50 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 721e8b3c6..fefc7d73b 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2665,6 +2665,57 @@ export const en = { "currentlyMaster": "Currently Master", "configurationRequirements": "Configuration Requirements", "configurationRequirementsDesc": "Ensure that the API Service URL is configured and correct, the API key is valid, and for license verification make sure you have both the license and plugin properly installed." + }, + "workspaces": { + "title": "Workspaces", + "subtitle": "Manage workspaces in this environment", + "refresh": "Refresh", + "errorLoadingWorkspaces": "Error loading workspaces", + "configurationIssue": "Configuration Issue", + "missingConfiguration": "Missing required configuration: API key or API service URL", + "totalWorkspaces": "Total Workspaces", + "managedWorkspaces": "Managed Workspaces", + "unmanagedWorkspaces": "Unmanaged Workspaces", + "workspace": "Workspace", + "role": "Role", + "status": "Status", + "managed": "Managed", + "unmanaged": "Unmanaged", + "actions": "Actions", + "viewAuditLogs": "View Audit Logs", + "audit": "Audit", + "searchWorkspaces": "Search workspaces by name or ID", + "showAll": "Show All", + "managedOnly": "Managed Only", + "showingResults": "Showing {count} of {total} workspaces", + "paginationTotal": "{start}-{end} of {total} workspaces", + "noWorkspacesFound": "No workspaces found in this environment" + }, + "userGroups": { + "title": "User Groups", + "subtitle": "Manage user groups in this environment", + "refresh": "Refresh", + "errorLoadingUserGroups": "Error loading user groups", + "configurationIssue": "Configuration Issue", + "missingConfiguration": "Missing required configuration: API key or API service URL", + "totalGroups": "Total Groups", + "allUsersGroups": "All Users Groups", + "developerGroups": "Developer Groups", + "customGroups": "Custom Groups", + "userGroup": "User Group", + "type": "Type", + "allUsers": "All Users", + "developers": "Developers", + "custom": "Custom", + "members": "Members", + "adminMembers": "Admin Members", + "created": "Created", + "totalMembersTooltip": "Total number of members in this group", + "adminMembersTooltip": "Number of admin users in this group", + "searchUserGroups": "Search user groups by name or ID", + "showingResults": "Showing {count} of {total} user groups", + "paginationTotal": "{start}-{end} of {total} user groups", + "noUserGroupsFound": "No user groups found in this environment" } } }, diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/UserGroupsTab.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/UserGroupsTab.tsx index e9f781b3c..c97d2f461 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/UserGroupsTab.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/UserGroupsTab.tsx @@ -6,6 +6,7 @@ import { Environment } from '../types/environment.types'; import { UserGroup, UserGroupsTabStats } from '../types/userGroup.types'; import { getEnvironmentUserGroups } from '../services/environments.service'; import { Spin, Empty } from 'antd'; +import { trans } from 'i18n'; const { Search } = Input; @@ -36,7 +37,7 @@ const UserGroupsTab: React.FC = ({ environment }) => { try { // Check for required environment properties if (!environment.environmentApikey || !environment.environmentApiServiceUrl) { - setError('Missing required configuration: API key or API service URL'); + setError(trans("enterprise.environments.userGroups.missingConfiguration")); setLoading(false); return; } @@ -65,7 +66,7 @@ const UserGroupsTab: React.FC = ({ environment }) => { custom }); } catch (err) { - setError(err instanceof Error ? err.message : "Failed to fetch user groups"); + setError(err instanceof Error ? err.message : trans("enterprise.environments.userGroups.errorLoadingUserGroups")); } finally { setLoading(false); setRefreshing(false); @@ -134,7 +135,7 @@ const UserGroupsTab: React.FC = ({ environment }) => { // Table columns const columns = [ { - title: 'User Group', + title: trans("enterprise.environments.userGroups.userGroup"), key: 'group', render: (group: UserGroup) => (
@@ -158,31 +159,31 @@ const UserGroupsTab: React.FC = ({ environment }) => { ), }, { - title: 'Type', + title: trans("enterprise.environments.userGroups.type"), key: 'type', render: (_: any, group: UserGroup) => { if (group.allUsersGroup) return ( - All Users + {trans("enterprise.environments.userGroups.allUsers")} ); if (group.devGroup) return ( - Developers + {trans("enterprise.environments.userGroups.developers")} ); return ( - Custom + {trans("enterprise.environments.userGroups.custom")} ); }, }, { - title: 'Members', + title: trans("enterprise.environments.userGroups.members"), key: 'members', render: (_: any, group: UserGroup) => ( - + {group.stats?.userCount || 0} @@ -190,10 +191,10 @@ const UserGroupsTab: React.FC = ({ environment }) => { ), }, { - title: 'Admin Members', + title: trans("enterprise.environments.userGroups.adminMembers"), key: 'adminMembers', render: (_: any, group: UserGroup) => ( - + {group.stats?.adminUserCount || 0} @@ -201,7 +202,7 @@ const UserGroupsTab: React.FC = ({ environment }) => { ), }, { - title: 'Created', + title: trans("enterprise.environments.userGroups.created"), dataIndex: 'createTime', key: 'createTime', render: (createTime: number) => ( @@ -223,10 +224,10 @@ const UserGroupsTab: React.FC = ({ environment }) => { }}>
- <UsergroupAddOutlined style={{ marginRight: 8 }} /> User Groups + <UsergroupAddOutlined style={{ marginRight: 8 }} /> {trans("enterprise.environments.userGroups.title")}

- Manage user groups in this environment + {trans("enterprise.environments.userGroups.subtitle")}

{/* Error display */} {error && ( = ({ environment }) => { {/* Configuration warnings */} {(!environment.environmentApikey || !environment.environmentApiServiceUrl) && !error && ( = ({ environment }) => { } /> } /> } /> } /> @@ -305,7 +306,7 @@ const UserGroupsTab: React.FC = ({ environment }) => {
) : userGroups.length === 0 ? ( ) : ( @@ -313,7 +314,7 @@ const UserGroupsTab: React.FC = ({ environment }) => { {/* Search Bar */}
setSearchText(value)} onChange={e => setSearchText(e.target.value)} @@ -321,7 +322,7 @@ const UserGroupsTab: React.FC = ({ environment }) => { /> {searchText && filteredUserGroups.length !== userGroups.length && (
- Showing {filteredUserGroups.length} of {userGroups.length} user groups + {trans("enterprise.environments.userGroups.showingResults", { count: filteredUserGroups.length, total: userGroups.length })}
)}
@@ -332,7 +333,7 @@ const UserGroupsTab: React.FC = ({ environment }) => { rowKey="groupId" pagination={{ pageSize: 10, - showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} user groups`, + showTotal: (total, range) => trans("enterprise.environments.userGroups.paginationTotal", { start: range[0], end: range[1], total }), size: 'small' }} size="middle" diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/WorkspacesTab.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/WorkspacesTab.tsx index 26732c76a..8e265350c 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/WorkspacesTab.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/WorkspacesTab.tsx @@ -6,6 +6,7 @@ import { Environment } from '../types/environment.types'; import { Workspace } from '../types/workspace.types'; import { getMergedEnvironmentWorkspaces } from '../services/workspace.service'; import { Spin, Empty } from 'antd'; +import { trans } from 'i18n'; import history from '@lowcoder-ee/util/history'; @@ -38,7 +39,7 @@ const WorkspacesTab: React.FC = ({ environment }) => { try { // Check for required environment properties if (!environment.environmentApikey || !environment.environmentApiServiceUrl) { - setError('Missing required configuration: API key or API service URL'); + setError(trans("enterprise.environments.workspaces.missingConfiguration")); setLoading(false); return; } @@ -52,7 +53,7 @@ const WorkspacesTab: React.FC = ({ environment }) => { setWorkspaces(result.workspaces); setStats(result.stats); } catch (err) { - setError(err instanceof Error ? err.message : "Failed to fetch workspaces"); + setError(err instanceof Error ? err.message : trans("enterprise.environments.workspaces.errorLoadingWorkspaces")); } finally { setLoading(false); setRefreshing(false); @@ -130,7 +131,7 @@ const WorkspacesTab: React.FC = ({ environment }) => { // Table columns const columns = [ { - title: 'Workspace', + title: trans("enterprise.environments.workspaces.workspace"), key: 'workspace', render: (workspace: Workspace) => (
@@ -154,12 +155,12 @@ const WorkspacesTab: React.FC = ({ environment }) => { ), }, { - title: 'Role', + title: trans("enterprise.environments.workspaces.role"), dataIndex: 'role', key: 'role', }, { - title: 'Status', + title: trans("enterprise.environments.workspaces.status"), dataIndex: 'status', key: 'status', render: (status: string) => ( @@ -170,7 +171,7 @@ const WorkspacesTab: React.FC = ({ environment }) => { ), }, { - title: 'Managed', + title: trans("enterprise.environments.workspaces.managed"), key: 'managed', render: (_: any, workspace: Workspace) => ( = ({ environment }) => { ? : } - {workspace.managed ? 'Managed' : 'Unmanaged'} + {workspace.managed ? trans("enterprise.environments.workspaces.managed") : trans("enterprise.environments.workspaces.unmanaged")} ), }, { - title: 'Actions', + title: trans("enterprise.environments.workspaces.actions"), key: 'actions', render: (_: any, workspace: Workspace) => ( e.stopPropagation()}> - + @@ -219,10 +220,10 @@ const WorkspacesTab: React.FC = ({ environment }) => { }}>
- <TeamOutlined style={{ marginRight: 8 }} /> Workspaces + <TeamOutlined style={{ marginRight: 8 }} /> {trans("enterprise.environments.workspaces.title")}

- Manage workspaces in this environment + {trans("enterprise.environments.workspaces.subtitle")}

{/* Error display */} {error && ( = ({ environment }) => { {/* Configuration warnings */} {(!environment.environmentApikey || !environment.environmentApiServiceUrl) && !error && ( = ({ environment }) => { } /> } /> } /> @@ -294,7 +295,7 @@ const WorkspacesTab: React.FC = ({ environment }) => { ) : workspaces.length === 0 ? ( ) : ( @@ -302,7 +303,7 @@ const WorkspacesTab: React.FC = ({ environment }) => { {/* Search and Filter Bar */}
setSearchText(value)} onChange={e => setSearchText(e.target.value)} @@ -314,13 +315,13 @@ const WorkspacesTab: React.FC = ({ environment }) => { icon={} style={{ marginLeft: '8px' }} > - {showManagedOnly ? 'Show All' : 'Managed Only'} + {showManagedOnly ? trans("enterprise.environments.workspaces.showAll") : trans("enterprise.environments.workspaces.managedOnly")}
{searchText && displayedWorkspaces.length !== workspaces.length && (
- Showing {displayedWorkspaces.length} of {workspaces.length} workspaces + {trans("enterprise.environments.workspaces.showingResults", { count: displayedWorkspaces.length, total: workspaces.length })}
)} @@ -330,7 +331,7 @@ const WorkspacesTab: React.FC = ({ environment }) => { rowKey="id" pagination={{ pageSize: 10, - showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} workspaces`, + showTotal: (total, range) => trans("enterprise.environments.workspaces.paginationTotal", { start: range[0], end: range[1], total }), size: 'small' }} size="middle" From 1eddf6dac9ef8547f855bb8e648f10bdbe748eb4 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Sat, 31 May 2025 00:16:31 +0500 Subject: [PATCH 08/13] Add trans for Apps, queries and DS tab --- .../packages/lowcoder/src/i18n/locales/en.ts | 90 +++++++++++++++++++ .../environments/components/AppsTab.tsx | 57 ++++++------ .../components/DataSourcesTab.tsx | 55 ++++++------ .../environments/components/QueriesTab.tsx | 53 +++++------ 4 files changed, 174 insertions(+), 81 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index fefc7d73b..953467957 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2716,6 +2716,96 @@ export const en = { "showingResults": "Showing {count} of {total} user groups", "paginationTotal": "{start}-{end} of {total} user groups", "noUserGroupsFound": "No user groups found in this environment" + }, + "apps": { + "title": "Apps", + "subtitle": "Manage workspace applications", + "refresh": "Refresh", + "errorLoadingApps": "Error loading apps", + "configurationIssue": "Configuration Issue", + "missingConfiguration": "Missing required configuration: API key or API service URL", + "totalApps": "Total Apps", + "publishedApps": "Published Apps", + "managedApps": "Managed Apps", + "unmanagedApps": "Unmanaged Apps", + "app": "App", + "status": "Status", + "published": "Published", + "draft": "Draft", + "managed": "Managed", + "unmanaged": "Unmanaged", + "deploy": "Deploy", + "audit": "Audit", + "appMustBeManagedToDeploy": "App must be managed before it can be deployed", + "deployThisApp": "Deploy this app to another environment", + "viewAuditLogs": "View Audit Logs", + "searchApps": "Search apps by name or ID", + "showAll": "Show All", + "managedOnly": "Managed Only", + "showingResults": "Showing {count} of {total} apps", + "paginationTotal": "{start}-{end} of {total} apps", + "noAppsFound": "No apps found in this workspace", + "appRecycled": "This app has been moved to recycle bin", + "managedSuccess": "{name} is now Managed", + "unmanagedSuccess": "{name} is now Unmanaged", + "managedError": "Failed to change managed status for {name}" + }, + "dataSources": { + "title": "Data Sources", + "subtitle": "Manage workspace data connections", + "refresh": "Refresh", + "errorLoadingDataSources": "Error loading data sources", + "configurationIssue": "Configuration Issue", + "missingConfiguration": "Missing required configuration: API key or API service URL", + "totalDataSources": "Total Data Sources", + "availableTypes": "Available Types", + "managed": "Managed", + "unmanaged": "Unmanaged", + "dataSource": "Data Source", + "type": "Type", + "status": "Status", + "deploy": "Deploy", + "audit": "Audit", + "dataSourceMustBeManagedToDeploy": "Data source must be managed before it can be deployed", + "deployThisDataSource": "Deploy this data source to another environment", + "viewAuditLogs": "View Audit Logs", + "searchDataSources": "Search data sources by name or ID", + "showAll": "Show All", + "managedOnly": "Managed Only", + "showingResults": "Showing {count} of {total} data sources", + "paginationTotal": "{start}-{end} of {total} data sources", + "noDataSourcesFound": "No data sources found in this workspace", + "managedSuccess": "{name} is now Managed", + "unmanagedSuccess": "{name} is now Unmanaged", + "managedError": "Failed to change managed status for {name}" + }, + "queries": { + "title": "Queries", + "subtitle": "Manage workspace API queries", + "refresh": "Refresh", + "errorLoadingQueries": "Error loading queries", + "configurationIssue": "Configuration Issue", + "missingConfiguration": "Missing required configuration: API key or API service URL", + "totalQueries": "Total Queries", + "managed": "Managed", + "unmanaged": "Unmanaged", + "query": "Query", + "creator": "Creator", + "status": "Status", + "deploy": "Deploy", + "audit": "Audit", + "queryMustBeManagedToDeploy": "Query must be managed before it can be deployed", + "deployThisQuery": "Deploy this query to another environment", + "viewAuditLogs": "View Audit Logs", + "searchQueries": "Search queries by name or ID", + "showAll": "Show All", + "managedOnly": "Managed Only", + "showingResults": "Showing {count} of {total} queries", + "paginationTotal": "{start}-{end} of {total} queries", + "noQueriesFound": "No queries found in this workspace", + "managedSuccess": "{name} is now Managed", + "unmanagedSuccess": "{name} is now Unmanaged", + "managedError": "Failed to change managed status for {name}" } } }, diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/AppsTab.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/AppsTab.tsx index 150b17242..f63bc3071 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/AppsTab.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/AppsTab.tsx @@ -11,6 +11,7 @@ import { useDeployModal } from '../context/DeployModalContext'; import { appsConfig } from '../config/apps.config'; import history from "@lowcoder-ee/util/history"; import { messageInstance } from 'lowcoder-design/src/components/GlobalInstances'; +import { trans } from 'i18n'; const { Search } = Input; @@ -117,10 +118,10 @@ const AppsTab: React.FC = ({ environment, workspaceId }) => { unmanaged: prev.total - managed })); - messageInstance.success(`${app.name} is now ${checked ? 'Managed' : 'Unmanaged'}`); + messageInstance.success(trans(checked ? "enterprise.environments.apps.managedSuccess" : "enterprise.environments.apps.unmanagedSuccess", { name: app.name })); return true; } catch (error) { - messageInstance.error(`Failed to change managed status for ${app.name}`); + messageInstance.error(trans("enterprise.environments.apps.managedError", { name: app.name })); return false; } finally { setRefreshing(false); @@ -141,7 +142,7 @@ const AppsTab: React.FC = ({ environment, workspaceId }) => { // Table columns const columns = [ { - title: 'App', + title: trans("enterprise.environments.apps.app"), key: 'app', render: (app: App) => (
@@ -158,7 +159,7 @@ const AppsTab: React.FC = ({ environment, workspaceId }) => {
{app.name} {app.applicationStatus === 'RECYCLED' && ( - + = ({ environment, workspaceId }) => { ), }, { - title: 'Status', + title: trans("enterprise.environments.apps.status"), key: 'status', render: (app: App) => ( - {app.published ? : null} {app.published ? 'Published' : 'Draft'} + {app.published ? : null} {app.published ? trans("enterprise.environments.apps.published") : trans("enterprise.environments.apps.draft")} - {app.managed ? : } {app.managed ? 'Managed' : 'Unmanaged'} + {app.managed ? : } {app.managed ? trans("enterprise.environments.apps.managed") : trans("enterprise.environments.apps.unmanaged")} ), }, { - title: 'Managed', + title: trans("enterprise.environments.apps.managed"), key: 'managed', render: (_: any, app: App) => ( = ({ environment, workspaceId }) => { ), }, { - title: 'Actions', + title: trans("enterprise.environments.workspaces.actions"), key: 'actions', render: (_: any, app: App) => ( e.stopPropagation()}> - + - + @@ -289,10 +290,10 @@ const AppsTab: React.FC = ({ environment, workspaceId }) => { }}>
- <AppstoreOutlined style={{ marginRight: 8 }} /> Apps + <AppstoreOutlined style={{ marginRight: 8 }} /> {trans("enterprise.environments.apps.title")}

- Manage workspace applications + {trans("enterprise.environments.apps.subtitle")}

{/* Error display */} {error && ( = ({ environment, workspaceId }) => { {/* Configuration warnings */} {(!environment.environmentApikey || !environment.environmentApiServiceUrl) && !error && ( = ({ environment, workspaceId }) => { } /> } /> } /> } /> @@ -371,7 +372,7 @@ const AppsTab: React.FC = ({ environment, workspaceId }) => {
) : apps.length === 0 ? ( ) : ( @@ -379,7 +380,7 @@ const AppsTab: React.FC = ({ environment, workspaceId }) => { {/* Search and Filter Bar */}
setSearchText(value)} onChange={e => setSearchText(e.target.value)} @@ -391,13 +392,13 @@ const AppsTab: React.FC = ({ environment, workspaceId }) => { icon={} style={{ marginLeft: '8px' }} > - {showManagedOnly ? 'Show All' : 'Managed Only'} + {showManagedOnly ? trans("enterprise.environments.apps.showAll") : trans("enterprise.environments.apps.managedOnly")}
{searchText && displayedApps.length !== apps.length && (
- Showing {displayedApps.length} of {apps.length} apps + {trans("enterprise.environments.apps.showingResults", { count: displayedApps.length, total: apps.length })}
)} @@ -407,7 +408,7 @@ const AppsTab: React.FC = ({ environment, workspaceId }) => { rowKey="applicationId" pagination={{ pageSize: 10, - showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} apps`, + showTotal: (total, range) => trans("enterprise.environments.apps.paginationTotal", { start: range[0], end: range[1], total }), size: 'small' }} size="middle" diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/DataSourcesTab.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/DataSourcesTab.tsx index 9cdb0b55a..3179349fa 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/DataSourcesTab.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/DataSourcesTab.tsx @@ -21,6 +21,7 @@ import { ManagedObjectType, setManagedObject, unsetManagedObject } from '../serv import { useDeployModal } from '../context/DeployModalContext'; import { dataSourcesConfig } from '../config/data-sources.config'; import history from "@lowcoder-ee/util/history"; +import { trans } from 'i18n'; const { Search } = Input; @@ -115,10 +116,10 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI unmanaged: prev.total - managed })); - messageInstance.success(`${dataSource.name} is now ${checked ? 'Managed' : 'Unmanaged'}`); + messageInstance.success(trans(checked ? "enterprise.environments.dataSources.managedSuccess" : "enterprise.environments.dataSources.unmanagedSuccess", { name: dataSource.name })); return true; } catch (error) { - messageInstance.error(`Failed to change managed status for ${dataSource.name}`); + messageInstance.error(trans("enterprise.environments.dataSources.managedError", { name: dataSource.name })); return false; } finally { setRefreshing(false); @@ -139,7 +140,7 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI // Table columns const columns = [ { - title: 'Data Source', + title: trans("enterprise.environments.dataSources.dataSource"), key: 'datasource', render: (dataSource: DataSource) => (
@@ -161,7 +162,7 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI ), }, { - title: 'Type', + title: trans("enterprise.environments.dataSources.type"), dataIndex: 'type', key: 'type', render: (type: string) => ( @@ -171,19 +172,19 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI ), }, { - title: 'Status', + title: trans("enterprise.environments.dataSources.status"), key: 'status', render: (dataSource: DataSource) => ( - {dataSource.managed ? : } {dataSource.managed ? 'Managed' : 'Unmanaged'} + {dataSource.managed ? : } {dataSource.managed ? trans("enterprise.environments.dataSources.managed") : trans("enterprise.environments.dataSources.unmanaged")} ), }, { - title: 'Managed', + title: trans("enterprise.environments.dataSources.managed"), key: 'managed', render: (_: any, dataSource: DataSource) => ( = ({ environment, workspaceI ), }, { - title: 'Actions', + title: trans("enterprise.environments.workspaces.actions"), key: 'actions', render: (_: any, dataSource: DataSource) => ( e.stopPropagation()}> - + - + @@ -286,10 +287,10 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI }}>
- <DatabaseOutlined style={{ marginRight: 8 }} /> Data Sources + <DatabaseOutlined style={{ marginRight: 8 }} /> {trans("enterprise.environments.dataSources.title")}

- Manage workspace data connections + {trans("enterprise.environments.dataSources.subtitle")}

{/* Error display */} {error && ( = ({ environment, workspaceI {/* Configuration warnings */} {(!environment.environmentApikey || !environment.environmentApiServiceUrl) && !error && ( = ({ environment, workspaceI } /> } /> } /> } /> @@ -368,7 +369,7 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI ) : dataSources.length === 0 ? ( ) : ( @@ -376,7 +377,7 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI {/* Search and Filter Bar */}
setSearchText(value)} onChange={e => setSearchText(e.target.value)} @@ -388,13 +389,13 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI icon={} style={{ marginLeft: '8px' }} > - {showManagedOnly ? 'Show All' : 'Managed Only'} + {showManagedOnly ? trans("enterprise.environments.dataSources.showAll") : trans("enterprise.environments.dataSources.managedOnly")}
{searchText && displayedDataSources.length !== dataSources.length && (
- Showing {displayedDataSources.length} of {dataSources.length} data sources + {trans("enterprise.environments.dataSources.showingResults", { count: displayedDataSources.length, total: dataSources.length })}
)} @@ -404,7 +405,7 @@ const DataSourcesTab: React.FC = ({ environment, workspaceI rowKey="id" pagination={{ pageSize: 10, - showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} data sources`, + showTotal: (total, range) => trans("enterprise.environments.dataSources.paginationTotal", { start: range[0], end: range[1], total }), size: 'small' }} size="middle" diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/QueriesTab.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/QueriesTab.tsx index 0d754025f..49e55b6d4 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/QueriesTab.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/QueriesTab.tsx @@ -23,6 +23,7 @@ import { ManagedObjectType, setManagedObject, unsetManagedObject } from '../serv import { useDeployModal } from '../context/DeployModalContext'; import { queryConfig } from '../config/query.config'; import history from "@lowcoder-ee/util/history"; +import { trans } from 'i18n'; const { Search } = Input; @@ -116,10 +117,10 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => unmanaged: prev.total - managed })); - messageInstance.success(`${query.name} is now ${checked ? 'Managed' : 'Unmanaged'}`); + messageInstance.success(trans(checked ? "enterprise.environments.queries.managedSuccess" : "enterprise.environments.queries.unmanagedSuccess", { name: query.name })); return true; } catch (error) { - messageInstance.error(`Failed to change managed status for ${query.name}`); + messageInstance.error(trans("enterprise.environments.queries.managedError", { name: query.name })); return false; } finally { setRefreshing(false); @@ -151,7 +152,7 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => // Table columns const columns = [ { - title: 'Query', + title: trans("enterprise.environments.queries.query"), key: 'query', render: (query: Query) => (
@@ -174,7 +175,7 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => ), }, { - title: 'Creator', + title: trans("enterprise.environments.queries.creator"), dataIndex: 'creatorName', key: 'creatorName', render: (creatorName: string) => ( @@ -189,19 +190,19 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => ) }, { - title: 'Status', + title: trans("enterprise.environments.queries.status"), key: 'status', render: (query: Query) => ( - {query.managed ? : } {query.managed ? 'Managed' : 'Unmanaged'} + {query.managed ? : } {query.managed ? trans("enterprise.environments.queries.managed") : trans("enterprise.environments.queries.unmanaged")} ), }, { - title: 'Managed', + title: trans("enterprise.environments.queries.managed"), key: 'managed', render: (_: any, query: Query) => ( = ({ environment, workspaceId }) => ), }, { - title: 'Actions', + title: trans("enterprise.environments.workspaces.actions"), key: 'actions', render: (_: any, query: Query) => ( e.stopPropagation()}> - + - + @@ -286,10 +287,10 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => }}>
- <ThunderboltOutlined style={{ marginRight: 8 }} /> Queries + <ThunderboltOutlined style={{ marginRight: 8 }} /> {trans("enterprise.environments.queries.title")}

- Manage workspace API queries + {trans("enterprise.environments.queries.subtitle")}

{/* Error display */} {error && ( = ({ environment, workspaceId }) => {/* Configuration warnings */} {(!environment.environmentApikey || !environment.environmentApiServiceUrl) && !error && ( = ({ environment, workspaceId }) => } /> } /> } /> @@ -361,7 +362,7 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => ) : queries.length === 0 ? ( ) : ( @@ -369,7 +370,7 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => {/* Search and Filter Bar */}
setSearchText(value)} onChange={e => setSearchText(e.target.value)} @@ -381,13 +382,13 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => icon={} style={{ marginLeft: '8px' }} > - {showManagedOnly ? 'Show All' : 'Managed Only'} + {showManagedOnly ? trans("enterprise.environments.queries.showAll") : trans("enterprise.environments.queries.managedOnly")}
{searchText && displayedQueries.length !== queries.length && (
- Showing {displayedQueries.length} of {queries.length} queries + {trans("enterprise.environments.queries.showingResults", { count: displayedQueries.length, total: queries.length })}
)} @@ -397,7 +398,7 @@ const QueriesTab: React.FC = ({ environment, workspaceId }) => rowKey="id" pagination={{ pageSize: 10, - showTotal: (total, range) => `${range[0]}-${range[1]} of ${total} queries`, + showTotal: (total, range) => trans("enterprise.environments.queries.paginationTotal", { start: range[0], end: range[1], total }), size: 'small' }} size="middle" From 5b241f819287416a7faa03e21be10e4a11e47c01 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Sat, 31 May 2025 00:24:52 +0500 Subject: [PATCH 09/13] add trans for environments services --- .../packages/lowcoder/src/i18n/locales/en.ts | 52 ++++++++++++ .../services/enterprise.service.ts | 35 ++++---- .../services/environments.service.ts | 79 ++++++++++--------- 3 files changed, 110 insertions(+), 56 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 953467957..5de851179 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2806,6 +2806,58 @@ export const en = { "managedSuccess": "{name} is now Managed", "unmanagedSuccess": "{name} is now Unmanaged", "managedError": "Failed to change managed status for {name}" + }, + + // Service error messages + "services": { + "environments": { + "missingEnvironmentId": "Missing environment ID", + "failedToUpdateEnvironment": "Failed to update environment", + "environmentCreatedSuccessfully": "Environment created successfully", + "failedToCreateEnvironment": "Failed to create environment", + "failedToFetchEnvironments": "Failed to fetch environments", + "failedToFetchEnvironment": "Failed to fetch environment", + "environmentIdRequired": "Environment ID is required", + "apiKeyRequiredForWorkspaces": "API key is required to fetch workspaces", + "apiServiceUrlRequiredForWorkspaces": "API service URL is required to fetch workspaces", + "failedToFetchWorkspaces": "Failed to fetch workspaces", + "apiKeyRequiredForUserGroups": "API key is required to fetch user groups", + "apiServiceUrlRequiredForUserGroups": "API service URL is required to fetch user groups", + "failedToFetchUserGroups": "Failed to fetch user groups", + "workspaceIdRequired": "Workspace ID is required", + "apiKeyRequiredForApps": "API key is required to fetch apps", + "apiServiceUrlRequiredForApps": "API service URL is required to fetch apps", + "failedToFetchWorkspaceApps": "Failed to fetch workspace apps", + "apiKeyRequiredForDataSources": "API key is required to fetch data sources", + "apiServiceUrlRequiredForDataSources": "API service URL is required to fetch data sources", + "failedToFetchWorkspaceDataSources": "Failed to fetch workspace data sources", + "apiKeyRequiredForQueries": "API key is required to fetch queries", + "apiServiceUrlRequiredForQueries": "API service URL is required to fetch queries", + "failedToFetchWorkspaceQueries": "Failed to fetch workspace queries", + "apiServiceUrlNotConfigured": "API service URL not configured", + "licenseCheckFailed": "License check failed", + "apiKeyRequiredForDeploymentId": "API key is required to fetch deployment ID", + "failedToFetchDeploymentId": "Failed to fetch deployment ID" + }, + "enterprise": { + "missingEnvironmentId": "Missing environment ID", + "failedToFetchManagedWorkspaces": "Failed to fetch managed workspaces", + "missingRequiredParamsToConnectOrg": "Missing required params to connect workspace", + "failedToConnectOrg": "Failed to connect workspace", + "missingOrgGidToUnconnectWorkspace": "Missing workspace GID to unconnect workspace", + "failedToUnconnectOrg": "Failed to unconnect workspace", + "failedToConnectApp": "Failed to connect app", + "failedToUnconnectApp": "Failed to unconnect app", + "failedToFetchDataSources": "Failed to fetch data sources", + "failedToDeployDataSource": "Failed to deploy data source", + "failedToDisconnectManagedDataSource": "Failed to disconnect managed data source", + "environmentIdRequired": "Environment ID is required", + "failedToFetchQueries": "Failed to fetch queries", + "environmentIdAndQueryGidRequired": "Environment ID and Query GID are required", + "failedToDeployQuery": "Failed to deploy query", + "queryGidRequired": "Query GID is required", + "failedToDisconnectQuery": "Failed to disconnect query" + } } } }, diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/enterprise.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/enterprise.service.ts index f676f1734..208085c69 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/enterprise.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/enterprise.service.ts @@ -1,5 +1,6 @@ import axios from "axios"; import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; +import { trans } from "i18n"; import { ManagedOrg } from "../types/enterprise.types"; import { Query } from "../types/query.types"; @@ -17,7 +18,7 @@ export async function getManagedWorkspaces( ): Promise { if (!environmentId) { - throw new Error("Missing environmentId"); + throw new Error(trans("enterprise.environments.services.enterprise.missingEnvironmentId")); } try { @@ -25,7 +26,7 @@ export async function getManagedWorkspaces( const all: ManagedOrg[] = res.data.data; return all.filter(org => org.environmentId === environmentId); } catch (err) { - const errorMsg = err instanceof Error ? err.message : "Failed to fetch managed workspaces"; + const errorMsg = err instanceof Error ? err.message : trans("enterprise.environments.services.enterprise.failedToFetchManagedWorkspaces"); messageInstance.error(errorMsg); throw err; } @@ -48,7 +49,7 @@ export async function connectManagedWorkspace( orgTags: string[] = [], ) { if (!environmentId || !orgName || !org_gid) { - throw new Error("Missing required params to connect org"); + throw new Error(trans("enterprise.environments.services.enterprise.missingRequiredParamsToConnectOrg")); } try { @@ -62,7 +63,7 @@ export async function connectManagedWorkspace( const res = await axios.post(`/api/plugins/enterprise/org`, payload); return res.data; } catch (err) { - const errorMsg = err instanceof Error ? err.message : "Failed to connect org"; + const errorMsg = err instanceof Error ? err.message : trans("enterprise.environments.services.enterprise.failedToConnectOrg"); messageInstance.error(errorMsg); throw err; } @@ -78,7 +79,7 @@ export async function connectManagedWorkspace( */ export async function unconnectManagedWorkspace(orgGid: string) { if (!orgGid) { - throw new Error("Missing orgGid to unconnect workspace"); + throw new Error(trans("enterprise.environments.services.enterprise.missingOrgGidToUnconnectWorkspace")); } try { @@ -87,7 +88,7 @@ export async function unconnectManagedWorkspace(orgGid: string) { }); } catch (err) { const errorMsg = - err instanceof Error ? err.message : "Failed to unconnect org"; + err instanceof Error ? err.message : trans("enterprise.environments.services.enterprise.failedToUnconnectOrg"); messageInstance.error(errorMsg); throw err; } @@ -123,7 +124,7 @@ export async function connectManagedApp( return res.data; } catch (err) { const errorMsg = - err instanceof Error ? err.message : "Failed to connect app"; + err instanceof Error ? err.message : trans("enterprise.environments.services.enterprise.failedToConnectApp"); messageInstance.error(errorMsg); throw err; } @@ -136,7 +137,7 @@ export async function unconnectManagedApp(appGid: string) { params: { appGid }, }); } catch (err) { - const errorMsg = err instanceof Error ? err.message : "Failed to unconnect app"; + const errorMsg = err instanceof Error ? err.message : trans("enterprise.environments.services.enterprise.failedToUnconnectApp"); messageInstance.error(errorMsg); throw err; } @@ -151,7 +152,7 @@ export const getManagedDataSources = async (environmentId: string): Promise { try { if (!environmentId) { - throw new Error('Environment ID is required'); + throw new Error(trans("enterprise.environments.services.enterprise.environmentIdRequired")); } // Get managed queries from the enterprise endpoint @@ -226,7 +227,7 @@ export async function getManagedQueries(environmentId: string): Promise })); } catch (error) { - const errorMsg = error instanceof Error ? error.message : 'Failed to fetch queries'; + const errorMsg = error instanceof Error ? error.message : trans("enterprise.environments.services.enterprise.failedToFetchQueries"); messageInstance.error(errorMsg); throw error; } @@ -240,7 +241,7 @@ export async function connectManagedQuery( ): Promise { try { if (!environmentId || !queryGid) { - throw new Error('Environment ID and Query GID are required'); + throw new Error(trans("enterprise.environments.services.enterprise.environmentIdAndQueryGidRequired")); } const response = await axios.post('/api/plugins/enterprise/qlQuery', { @@ -253,7 +254,7 @@ export async function connectManagedQuery( return response.status === 200; } catch (error) { - const errorMsg = error instanceof Error ? error.message : 'Failed to deploy query'; + const errorMsg = error instanceof Error ? error.message : trans("enterprise.environments.services.enterprise.failedToDeployQuery"); messageInstance.error(errorMsg); throw error; } @@ -263,7 +264,7 @@ export async function connectManagedQuery( export async function unconnectManagedQuery(queryGid: string): Promise { try { if (!queryGid) { - throw new Error('Query GID is required'); + throw new Error(trans("enterprise.environments.services.enterprise.queryGidRequired")); } const response = await axios.delete(`/api/plugins/enterprise/qlQuery`, { @@ -275,7 +276,7 @@ export async function unconnectManagedQuery(queryGid: string): Promise return response.status === 200; } catch (error) { - const errorMsg = error instanceof Error ? error.message : 'Failed to disconnect query'; + const errorMsg = error instanceof Error ? error.message : trans("enterprise.environments.services.enterprise.failedToDisconnectQuery"); messageInstance.error(errorMsg); throw error; } diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts index b3ccb5314..6f38a87b3 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts @@ -1,5 +1,6 @@ import axios from "axios"; import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; +import { trans } from "i18n"; import { Environment } from "../types/environment.types"; import { Workspace } from "../types/workspace.types"; import { UserGroup } from "../types/userGroup.types"; @@ -16,7 +17,7 @@ export async function updateEnvironment( environmentData: Partial ): Promise { if (!environmentId) { - throw new Error("Missing environmentId"); + throw new Error(trans("enterprise.environments.services.environments.missingEnvironmentId")); } try { @@ -39,7 +40,7 @@ export async function updateEnvironment( return res.data; } catch (err) { - const errorMsg = err instanceof Error ? err.message : "Failed to update environment"; + const errorMsg = err instanceof Error ? err.message : trans("enterprise.environments.services.environments.failedToUpdateEnvironment"); messageInstance.error(errorMsg); throw err; } @@ -70,13 +71,13 @@ export async function createEnvironment( const res = await axios.post(`/api/plugins/enterprise/environments`, payload); if (res.data) { - messageInstance.success("Environment created successfully"); + messageInstance.success(trans("enterprise.environments.services.environments.environmentCreatedSuccessfully")); return res.data; } else { - throw new Error("Failed to create environment"); + throw new Error(trans("enterprise.environments.services.environments.failedToCreateEnvironment")); } } catch (err) { - const errorMsg = err instanceof Error ? err.message : "Failed to create environment"; + const errorMsg = err instanceof Error ? err.message : trans("enterprise.environments.services.environments.failedToCreateEnvironment"); messageInstance.error(errorMsg); throw err; } @@ -97,7 +98,7 @@ export async function getEnvironments(): Promise { return response.data.data || []; } catch (error) { const errorMessage = - error instanceof Error ? error.message : "Failed to fetch environments"; + error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchEnvironments"); messageInstance.error(errorMessage); throw error; } @@ -115,7 +116,7 @@ export async function getEnvironmentById(id: string): Promise { ); if (!response.data) { - throw new Error("Failed to fetch environment"); + throw new Error(trans("enterprise.environments.services.environments.failedToFetchEnvironment")); } const environment = response.data.data; @@ -140,18 +141,18 @@ export async function getEnvironmentById(id: string): Promise { } else { envWithLicense.isLicensed = false; envWithLicense.licenseStatus = 'error'; - envWithLicense.licenseError = 'API service URL not configured'; + envWithLicense.licenseError = trans("enterprise.environments.services.environments.apiServiceUrlNotConfigured"); } } catch (error) { envWithLicense.isLicensed = false; envWithLicense.licenseStatus = 'error'; - envWithLicense.licenseError = error instanceof Error ? error.message : 'License check failed'; + envWithLicense.licenseError = error instanceof Error ? error.message : trans("enterprise.environments.services.environments.licenseCheckFailed"); } return envWithLicense; } catch (error) { const errorMessage = - error instanceof Error ? error.message : "Failed to fetch environment"; + error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchEnvironment"); messageInstance.error(errorMessage); throw error; } @@ -177,14 +178,14 @@ export async function getEnvironmentWorkspaces( try { // Check if required parameters are provided if (!environmentId) { - throw new Error("Environment ID is required"); + throw new Error(trans("enterprise.environments.services.environments.environmentIdRequired")); } if (!apiKey) { - throw new Error("API key is required to fetch workspaces"); + throw new Error(trans("enterprise.environments.services.environments.apiKeyRequiredForWorkspaces")); } if (!apiServiceUrl) { - throw new Error('API service URL is required to fetch workspaces'); + throw new Error(trans("enterprise.environments.services.environments.apiServiceUrlRequiredForWorkspaces")); } // Set up headers with the API key @@ -197,7 +198,7 @@ export async function getEnvironmentWorkspaces( // Check if response is valid if (!response.data || !response.data.success) { - throw new Error(response.data?.message || "Failed to fetch workspaces"); + throw new Error(response.data?.message || trans("enterprise.environments.services.environments.failedToFetchWorkspaces")); } // Extract workspaces from the response @@ -224,7 +225,7 @@ export async function getEnvironmentWorkspaces( } catch (error) { // Handle and transform error const errorMessage = - error instanceof Error ? error.message : "Failed to fetch workspaces"; + error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchWorkspaces"); messageInstance.error(errorMessage); throw error; } @@ -244,15 +245,15 @@ export async function getEnvironmentUserGroups( try { // Check if required parameters are provided if (!environmentId) { - throw new Error('Environment ID is required'); + throw new Error(trans("enterprise.environments.services.environments.environmentIdRequired")); } if (!apiKey) { - throw new Error('API key is required to fetch user groups'); + throw new Error(trans("enterprise.environments.services.environments.apiKeyRequiredForUserGroups")); } if (!apiServiceUrl) { - throw new Error('API service URL is required to fetch user groups'); + throw new Error(trans("enterprise.environments.services.environments.apiServiceUrlRequiredForUserGroups")); } // Set up headers with the Bearer token format @@ -265,7 +266,7 @@ export async function getEnvironmentUserGroups( // Check if response is valid if (!response.data) { - throw new Error('Failed to fetch user groups'); + throw new Error(trans("enterprise.environments.services.environments.failedToFetchUserGroups")); } // The response data is already an array of user groups @@ -274,7 +275,7 @@ export async function getEnvironmentUserGroups( return userGroups; } catch (error) { // Handle and transform error - const errorMessage = error instanceof Error ? error.message : 'Failed to fetch user groups'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchUserGroups"); messageInstance.error(errorMessage); throw error; } @@ -341,15 +342,15 @@ export async function getWorkspaceApps( try { // Check if required parameters are provided if (!workspaceId) { - throw new Error('Workspace ID is required'); + throw new Error(trans("enterprise.environments.services.environments.workspaceIdRequired")); } if (!apiKey) { - throw new Error('API key is required to fetch apps'); + throw new Error(trans("enterprise.environments.services.environments.apiKeyRequiredForApps")); } if (!apiServiceUrl) { - throw new Error('API service URL is required to fetch apps'); + throw new Error(trans("enterprise.environments.services.environments.apiServiceUrlRequiredForApps")); } // Set up headers with the Bearer token format @@ -384,7 +385,7 @@ export async function getWorkspaceApps( } catch (error) { // Handle and transform error - const errorMessage = error instanceof Error ? error.message : 'Failed to fetch workspace apps'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchWorkspaceApps"); messageInstance.error(errorMessage); throw error; } @@ -410,15 +411,15 @@ export async function getWorkspaceDataSources( try { // Check if required parameters are provided if (!workspaceId) { - throw new Error('Workspace ID is required'); + throw new Error(trans("enterprise.environments.services.environments.workspaceIdRequired")); } if (!apiKey) { - throw new Error('API key is required to fetch data sources'); + throw new Error(trans("enterprise.environments.services.environments.apiKeyRequiredForDataSources")); } if (!apiServiceUrl) { - throw new Error('API service URL is required to fetch data sources'); + throw new Error(trans("enterprise.environments.services.environments.apiServiceUrlRequiredForDataSources")); } // Set up headers with the Bearer token format @@ -442,7 +443,7 @@ export async function getWorkspaceDataSources( return response.data.data ; } catch (error) { // Handle and transform error - const errorMessage = error instanceof Error ? error.message : 'Failed to fetch workspace data sources'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchWorkspaceDataSources"); messageInstance.error(errorMessage); throw error; } @@ -471,15 +472,15 @@ export async function getWorkspaceQueries( try { // Check if required parameters are provided if (!workspaceId) { - throw new Error('Workspace ID is required'); + throw new Error(trans("enterprise.environments.services.environments.workspaceIdRequired")); } if (!apiKey) { - throw new Error('API key is required to fetch queries'); + throw new Error(trans("enterprise.environments.services.environments.apiKeyRequiredForQueries")); } if (!apiServiceUrl) { - throw new Error('API service URL is required to fetch queries'); + throw new Error(trans("enterprise.environments.services.environments.apiServiceUrlRequiredForQueries")); } // Set up headers with the Bearer token format @@ -524,7 +525,7 @@ export async function getWorkspaceQueries( } catch (error) { // Handle and transform error - const errorMessage = error instanceof Error ? error.message : 'Failed to fetch workspace queries'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchWorkspaceQueries"); messageInstance.error(errorMessage); throw error; } @@ -561,12 +562,12 @@ export async function getEnvironmentsWithLicenseStatus(): Promise } else { envWithLicense.isLicensed = false; envWithLicense.licenseStatus = 'error'; - envWithLicense.licenseError = 'API service URL not configured'; + envWithLicense.licenseError = trans("enterprise.environments.services.environments.apiServiceUrlNotConfigured"); } } catch (error) { envWithLicense.isLicensed = false; envWithLicense.licenseStatus = 'error'; - envWithLicense.licenseError = error instanceof Error ? error.message : 'License check failed'; + envWithLicense.licenseError = error instanceof Error ? error.message : trans("enterprise.environments.services.environments.licenseCheckFailed"); } return envWithLicense; @@ -576,7 +577,7 @@ export async function getEnvironmentsWithLicenseStatus(): Promise return environmentsWithLicense; } catch (error) { const errorMessage = - error instanceof Error ? error.message : "Failed to fetch environments"; + error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchEnvironments"); messageInstance.error(errorMessage); throw error; } @@ -595,11 +596,11 @@ export async function getEnvironmentDeploymentId( try { // Check if required parameters are provided if (!apiServiceUrl) { - throw new Error('API service URL is required'); + throw new Error(trans("enterprise.environments.services.environments.apiServiceUrlRequiredForWorkspaces")); } if (!apiKey) { - throw new Error('API key is required to fetch deployment ID'); + throw new Error(trans("enterprise.environments.services.environments.apiKeyRequiredForDeploymentId")); } // Set up headers with the Bearer token format @@ -612,14 +613,14 @@ export async function getEnvironmentDeploymentId( // Check if response is valid if (!response.data) { - throw new Error('Failed to fetch deployment ID'); + throw new Error(trans("enterprise.environments.services.environments.failedToFetchDeploymentId")); } // The response should return a string directly return response.data; } catch (error) { // Handle and transform error - const errorMessage = error instanceof Error ? error.message : 'Failed to fetch deployment ID'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.environments.failedToFetchDeploymentId"); messageInstance.error(errorMessage); throw error; } From 7daf6d5a7692fa4e9638daec40cd3dfbf9d71d01 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Sat, 31 May 2025 00:41:22 +0500 Subject: [PATCH 10/13] Add deployment related trans --- .../packages/lowcoder/src/i18n/locales/en.ts | 57 +++++++++++++++++++ .../components/DeployItemModal.tsx | 38 +++++++------ .../components/credentialConfirmations.tsx | 32 ++++++----- .../environments/config/apps.config.tsx | 16 +++--- .../config/data-sources.config.tsx | 5 +- .../environments/config/query.config.tsx | 5 +- .../environments/config/workspace.config.tsx | 3 +- 7 files changed, 111 insertions(+), 45 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 5de851179..d0b638e50 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2808,6 +2808,63 @@ export const en = { "managedError": "Failed to change managed status for {name}" }, + // Deploy Modal and Credential Confirmations + "deployModal": { + "deployTitle": "Deploy {singularLabel}: {name}", + "loadingEnvironments": "Loading environments...", + "sourceEnvironment": "Source Environment", + "targetEnvironment": "Target Environment", + "selectTargetEnvironment": "Select target environment", + "selectTargetEnvironmentValidation": "Please select a target environment", + "confirmed": "Confirmed", + "cancel": "Cancel", + "deploy": "Deploy", + "targetEnvironmentNotFound": "Target environment not found", + "confirmCredentialOverwrite": "Please confirm credential overwrite before deploying", + "deploySuccess": "Successfully deployed {name} to target environment", + "deployFailed": "Failed to deploy {singularLabel}", + "selectFieldValidation": "Please select {label}", + "selectFieldPlaceholder": "Select {label}", + "inputFieldValidation": "Please input {label}", + "inputFieldPlaceholder": "Enter {label}" + }, + + "credentialConfirmations": { + "firstConfirmation": { + "title": "Overwrite Credentials Warning", + "message": "This action will overwrite existing credentials in the target environment.", + "description": "This is a serious operation that may affect other applications and users.", + "question": "Are you sure you want to proceed?", + "continueButton": "Continue", + "cancelButton": "Cancel" + }, + "secondConfirmation": { + "title": "Final Confirmation Required", + "message": "Final Warning: Credential Overwrite", + "description": "You are about to overwrite credentials in the target environment. This action cannot be undone and may break existing integrations.", + "confirmOnceMore": "Please confirm one more time.", + "finalQuestion": "Are you absolutely certain you want to overwrite the credentials?", + "confirmButton": "Yes, Overwrite Credentials", + "cancelButton": "Cancel" + } + }, + + "config": { + "singularLabels": { + "app": "App", + "dataSource": "Data Source", + "query": "Query", + "workspace": "Workspace" + }, + "fields": { + "updateDependenciesIfNeeded": "Update Dependencies If Needed", + "publishOnTarget": "Publish On Target", + "publicToAll": "Public To All", + "publicToMarketplace": "Public To Marketplace", + "overwriteCredentials": "Overwrite Credentials" + } + }, + // Service error messages "services": { "environments": { diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx index b7051185c..757f55153 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/DeployItemModal.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { Modal, Form, Select, Checkbox, Button, Spin, Input, Tag, Space, Alert } from 'antd'; import { messageInstance } from 'lowcoder-design/src/components/GlobalInstances'; +import { trans } from "i18n"; import { useSelector } from 'react-redux'; import { selectLicensedEnvironments, selectEnvironmentsLoading } from 'redux/selectors/enterpriseSelectors'; import { Environment } from '../types/environment.types'; @@ -87,13 +88,13 @@ function DeployItemModal({ const targetEnv = licensedEnvironments.find(env => env.environmentId === values.targetEnvId); if (!targetEnv) { - messageInstance.error('Target environment not found'); + messageInstance.error(trans("enterprise.environments.deployModal.targetEnvironmentNotFound")); return; } // Additional check for credential overwrite if (values.deployCredential && credentialConfirmationStep !== 2) { - messageInstance.error('Please confirm credential overwrite before deploying'); + messageInstance.error(trans("enterprise.environments.deployModal.confirmCredentialOverwrite")); return; } @@ -105,12 +106,12 @@ function DeployItemModal({ // Execute deployment await config.deploy.execute(params); - messageInstance.success(`Successfully deployed ${item.name} to target environment`); + messageInstance.success(trans("enterprise.environments.deployModal.deploySuccess", { name: item.name })); if (onSuccess) onSuccess(); onClose(); } catch (error) { console.error('Deployment error:', error); - messageInstance.error(`Failed to deploy ${config.deploy.singularLabel.toLowerCase()}`); + messageInstance.error(trans("enterprise.environments.deployModal.deployFailed", { singularLabel: config.deploy.singularLabel.toLowerCase() })); } finally { setDeploying(false); } @@ -118,7 +119,10 @@ function DeployItemModal({ return ( {isLoading ? (
- +
) : (
{/* Source environment display */} - + {sourceEnvironment.environmentName} {sourceEnvironment.environmentType && ( @@ -147,10 +151,10 @@ function DeployItemModal({ - {targetEnvironments.map((env) => ( @@ -196,7 +200,7 @@ function DeployItemModal({ style={{ marginLeft: 8 }} icon={} > - Confirmed + {trans("enterprise.environments.deployModal.confirmed")} )} @@ -209,9 +213,9 @@ function DeployItemModal({ name={field.name} label={field.label} initialValue={field.defaultValue} - rules={field.required ? [{ required: true, message: `Please select ${field.label}` }] : undefined} + rules={field.required ? [{ required: true, message: trans("enterprise.environments.deployModal.selectFieldValidation", { label: field.label }) }] : undefined} > - {field.options?.map(option => ( {option.label} @@ -227,9 +231,9 @@ function DeployItemModal({ name={field.name} label={field.label} initialValue={field.defaultValue} - rules={field.required ? [{ required: true, message: `Please input ${field.label}` }] : undefined} + rules={field.required ? [{ required: true, message: trans("enterprise.environments.deployModal.inputFieldValidation", { label: field.label }) }] : undefined} > - + ); default: @@ -239,10 +243,10 @@ function DeployItemModal({ diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/credentialConfirmations.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/credentialConfirmations.tsx index dfaee1cc5..694eec008 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/credentialConfirmations.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/credentialConfirmations.tsx @@ -1,6 +1,6 @@ - import { Modal, Alert } from 'antd'; import { ExclamationCircleOutlined, WarningOutlined } from '@ant-design/icons'; +import { trans } from "i18n"; interface ConfirmHandlers { onOk: () => void; @@ -15,21 +15,23 @@ export function showFirstCredentialOverwriteConfirm({ onOk, onCancel }: ConfirmH title: (
- Overwrite Credentials Warning + + {trans("enterprise.environments.credentialConfirmations.firstConfirmation.title")} +
), icon: null, content: (

- This is a serious operation that may affect other applications and users. + {trans("enterprise.environments.credentialConfirmations.firstConfirmation.description")}

- Are you sure you want to proceed? + {trans("enterprise.environments.credentialConfirmations.firstConfirmation.question")}

} @@ -39,8 +41,8 @@ export function showFirstCredentialOverwriteConfirm({ onOk, onCancel }: ConfirmH /> ), - okText: 'Continue', - cancelText: 'Cancel', + okText: trans("enterprise.environments.credentialConfirmations.firstConfirmation.continueButton"), + cancelText: trans("enterprise.environments.credentialConfirmations.firstConfirmation.cancelButton"), okButtonProps: { style: { backgroundColor: '#ff7a00', borderColor: '#ff7a00', fontWeight: 500 } }, @@ -62,21 +64,23 @@ export function showSecondCredentialOverwriteConfirm({ onOk, onCancel }: Confirm title: (
- Final Confirmation Required + + {trans("enterprise.environments.credentialConfirmations.secondConfirmation.title")} +
), icon: null, content: (

- You are about to overwrite credentials in the target environment. This action cannot be undone and may break existing integrations. + {trans("enterprise.environments.credentialConfirmations.secondConfirmation.description")}

- Please confirm one more time. + {trans("enterprise.environments.credentialConfirmations.secondConfirmation.confirmOnceMore")}

} @@ -93,14 +97,14 @@ export function showSecondCredentialOverwriteConfirm({ onOk, onCancel }: Confirm }} >

- Are you absolutely certain you want to overwrite the credentials? + {trans("enterprise.environments.credentialConfirmations.secondConfirmation.finalQuestion")}

), - okText: 'Yes, Overwrite Credentials', + okText: trans("enterprise.environments.credentialConfirmations.secondConfirmation.confirmButton"), okType: 'danger', - cancelText: 'Cancel', + cancelText: trans("enterprise.environments.credentialConfirmations.secondConfirmation.cancelButton"), okButtonProps: { style: { fontWeight: 500 } }, cancelButtonProps: { style: { fontWeight: 500 } }, width: 520, diff --git a/client/packages/lowcoder/src/pages/setting/environments/config/apps.config.tsx b/client/packages/lowcoder/src/pages/setting/environments/config/apps.config.tsx index 197b2a826..6409cd5e4 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/config/apps.config.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/config/apps.config.tsx @@ -2,11 +2,9 @@ import { DeployableItemConfig } from '../types/deployable-item.types'; import { Environment } from '../types/environment.types'; import { deployApp } from '../services/apps.service'; - +import { trans } from "i18n"; import { App } from '../types/app.types'; - - // Define AppStats interface if not already defined @@ -14,35 +12,35 @@ export const appsConfig: DeployableItemConfig = { deploy: { - singularLabel: 'App', + singularLabel: trans("enterprise.environments.config.singularLabels.app"), fields: [ { name: 'updateDependenciesIfNeeded', - label: 'Update Dependencies If Needed', + label: trans("enterprise.environments.config.fields.updateDependenciesIfNeeded"), type: 'checkbox', defaultValue: false }, { name: 'publishOnTarget', - label: 'Publish On Target', + label: trans("enterprise.environments.config.fields.publishOnTarget"), type: 'checkbox', defaultValue: false }, { name: 'publicToAll', - label: 'Public To All', + label: trans("enterprise.environments.config.fields.publicToAll"), type: 'checkbox', defaultValue: false }, { name: 'publicToMarketplace', - label: 'Public To Marketplace', + label: trans("enterprise.environments.config.fields.publicToMarketplace"), type: 'checkbox', defaultValue: false }, { name: 'deployCredential', - label: 'Overwrite Credentials', + label: trans("enterprise.environments.config.fields.overwriteCredentials"), type: 'checkbox', defaultValue: false } diff --git a/client/packages/lowcoder/src/pages/setting/environments/config/data-sources.config.tsx b/client/packages/lowcoder/src/pages/setting/environments/config/data-sources.config.tsx index ce802e8de..c739a972d 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/config/data-sources.config.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/config/data-sources.config.tsx @@ -4,14 +4,15 @@ import { DeployableItemConfig } from '../types/deployable-item.types'; import { DataSource} from '../types/datasource.types'; import { Environment } from '../types/environment.types'; import { deployDataSource, DataSourceStats } from '../services/datasources.service'; +import { trans } from "i18n"; export const dataSourcesConfig: DeployableItemConfig = { deploy: { - singularLabel: 'Data Source', + singularLabel: trans("enterprise.environments.config.singularLabels.dataSource"), fields: [ { name: 'deployCredential', - label: 'Overwrite Credentials', + label: trans("enterprise.environments.config.fields.overwriteCredentials"), type: 'checkbox', defaultValue: false } diff --git a/client/packages/lowcoder/src/pages/setting/environments/config/query.config.tsx b/client/packages/lowcoder/src/pages/setting/environments/config/query.config.tsx index 7495e5371..0a10f2bff 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/config/query.config.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/config/query.config.tsx @@ -3,15 +3,16 @@ import { DeployableItemConfig } from '../types/deployable-item.types'; import { Query } from '../types/query.types'; import { deployQuery } from '../services/query.service'; import { Environment } from '../types/environment.types'; +import { trans } from "i18n"; export const queryConfig: DeployableItemConfig = { deploy: { - singularLabel: 'Query', + singularLabel: trans("enterprise.environments.config.singularLabels.query"), fields: [ { name: 'deployCredential', - label: 'Overwrite Credentials', + label: trans("enterprise.environments.config.fields.overwriteCredentials"), type: 'checkbox', defaultValue: false } diff --git a/client/packages/lowcoder/src/pages/setting/environments/config/workspace.config.tsx b/client/packages/lowcoder/src/pages/setting/environments/config/workspace.config.tsx index e35423f2f..78865a91a 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/config/workspace.config.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/config/workspace.config.tsx @@ -4,12 +4,13 @@ import { DeployableItemConfig } from '../types/deployable-item.types'; import { Environment } from '../types/environment.types'; import { deployWorkspace } from '../services/workspace.service'; import { Workspace } from '../types/workspace.types'; +import { trans } from "i18n"; export const workspaceConfig: DeployableItemConfig = { // Deploy configuration deploy: { - singularLabel: 'Workspace', + singularLabel: trans("enterprise.environments.config.singularLabels.workspace"), fields: [ // Removed deployCredential field as workspaces don't need credential overwrite ], From d193effd8f1450055ba3a37d572d4af3a1dfead5 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Sat, 31 May 2025 00:50:25 +0500 Subject: [PATCH 11/13] add apps services --- client/packages/lowcoder/src/i18n/locales/en.ts | 4 ++++ .../src/pages/setting/environments/services/apps.service.ts | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index d0b638e50..bc2f7fbe4 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2914,6 +2914,10 @@ export const en = { "failedToDeployQuery": "Failed to deploy query", "queryGidRequired": "Query GID is required", "failedToDisconnectQuery": "Failed to disconnect query" + }, + "apps": { + "failedToFetchApps": "Failed to fetch apps", + "failedToDeployApp": "Failed to deploy app" } } } diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/apps.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/apps.service.ts index db7f21dff..3078bb604 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/apps.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/apps.service.ts @@ -1,5 +1,6 @@ // services/appService.ts import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; +import { trans } from "i18n"; import { getWorkspaceApps } from "./environments.service"; import { getManagedApps } from "./enterprise.service"; import { App, AppStats } from "../types/app.types"; @@ -99,7 +100,7 @@ export async function getMergedWorkspaceApps( }; } catch (error) { const errorMessage = - error instanceof Error ? error.message : "Failed to fetch apps"; + error instanceof Error ? error.message : trans("enterprise.environments.services.apps.failedToFetchApps"); messageInstance.error(errorMessage); throw error; } @@ -137,7 +138,7 @@ export const deployApp = async (params: DeployAppParams): Promise => { return response.status === 200; } catch (error) { - const errorMessage = error instanceof Error ? error.message : 'Failed to deploy app'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.apps.failedToDeployApp"); // Don't show message directly, let the calling component handle it throw new Error(errorMessage); } From f4bca6275d5a71f4e3dcce99c4fd49179ffb21b3 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Sat, 31 May 2025 00:59:36 +0500 Subject: [PATCH 12/13] add more services in trans --- .../packages/lowcoder/src/i18n/locales/en.ts | 46 +++++++++++++++++++ .../components/ContactLowcoderModal.tsx | 19 ++++---- .../services/datasources.service.ts | 13 +++--- .../environments/services/license.service.ts | 22 +++++---- .../services/managed-objects.service.ts | 23 +++++----- .../environments/services/query.service.ts | 1 + .../services/workspace.service.ts | 5 +- 7 files changed, 93 insertions(+), 36 deletions(-) diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index bc2f7fbe4..d5914e6d1 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -2829,6 +2829,22 @@ export const en = { "inputFieldPlaceholder": "Enter {label}" }, + // Add contact lowcoder modal + "contactLowcoder": { + "title": "Contact Lowcoder Team", + "environmentLabel": "Environment:", + "environmentIdLabel": "Environment ID:", + "deploymentIdLabel": "Deployment ID:", + "loading": "Loading...", + "notAvailable": "Not available", + "unnamedEnvironment": "Unnamed Environment", + "fetchingDeploymentInfo": "Fetching deployment information...", + "unableToLoadContactForm": "Unable to Load Contact Form", + "apiConfigurationError": "Environment API service URL or API key not configured", + "failedToFetchDeploymentId": "Failed to fetch deployment ID", + "ensureProperConfiguration": "Please ensure the environment is properly configured to contact support." + }, + "credentialConfirmations": { "firstConfirmation": { "title": "Overwrite Credentials Warning", @@ -2918,6 +2934,36 @@ export const en = { "apps": { "failedToFetchApps": "Failed to fetch apps", "failedToDeployApp": "Failed to deploy app" + }, + "datasources": { + "workspaceIdRequired": "Workspace ID is required", + "apiKeyRequiredToFetchDataSources": "API key is required to fetch data sources", + "apiServiceUrlRequiredToFetchDataSources": "API service URL is required to fetch data sources", + "failedToFetchDataSources": "Failed to fetch data sources", + "failedToDeployDataSource": "Failed to deploy data source" + }, + "workspace": { + "failedToFetchWorkspaces": "Failed to fetch workspaces", + "failedToDeployWorkspace": "Failed to deploy workspace" + }, + "managedObjects": { + "missingRequiredParameters": "Missing required parameters", + "failedToCheckManagedStatus": "Failed to check managed status", + "failedToSetAsManaged": "Failed to set {{objType}} as managed", + "failedToRemoveFromManaged": "Failed to remove {{objType}} from managed", + "missingEnvironmentId": "Missing environment ID", + "failedToFetchManagedObjects": "Failed to fetch managed objects", + "failedToFetchManagedObject": "Failed to fetch managed object", + "managedObjectNotFound": "Managed object not found for objGid: {{objGid}}" + }, + "license": { + "apiServiceUrlRequired": "API service URL is required", + "licenseInformationUnavailable": "License information unavailable", + "licenseCheckTookTooLong": "License check took too long", + "licenseServiceNotAvailable": "License service not available", + "authenticationRequired": "Authentication required - please check API key", + "licenseServiceTemporarilyUnavailable": "License service temporarily unavailable", + "remainingAPICalls": "{{remaining}} remaining ({{used}}/{{total}} used, {{percentage}}%)", } } } diff --git a/client/packages/lowcoder/src/pages/setting/environments/components/ContactLowcoderModal.tsx b/client/packages/lowcoder/src/pages/setting/environments/components/ContactLowcoderModal.tsx index 34ab0526f..7362d35ee 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/components/ContactLowcoderModal.tsx +++ b/client/packages/lowcoder/src/pages/setting/environments/components/ContactLowcoderModal.tsx @@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react'; import { Modal, Card, Row, Col, Typography, Divider, Spin, Alert } from 'antd'; import { CustomerServiceOutlined, CloudServerOutlined } from '@ant-design/icons'; import { useSelector } from 'react-redux'; +import { trans } from 'i18n'; import { Environment } from '../types/environment.types'; import { getEnvironmentDeploymentId } from '../services/environments.service'; import { HubspotModal } from '../../hubspotModal'; @@ -34,7 +35,7 @@ const ContactLowcoderModal: React.FC = ({ const fetchDeploymentId = async () => { if (!visible || !environment.environmentApiServiceUrl || !environment.environmentApikey) { if (visible) { - setError('Environment API service URL or API key not configured'); + setError(trans('enterprise.environments.contactLowcoder.apiConfigurationError')); } return; } @@ -51,7 +52,7 @@ const ContactLowcoderModal: React.FC = ({ setShowHubspotModal(true); } catch (err) { console.error('Failed to fetch deployment ID:', err); - setError(err instanceof Error ? err.message : 'Failed to fetch deployment ID'); + setError(err instanceof Error ? err.message : trans('enterprise.environments.contactLowcoder.failedToFetchDeploymentId')); } finally { setIsLoading(false); } @@ -91,7 +92,7 @@ const ContactLowcoderModal: React.FC = ({ title={
- Contact Lowcoder Team + {trans('enterprise.environments.contactLowcoder.title')}
} open={visible} @@ -119,15 +120,15 @@ const ContactLowcoderModal: React.FC = ({
- Environment: {environment.environmentName || 'Unnamed Environment'} + {trans('enterprise.environments.contactLowcoder.environmentLabel')} {environment.environmentName || trans('enterprise.environments.contactLowcoder.unnamedEnvironment')}
- Environment ID: {environment.environmentId} + {trans('enterprise.environments.contactLowcoder.environmentIdLabel')} {environment.environmentId}
- Deployment ID: {isLoading ? 'Loading...' : deploymentId || 'Not available'} + {trans('enterprise.environments.contactLowcoder.deploymentIdLabel')} {isLoading ? trans('enterprise.environments.contactLowcoder.loading') : deploymentId || trans('enterprise.environments.contactLowcoder.notAvailable')}
@@ -148,14 +149,14 @@ const ContactLowcoderModal: React.FC = ({ }}> - Fetching deployment information... + {trans('enterprise.environments.contactLowcoder.fetchingDeploymentInfo')} )} {error && ( = ({ fontSize: '14px' }}> -
Please ensure the environment is properly configured to contact support.
+
{trans('enterprise.environments.contactLowcoder.ensureProperConfiguration')}
)} diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/datasources.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/datasources.service.ts index 2fc492028..a14fe941b 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/datasources.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/datasources.service.ts @@ -1,6 +1,7 @@ // services/dataSources.service.ts import axios from 'axios'; import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; +import { trans } from "i18n"; import { DataSource, DataSourceWithMeta } from "../types/datasource.types"; import { getManagedObjects, ManagedObject, ManagedObjectType , transferManagedObject } from "./managed-objects.service"; @@ -32,15 +33,15 @@ export async function getWorkspaceDataSources( try { // Check if required parameters are provided if (!workspaceId) { - throw new Error('Workspace ID is required'); + throw new Error(trans("enterprise.environments.services.datasources.workspaceIdRequired")); } if (!apiKey) { - throw new Error('API key is required to fetch data sources'); + throw new Error(trans("enterprise.environments.services.datasources.apiKeyRequiredToFetchDataSources")); } if (!apiServiceUrl) { - throw new Error('API service URL is required to fetch data sources'); + throw new Error(trans("enterprise.environments.services.datasources.apiServiceUrlRequiredToFetchDataSources")); } // Set up headers with the Bearer token format @@ -64,7 +65,7 @@ export async function getWorkspaceDataSources( return response.data.data; } catch (error) { // Handle and transform error - const errorMessage = error instanceof Error ? error.message : 'Failed to fetch data sources'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.datasources.failedToFetchDataSources"); messageInstance.error(errorMessage); throw error; } @@ -143,7 +144,7 @@ export async function getMergedWorkspaceDataSources( }; } catch (error) { const errorMessage = - error instanceof Error ? error.message : "Failed to fetch data sources"; + error instanceof Error ? error.message : trans("enterprise.environments.services.datasources.failedToFetchDataSources"); messageInstance.error(errorMessage); throw error; } @@ -170,7 +171,7 @@ export async function deployDataSource(params: DeployDataSourceParams): Promise< } return response.status === 200; } catch (error) { - const errorMessage = error instanceof Error ? error.message : 'Failed to deploy data source'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.datasources.failedToDeployDataSource"); messageInstance.error(errorMessage); throw error; } diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/license.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/license.service.ts index ebc0ae46a..e2fac5ef6 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/license.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/license.service.ts @@ -1,4 +1,5 @@ import axios from 'axios'; +import { trans } from 'i18n'; import { EnvironmentLicense, DetailedLicenseInfo } from '../types/environment.types'; /** @@ -15,7 +16,7 @@ export async function checkEnvironmentLicense( if (!apiServiceUrl) { return { isValid: false, - error: 'API service URL is required' + error: trans('enterprise.environments.services.license.apiServiceUrlRequired') }; } @@ -30,7 +31,7 @@ export async function checkEnvironmentLicense( `${apiServiceUrl}/api/plugins/enterprise/license`, { headers, - timeout: 500 // Very short timeout for immediate failure when endpoint doesn't exist + timeout: 1500 // Very short timeout for immediate failure when endpoint doesn't exist } ); @@ -65,17 +66,17 @@ export async function checkEnvironmentLicense( } catch (error) { // Determine the specific error type - let errorMessage = 'License information unavailable'; + let errorMessage = trans('enterprise.environments.services.license.licenseInformationUnavailable'); if (axios.isAxiosError(error)) { if (error.code === 'ECONNABORTED') { - errorMessage = 'License check took too long'; + errorMessage = trans('enterprise.environments.services.license.licenseCheckTookTooLong'); } else if (error.response?.status === 404) { - errorMessage = 'License service not available'; + errorMessage = trans('enterprise.environments.services.license.licenseServiceNotAvailable'); } else if (error.response?.status === 401) { - errorMessage = 'Authentication required - please check API key'; + errorMessage = trans('enterprise.environments.services.license.authenticationRequired'); } else if (error.response && error.response.status >= 500) { - errorMessage = 'License service temporarily unavailable'; + errorMessage = trans('enterprise.environments.services.license.licenseServiceTemporarilyUnavailable'); } } @@ -96,7 +97,12 @@ export function formatAPICalls(remaining: number, total: number): string { const used = total - remaining; const percentage = total > 0 ? Math.round((used / total) * 100) : 0; - return `${remaining.toLocaleString()} remaining (${used.toLocaleString()}/${total.toLocaleString()} used, ${percentage}%)`; + return trans('enterprise.environments.services.license.remainingAPICalls', { + remaining: remaining.toLocaleString(), + used: used.toLocaleString(), + total: total.toLocaleString(), + percentage + }); } /** diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/managed-objects.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/managed-objects.service.ts index 0a4e0b14a..e70322221 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/managed-objects.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/managed-objects.service.ts @@ -1,5 +1,6 @@ import axios from "axios"; import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; +import { trans } from "i18n"; // Object types that can be managed export enum ManagedObjectType { @@ -32,7 +33,7 @@ export async function isManagedObject( ): Promise { try { if (!objGid || !environmentId || !objType) { - throw new Error("Missing required parameters"); + throw new Error(trans("enterprise.environments.services.managedObjects.missingRequiredParameters")); } const response = await axios.get(`/api/plugins/enterprise/managed-obj`, { @@ -50,7 +51,7 @@ export async function isManagedObject( return false; } - const errorMessage = error instanceof Error ? error.message : "Failed to check managed status"; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.managedObjects.failedToCheckManagedStatus"); messageInstance.error(errorMessage); throw error; } @@ -73,7 +74,7 @@ export async function setManagedObject( ): Promise { try { if (!objGid || !environmentId || !objType) { - throw new Error("Missing required parameters"); + throw new Error(trans("enterprise.environments.services.managedObjects.missingRequiredParameters")); } const requestBody = { @@ -87,7 +88,7 @@ export async function setManagedObject( return response.status === 200; } catch (error) { - const errorMessage = error instanceof Error ? error.message : `Failed to set ${objType} as managed`; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.managedObjects.failedToSetAsManaged", { objType }); messageInstance.error(errorMessage); throw error; } @@ -108,7 +109,7 @@ export async function unsetManagedObject( ): Promise { try { if (!objGid || !environmentId || !objType) { - throw new Error("Missing required parameters"); + throw new Error(trans("enterprise.environments.services.managedObjects.missingRequiredParameters")); } const response = await axios.delete(`/api/plugins/enterprise/managed-obj`, { @@ -121,7 +122,7 @@ export async function unsetManagedObject( return response.status === 200; } catch (error) { - const errorMessage = error instanceof Error ? error.message : `Failed to remove ${objType} from managed`; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.managedObjects.failedToRemoveFromManaged", { objType }); messageInstance.error(errorMessage); throw error; } @@ -134,7 +135,7 @@ export async function getManagedObjects( ): Promise { try { if (!environmentId) { - throw new Error("Missing environment ID"); + throw new Error(trans("enterprise.environments.services.managedObjects.missingEnvironmentId")); } const response = await axios.get(`/api/plugins/enterprise/managed-obj/list`, { @@ -146,7 +147,7 @@ export async function getManagedObjects( return response.data.data; } catch (error) { - const errorMessage = error instanceof Error ? error.message : "Failed to fetch managed objects"; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.managedObjects.failedToFetchManagedObjects"); messageInstance.error(errorMessage); throw error; } @@ -166,7 +167,7 @@ export async function getSingleManagedObject( ): Promise { try { if (!objGid || !environmentId || !objType) { - throw new Error("Missing required parameters"); + throw new Error(trans("enterprise.environments.services.managedObjects.missingRequiredParameters")); } const response = await axios.get(`/api/plugins/enterprise/managed-obj`, { @@ -184,7 +185,7 @@ export async function getSingleManagedObject( return null; } - const errorMessage = error instanceof Error ? error.message : "Failed to fetch managed object"; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.managedObjects.failedToFetchManagedObject"); messageInstance.error(errorMessage); throw error; } @@ -197,7 +198,7 @@ export async function transferManagedObject(objGid: string, sourceEnvId: string, if (managedObject) { await setManagedObject(managedObject.objGid, targetEnvId, objType, managedObject.managedId); } else { - throw new Error(`Managed object not found for objGid: ${objGid}`); + throw new Error(trans("enterprise.environments.services.managedObjects.managedObjectNotFound", { objGid })); } } catch (error) { console.error('Error transferring managed object:', error); diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/query.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/query.service.ts index 20b79f4ee..a79f10f87 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/query.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/query.service.ts @@ -2,6 +2,7 @@ * Get merged queries (both regular and managed) for a workspace */ import axios from 'axios'; +import { trans } from 'i18n'; import { getManagedObjects, ManagedObjectType, transferManagedObject } from './managed-objects.service'; import { getWorkspaceQueries } from './environments.service'; import { Query, QueryStats } from '../types/query.types'; diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/workspace.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/workspace.service.ts index b7cf4a37c..6cbe947ab 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/workspace.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/workspace.service.ts @@ -1,5 +1,6 @@ // services/workspacesService.ts (or wherever makes sense in your structure) import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; +import { trans } from "i18n"; import { getEnvironmentWorkspaces } from "./environments.service"; import { getManagedObjects, ManagedObject, ManagedObjectType, transferManagedObject } from "./managed-objects.service"; import { Workspace } from "../types/workspace.types"; @@ -69,7 +70,7 @@ export async function getMergedEnvironmentWorkspaces( } }; } catch (error) { - const errorMessage = error instanceof Error ? error.message : "Failed to fetch workspaces"; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.workspace.failedToFetchWorkspaces"); messageInstance.error(errorMessage); throw error; } @@ -107,7 +108,7 @@ export async function deployWorkspace(params: { return response.status === 200; } catch (error) { - const errorMessage = error instanceof Error ? error.message : 'Failed to deploy workspace'; + const errorMessage = error instanceof Error ? error.message : trans("enterprise.environments.services.workspace.failedToDeployWorkspace"); // Don't show message directly, let the calling component handle it throw new Error(errorMessage); } From bbc0828d5cb8c3a21c012625ea0652d6a5aea6b0 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Sat, 31 May 2025 01:43:50 +0500 Subject: [PATCH 13/13] remove duplicate trans import --- .../pages/setting/environments/services/environments.service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts b/client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts index 6ef0b0f01..a781184f4 100644 --- a/client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts +++ b/client/packages/lowcoder/src/pages/setting/environments/services/environments.service.ts @@ -8,7 +8,6 @@ import {App} from "../types/app.types"; import { DataSourceWithMeta } from '../types/datasource.types'; import { Query, QueryResponse } from "../types/query.types"; import { checkEnvironmentLicense } from './license.service'; -import { trans } from "i18n"; export async function updateEnvironment( environmentId: string, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy