@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 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
- program
41
- .version('1.0.0')
42
- .command('compile')
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
- program
84
- .command('create')
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 more advanced boilerplate that can be used as a tutorial like one.')
88
- .action((componentName, { extended }) => {
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
- const reactComponent = path.resolve(__dirname, 'templates', extended ? 'component_extended.tsx' : 'component_base.tsx');
96
- const javaComponent = path.resolve(__dirname, 'templates', extended ? 'component_extended.java' : 'component_base.java');
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 void setValue(SetValuePayload payload) throws BusClassException {
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('count', this.getValue('count') + 1, 0);
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 void setValue(SetValuePayload payload) throws BusClassException {
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
- state = {
69
- count: 0,
70
- };
71
-
72
- constructor() {
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.getAdditional<{
94
- instances: {
95
- name: string;
96
- description: string;
97
- monthlyPrice: string;
98
- }[];
99
- }>().instances.map((c) => (
100
- <Box
101
- className={`plan ${this.getStringValue('selectedPlan') === c.name ? 'selected' : ''}`}
102
- key={c.name}
103
- onClick={() => {
104
- this.setStringValue('selectedPlan', c.name);
105
- }}
106
- >
107
- <strong>{c.name}</strong>
108
- {this.getProperty('toggleAdvancedInfo') && <p>{c.description}</p>}
109
- <small>{c.monthlyPrice}</small>
110
- </Box>
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.20",
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": "dabff9ca7bf9d14298fe7a661d73607a35a4df2a",
17
+ "gitHead": "0c34ed891f366be27e3fb8d291b6c7c9d90eb201",
18
18
  "devDependencies": {
19
19
  "ts-loader": "^9.5.2",
20
20
  "wrapper-webpack-plugin": "^2.2.2"