mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
commit
74282cbe97
12 changed files with 37 additions and 46 deletions
2
.version
2
.version
|
|
@ -1 +1 @@
|
|||
2.21.0
|
||||
2.21.1
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2.21.0
|
||||
2.21.1
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useRef, useEffect, useState } from 'react';
|
||||
import { ToolTip } from '@/_components';
|
||||
import { appService } from '@/_services';
|
||||
import { handleHttpErrorMessages, validateAppName, validateName } from '@/_helpers/utils';
|
||||
import { handleHttpErrorMessages, validateName } from '@/_helpers/utils';
|
||||
import InfoOrErrorBox from './InfoOrErrorBox';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ function EditAppName({ appId, appName = '', onNameChanged }) {
|
|||
|
||||
const saveAppName = async (newName) => {
|
||||
const trimmedName = newName.trim();
|
||||
if (validateName(trimmedName, 'App name', true)?.errorMsg) {
|
||||
if (validateName(trimmedName, 'App', false, true)?.errorMsg) {
|
||||
setName(appName);
|
||||
clearError();
|
||||
setIsEditing(false);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ export default function AppCard({
|
|||
canCreateApp,
|
||||
canDeleteApp,
|
||||
deleteApp,
|
||||
cloneApp,
|
||||
exportApp,
|
||||
appActionModal,
|
||||
canUpdateApp,
|
||||
|
|
@ -85,7 +84,6 @@ export default function AppCard({
|
|||
canDeleteApp={canDeleteApp(app)}
|
||||
canUpdateApp={canUpdateApp(app)}
|
||||
deleteApp={() => deleteApp(app)}
|
||||
cloneApp={() => cloneApp(app)}
|
||||
exportApp={() => exportApp(app)}
|
||||
isMenuOpen={isMenuOpen}
|
||||
darkMode={darkMode}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ const AppList = (props) => {
|
|||
canDeleteApp={props.canDeleteApp}
|
||||
canUpdateApp={props.canUpdateApp}
|
||||
deleteApp={props.deleteApp}
|
||||
cloneApp={props.cloneApp}
|
||||
exportApp={props.exportApp}
|
||||
appActionModal={props.appActionModal}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -133,14 +133,14 @@ class HomePageComponent extends React.Component {
|
|||
_self.setState({ creatingApp: true });
|
||||
try {
|
||||
const data = await appService.createApp({ icon: sample(iconList), name: appName });
|
||||
|
||||
const workspaceId = getWorkspaceId();
|
||||
_self.props.navigate(`/${workspaceId}/apps/${data.id}`);
|
||||
toast.success('App created successfully!');
|
||||
_self.setState({ creatingApp: false });
|
||||
return true;
|
||||
} catch (errorResponse) {
|
||||
_self.setState({ creatingApp: false });
|
||||
if (errorResponse.statusCode === 409) {
|
||||
_self.setState({ creatingApp: false });
|
||||
return false;
|
||||
} else {
|
||||
throw errorResponse;
|
||||
|
|
@ -155,11 +155,11 @@ class HomePageComponent extends React.Component {
|
|||
await appService.saveApp(appId, { name: newAppName });
|
||||
await this.fetchApps();
|
||||
toast.success('App name has been updated!');
|
||||
_self.setState({ renamingApp: false });
|
||||
return true;
|
||||
} catch (errorResponse) {
|
||||
_self.setState({ renamingApp: false });
|
||||
if (errorResponse.statusCode === 409) {
|
||||
console.log(errorResponse);
|
||||
_self.setState({ renamingApp: false });
|
||||
return false;
|
||||
} else {
|
||||
throw errorResponse;
|
||||
|
|
@ -171,13 +171,16 @@ class HomePageComponent extends React.Component {
|
|||
this.setState({ showAppDeletionConfirmation: true, appToBeDeleted: app });
|
||||
};
|
||||
|
||||
cloneApp = async (appId, appName) => {
|
||||
cloneApp = async (appName, appId) => {
|
||||
this.setState({ isCloningApp: true });
|
||||
try {
|
||||
const data = await appService.cloneApp(appName, appId);
|
||||
const data = await appService.cloneResource({
|
||||
app: [{ id: appId, name: appName }],
|
||||
organization_id: getWorkspaceId(),
|
||||
});
|
||||
toast.success('App cloned successfully!');
|
||||
this.props.navigate(`/${getWorkspaceId()}/apps/${data?.imports?.app[0]?.id}`);
|
||||
this.setState({ isCloningApp: false });
|
||||
this.props.navigate(`/${getWorkspaceId()}/apps/${data.id}`);
|
||||
return true;
|
||||
} catch (_error) {
|
||||
this.setState({ isCloningApp: false });
|
||||
|
|
@ -221,9 +224,9 @@ class HomePageComponent extends React.Component {
|
|||
const organization_id = getWorkspaceId();
|
||||
const isLegacyImport = isEmpty(importJSON.tooljet_version);
|
||||
if (isLegacyImport) {
|
||||
importJSON = { app: [{ definition: importJSON }], tooljet_version: importJSON.tooljetVersion };
|
||||
importJSON = { app: [{ definition: importJSON, appName: appName }], tooljet_version: importJSON.tooljetVersion };
|
||||
}
|
||||
const requestBody = { organization_id, appName, ...importJSON };
|
||||
const requestBody = { organization_id, ...importJSON };
|
||||
try {
|
||||
const data = await appService.importResource(requestBody);
|
||||
toast.success('App imported successfully.');
|
||||
|
|
@ -841,7 +844,6 @@ class HomePageComponent extends React.Component {
|
|||
canDeleteApp={this.canDeleteApp}
|
||||
canUpdateApp={this.canUpdateApp}
|
||||
deleteApp={this.deleteApp}
|
||||
cloneApp={this.cloneApp}
|
||||
exportApp={this.exportApp}
|
||||
meta={meta}
|
||||
currentFolder={currentFolder}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { toast } from 'react-hot-toast';
|
|||
import Modal from '../HomePage/Modal';
|
||||
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
|
||||
import _ from 'lodash';
|
||||
import { validateAppName } from '@/_helpers/utils';
|
||||
import { validateName } from '@/_helpers/utils';
|
||||
|
||||
export function AppModal({
|
||||
closeModal,
|
||||
|
|
@ -105,7 +105,7 @@ export function AppModal({
|
|||
setInfoText('Maximum length has been reached');
|
||||
} else {
|
||||
setInfoText('');
|
||||
const error = validateAppName(trimmedName);
|
||||
const error = validateName(trimmedName, 'App', false);
|
||||
setErrorText(error?.errorMsg || '');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -920,26 +920,10 @@ export function isExpectedDataType(data, expectedDataType) {
|
|||
return data;
|
||||
}
|
||||
|
||||
export const validateAppName = (name, showError = false) => {
|
||||
export const validateName = (name, nameType, emptyCheck = true, showError = false, allowSpecialChars = true) => {
|
||||
const newName = name.trim();
|
||||
let errorMsg = '';
|
||||
if (newName.length > 50) {
|
||||
errorMsg = `Maximum length has been reached`;
|
||||
showError &&
|
||||
toast.error(errorMsg, {
|
||||
id: '1',
|
||||
});
|
||||
}
|
||||
return {
|
||||
status: !(errorMsg.length > 0),
|
||||
errorMsg,
|
||||
};
|
||||
};
|
||||
|
||||
export const validateName = (name, nameType, showError = false, allowSpecialChars = true) => {
|
||||
const newName = name.trim();
|
||||
let errorMsg = '';
|
||||
if (!newName) {
|
||||
if (emptyCheck && !newName) {
|
||||
errorMsg = `${nameType} can't be empty`;
|
||||
showError &&
|
||||
toast.error(errorMsg, {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2.21.0
|
||||
2.21.1
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { IsUUID, IsOptional } from 'class-validator';
|
||||
import { IsUUID, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
export class CloneResourcesDto {
|
||||
@IsOptional()
|
||||
|
|
@ -14,6 +14,9 @@ export class CloneResourcesDto {
|
|||
export class CloneAppDto {
|
||||
@IsUUID()
|
||||
id: string;
|
||||
|
||||
@IsString()
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class CloneTooljetDatabaseDto {
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@ export class ImportResourcesDto {
|
|||
@IsOptional()
|
||||
app: ImportAppDto[];
|
||||
|
||||
@IsOptional()
|
||||
appName: string;
|
||||
|
||||
@IsOptional()
|
||||
tooljet_database: ImportTooljetDatabaseDto[];
|
||||
}
|
||||
|
|
@ -20,6 +17,9 @@ export class ImportResourcesDto {
|
|||
export class ImportAppDto {
|
||||
@IsDefined()
|
||||
definition: any;
|
||||
|
||||
@IsString()
|
||||
appName: string;
|
||||
}
|
||||
|
||||
export class ImportTooljetDatabaseDto {
|
||||
|
|
|
|||
|
|
@ -59,12 +59,16 @@ export class ImportExportResourcesService {
|
|||
}
|
||||
|
||||
if (importResourcesDto.app) {
|
||||
const appName = importResourcesDto.appName;
|
||||
for (const appImportDto of importResourcesDto.app) {
|
||||
user.organizationId = importResourcesDto.organization_id;
|
||||
const createdApp = await this.appImportExportService.import(user, appImportDto.definition, appName, {
|
||||
tooljet_database: tableNameMapping,
|
||||
});
|
||||
const createdApp = await this.appImportExportService.import(
|
||||
user,
|
||||
appImportDto.definition,
|
||||
appImportDto.appName,
|
||||
{
|
||||
tooljet_database: tableNameMapping,
|
||||
}
|
||||
);
|
||||
imports.app.push({ id: createdApp.id, name: createdApp.name });
|
||||
}
|
||||
}
|
||||
|
|
@ -82,6 +86,7 @@ export class ImportExportResourcesService {
|
|||
|
||||
const resourceExport = await this.export(user, exportResourcesDto);
|
||||
resourceExport['organization_id'] = cloneResourcesDto.organization_id;
|
||||
resourceExport['app'][0]['appName'] = cloneResourcesDto.app[0].name;
|
||||
const clonedResource = await this.import(user, resourceExport as ImportResourcesDto, true);
|
||||
|
||||
return clonedResource;
|
||||
|
|
|
|||
Loading…
Reference in a new issue