@apia/cli 4.0.20 → 4.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/cli.cjs +31 -13
- package/cli/templates/component_base.java +3 -2
- package/cli/templates/component_base.tsx +13 -2
- package/cli/templates/component_extended.java +4 -2
- package/cli/templates/component_extended.tsx +31 -30
- package/cli/templates/component_uploader.java +18 -0
- package/cli/templates/component_uploader.tsx +76 -0
- package/package.json +2 -2
package/cli/cli.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { program } = require('commander');
|
|
3
|
+
const { program, Command } = require('commander');
|
|
4
4
|
const { spawn } = require('child_process');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
const fs = require('fs');
|
|
@@ -32,14 +32,19 @@ function componentFolderResolver(componentName) {
|
|
|
32
32
|
return path.resolve(process.cwd(), 'components', componentName)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
program
|
|
36
|
+
.description("The Apia command line is intended to help on new projects development.\n\nIt offers utilities related to create and compile custom components.")
|
|
37
|
+
.version('1.0.0');
|
|
38
|
+
|
|
35
39
|
/**
|
|
36
40
|
* Starts webpack on the given component.
|
|
37
41
|
*
|
|
38
42
|
* - If --watch flag is passed, run webpack in development mode.
|
|
39
43
|
*/
|
|
40
|
-
|
|
41
|
-
.
|
|
42
|
-
|
|
44
|
+
const compile = new Command('compile')
|
|
45
|
+
.description('Base command for compiling Apia development elements');
|
|
46
|
+
|
|
47
|
+
compile.command('component')
|
|
43
48
|
.argument('<component_name>', 'The name of the component to be compiled.')
|
|
44
49
|
.description('Compiles the component into the OUT_DIR declared in the .env file.')
|
|
45
50
|
.option('--watch', 'Starts the compiler in watch mode.')
|
|
@@ -73,27 +78,37 @@ program
|
|
|
73
78
|
} else {
|
|
74
79
|
throw new Error("Cannot find .env file");
|
|
75
80
|
}
|
|
76
|
-
})
|
|
81
|
+
})
|
|
82
|
+
|
|
77
83
|
|
|
78
84
|
/**
|
|
79
85
|
* Makes a component inside ./<component_name>/index.tsx
|
|
80
86
|
*
|
|
81
87
|
* - If the component exists, warn the user and do nothing.
|
|
82
88
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
const create = new Command('create').description("Base command for creating Apia development elements")
|
|
90
|
+
create
|
|
91
|
+
.command('component')
|
|
85
92
|
.argument('<component_name>', 'The name of the component to be created.')
|
|
86
93
|
.description('Creates the boilerplate for the given component name.')
|
|
87
|
-
.option('--extended', 'Creates a
|
|
88
|
-
.
|
|
94
|
+
.option('--extended', 'Creates a plans selector that can be used as an example of how to manage multiple attributes, properties and events.')
|
|
95
|
+
.option('--uploader', 'Creates an uploader component that can be used as an example of how to upload files using custom components.')
|
|
96
|
+
.action((componentName, { extended, uploader }) => {
|
|
89
97
|
const parsedName = componentName.charAt(0).toUpperCase() + componentName.slice(1);
|
|
90
98
|
const snakeName = parsedName.split(/([A-Z][a-z0-9_-]+)/).filter(Boolean).map(c => c.toLowerCase()).join('_');
|
|
91
99
|
|
|
92
100
|
const destinationDir = componentFolderResolver(parsedName);
|
|
93
101
|
const destinationReact = path.resolve(destinationDir, 'index.tsx');
|
|
94
102
|
const destinationJava = path.resolve(destinationDir, 'component.java');
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
|
|
104
|
+
if ([extended, uploader].filter(Boolean).length > 1) {
|
|
105
|
+
throw new Error("Cannot use multiple example components as base. You must choose one.")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let strBase = extended ? 'extended' : uploader ? 'uploader' : 'base';
|
|
109
|
+
|
|
110
|
+
const reactComponent = path.resolve(__dirname, 'templates', `component_${strBase}.tsx`);
|
|
111
|
+
const javaComponent = path.resolve(__dirname, 'templates', `component_${strBase}.java`);
|
|
97
112
|
|
|
98
113
|
if (fs.existsSync(destinationReact)) {
|
|
99
114
|
logger.error(`Already exists component with name "${parsedName}" in ${destinationReact}`);
|
|
@@ -122,7 +137,10 @@ program
|
|
|
122
137
|
|
|
123
138
|
logger.success(`Plugin created at: ${destinationDir}`);
|
|
124
139
|
}
|
|
125
|
-
})
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
program.addCommand(compile);
|
|
143
|
+
program.addCommand(create);
|
|
126
144
|
|
|
127
145
|
|
|
128
146
|
program.parse(process.argv);
|
|
@@ -31,8 +31,9 @@ public class __COMPONENT_NAME__ extends AbstractCustomComponent {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
@Override
|
|
34
|
-
public
|
|
35
|
-
super.setValue(payload);
|
|
34
|
+
public Xml setValue(SetValuePayload payload) throws BusClassException {
|
|
35
|
+
Xml result = super.setValue(payload);
|
|
36
36
|
onChange.fire();
|
|
37
|
+
return result;
|
|
37
38
|
}
|
|
38
39
|
}
|
|
@@ -19,16 +19,27 @@ class __COMPONENT_NAME__ extends AbstractCustomComponent {
|
|
|
19
19
|
makeObservable(this, { state: observable });
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
protected init() {
|
|
23
|
+
/**
|
|
24
|
+
* En general este método se utiliza para leer estados adicionales,
|
|
25
|
+
* generados con el método getAdditionalState() en el server.
|
|
26
|
+
*/
|
|
27
|
+
}
|
|
28
|
+
|
|
22
29
|
protected Component: FC = observer(() => {
|
|
23
30
|
return (
|
|
24
31
|
<Box className="__COMPONENT_NAME_SNAKE__" sx={__COMPONENT_NAME__Styles}>
|
|
25
32
|
<SimpleButton
|
|
26
33
|
disabled={this.isLoading}
|
|
27
34
|
onClick={() => {
|
|
28
|
-
this.setValue(
|
|
35
|
+
this.handler.setValue(
|
|
36
|
+
'count',
|
|
37
|
+
this.handler.getValue('count') + 1,
|
|
38
|
+
0,
|
|
39
|
+
);
|
|
29
40
|
}}
|
|
30
41
|
>
|
|
31
|
-
{this.getValue('count', 0)}
|
|
42
|
+
{this.handler.getValue('count', 0)}
|
|
32
43
|
</SimpleButton>
|
|
33
44
|
</Box>
|
|
34
45
|
);
|
|
@@ -95,8 +95,8 @@ public class __COMPONENT_NAME__ extends AbstractCustomComponent {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
@Override
|
|
98
|
-
public
|
|
99
|
-
super.setValue(payload);
|
|
98
|
+
public Xml setValue(SetValuePayload payload) throws BusClassException {
|
|
99
|
+
Xml result = super.setValue(payload);
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
102
|
* Solo se dispara el evento onChange si se setea el plan seleccionado.
|
|
@@ -106,6 +106,8 @@ public class __COMPONENT_NAME__ extends AbstractCustomComponent {
|
|
|
106
106
|
if ("selectedPlan".equals(payload.getAttName())) {
|
|
107
107
|
onChange.schedule();
|
|
108
108
|
}
|
|
109
|
+
|
|
110
|
+
return result;
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
@Override
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
2
|
import { AbstractCustomComponent, Plugin } from '@apia/execution-react';
|
|
3
|
-
import { makeObservable, observable } from 'mobx';
|
|
4
3
|
import { observer } from 'mobx-react-lite';
|
|
5
4
|
import {
|
|
6
5
|
Box,
|
|
@@ -65,50 +64,52 @@ const __COMPONENT_NAME__Styles: ThemeUICSSObject = {
|
|
|
65
64
|
};
|
|
66
65
|
|
|
67
66
|
class __COMPONENT_NAME__ extends AbstractCustomComponent {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
super();
|
|
74
|
-
makeObservable(this, { state: observable });
|
|
67
|
+
protected init() {
|
|
68
|
+
/**
|
|
69
|
+
* En general este método se utiliza para leer estados adicionales,
|
|
70
|
+
* generados con el método getAdditionalState() en el server.
|
|
71
|
+
*/
|
|
75
72
|
}
|
|
76
73
|
|
|
77
74
|
protected Component: FC = observer(() => {
|
|
78
|
-
console.log(this.getStringValue('selectedPlan'));
|
|
75
|
+
console.log(this.handler.getStringValue('selectedPlan'));
|
|
79
76
|
return (
|
|
80
77
|
<Box className="__COMPONENT_NAME_SNAKE__" sx={__COMPONENT_NAME__Styles}>
|
|
81
78
|
<Heading as="h3">Selecciona un plan</Heading>
|
|
82
79
|
<Label>
|
|
83
80
|
<Checkbox
|
|
84
81
|
native
|
|
85
|
-
checked={this.getProperty('toggleAdvancedInfo')}
|
|
82
|
+
checked={this.handler.getProperty('toggleAdvancedInfo')}
|
|
86
83
|
onChange={(ev) => {
|
|
87
|
-
this.setProperty('toggleAdvancedInfo', ev.target.checked);
|
|
84
|
+
this.handler.setProperty('toggleAdvancedInfo', ev.target.checked);
|
|
88
85
|
}}
|
|
89
86
|
/>
|
|
90
87
|
{getLabel('toggleAdvancedInfo').text}
|
|
91
88
|
</Label>
|
|
92
89
|
<Box className="plans">
|
|
93
|
-
{this.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
90
|
+
{this.handler
|
|
91
|
+
.getAdditional<{
|
|
92
|
+
instances: {
|
|
93
|
+
name: string;
|
|
94
|
+
description: string;
|
|
95
|
+
monthlyPrice: string;
|
|
96
|
+
}[];
|
|
97
|
+
}>()
|
|
98
|
+
.instances.map((c) => (
|
|
99
|
+
<Box
|
|
100
|
+
className={`plan ${this.handler.getStringValue('selectedPlan') === c.name ? 'selected' : ''}`}
|
|
101
|
+
key={c.name}
|
|
102
|
+
onClick={() => {
|
|
103
|
+
this.handler.setStringValue('selectedPlan', c.name);
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<strong>{c.name}</strong>
|
|
107
|
+
{this.handler.getProperty('toggleAdvancedInfo') && (
|
|
108
|
+
<p>{c.description}</p>
|
|
109
|
+
)}
|
|
110
|
+
<small>{c.monthlyPrice}</small>
|
|
111
|
+
</Box>
|
|
112
|
+
))}
|
|
112
113
|
</Box>
|
|
113
114
|
<Heading as="h3">Deja un comentario</Heading>
|
|
114
115
|
<Textarea
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
package test;
|
|
2
|
+
|
|
3
|
+
import com.dogma.busClass.customComponent.AbstractCustomComponent;
|
|
4
|
+
import com.dogma.busClass.customComponent.CustomComponentAttribute;
|
|
5
|
+
import com.dogma.busClass.customComponent.CustomComponentData;
|
|
6
|
+
|
|
7
|
+
@CustomComponentData(
|
|
8
|
+
name = "__COMPONENT_NAME__",
|
|
9
|
+
title = "Files uploader",
|
|
10
|
+
description = "Componente de demo que permite la carga de archivos.")
|
|
11
|
+
public class __COMPONENT_NAME__ extends AbstractCustomComponent {
|
|
12
|
+
@CustomComponentAttribute(
|
|
13
|
+
name = "uploaded",
|
|
14
|
+
title = "Archivos subidos",
|
|
15
|
+
description = "Este atributo esetá marcado con isDocument=true, lo que permite al server tratarlo diferente por conveniencia para el cliente.",
|
|
16
|
+
isDocument = true)
|
|
17
|
+
public Attribute uploaded;
|
|
18
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { AbstractCustomComponent, Plugin } from '@apia/execution-react';
|
|
3
|
+
import { Box, ThemeUICSSObject } from '@apia/theme';
|
|
4
|
+
import {
|
|
5
|
+
UploadHandler,
|
|
6
|
+
Uploader as ExternalUploaderComponent,
|
|
7
|
+
} from '@apia/components';
|
|
8
|
+
|
|
9
|
+
const __COMPONENT_NAME__Styles: ThemeUICSSObject = {
|
|
10
|
+
'&.__COMPONENT_NAME_SNAKE__': {},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type UploaderState = { name: string; index: number }[];
|
|
14
|
+
|
|
15
|
+
class __COMPONENT_NAME__ extends AbstractCustomComponent {
|
|
16
|
+
/**
|
|
17
|
+
* El uploader handler es una clase utilitaria que se usa para gestionar la vista de upload.
|
|
18
|
+
*
|
|
19
|
+
* La ventaja más específica que tiene es que se mapea directamente con el componente Uploader
|
|
20
|
+
* de @apia/components, lo cual permite un manejo muy sencillo del upload de archivos.
|
|
21
|
+
*/
|
|
22
|
+
uploadHandler = new UploadHandler({
|
|
23
|
+
initialFiles: [],
|
|
24
|
+
isMultiple: true,
|
|
25
|
+
onDelete: async (_file) => {
|
|
26
|
+
/**
|
|
27
|
+
* El método onDelete del uploadHandler se mapea directamente con el método removeIndex del CustomComponent::Handler
|
|
28
|
+
*/
|
|
29
|
+
const result = await this.handler.removeIndex(
|
|
30
|
+
'uploaded',
|
|
31
|
+
_file.id as number,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return result || 'Something went wrong when deleting the file';
|
|
35
|
+
},
|
|
36
|
+
onUpload: async (file) => {
|
|
37
|
+
/**
|
|
38
|
+
* El método onUpload del uploadHandler se mapea directamente con el método upload del CustomComponent::Handler
|
|
39
|
+
*/
|
|
40
|
+
const result = await this.handler.upload('uploaded', file.file, {
|
|
41
|
+
signal: file.abortController?.signal,
|
|
42
|
+
onUploadProgress: (p) => (file.progress = p),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (result?.success) {
|
|
46
|
+
/**
|
|
47
|
+
* Si todo salió bien obtenemos el índice donde fue colocado el archivo y el nombre del mismo, que coincide
|
|
48
|
+
* con el nombre original del archivo.
|
|
49
|
+
*/
|
|
50
|
+
return { id: result.index, name: result.fileName };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return 'Something went wrong when uploading the file';
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
protected init() {
|
|
58
|
+
/**
|
|
59
|
+
* Cuando el atributo se marca con isDocument=true, el server responde con el tipo UploaderState,
|
|
60
|
+
* que podemos usarlo para mapear el estado inicial del uploader.
|
|
61
|
+
*/
|
|
62
|
+
this.uploadHandler.state.uploadedFiles = (
|
|
63
|
+
this.handler.getValues('uploaded') as UploaderState
|
|
64
|
+
).map((c) => ({ id: c.index, name: c.name }));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
protected Component: FC = () => {
|
|
68
|
+
return (
|
|
69
|
+
<Box className="__COMPONENT_NAME_SNAKE__" sx={__COMPONENT_NAME__Styles}>
|
|
70
|
+
<ExternalUploaderComponent handler={this.uploadHandler} />
|
|
71
|
+
</Box>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
new Plugin('__COMPONENT_NAME__', __COMPONENT_NAME__);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apia/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.24",
|
|
4
4
|
"sideEffects": true,
|
|
5
5
|
"author": "Alexis Leite <alexisleite@live.com>",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"access": "public",
|
|
15
15
|
"registry": "https://registry.npmjs.org/"
|
|
16
16
|
},
|
|
17
|
-
"gitHead": "
|
|
17
|
+
"gitHead": "0c34ed891f366be27e3fb8d291b6c7c9d90eb201",
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"ts-loader": "^9.5.2",
|
|
20
20
|
"wrapper-webpack-plugin": "^2.2.2"
|