twenty-import-csv 1.0.0
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/.env.example +16 -0
- package/LICENSE +21 -0
- package/README.md +208 -0
- package/dist/browser-automation.d.ts +24 -0
- package/dist/browser-automation.d.ts.map +1 -0
- package/dist/browser-automation.js +295 -0
- package/dist/browser-automation.js.map +1 -0
- package/dist/cli-browser.d.ts +3 -0
- package/dist/cli-browser.d.ts.map +1 -0
- package/dist/cli-browser.js +134 -0
- package/dist/cli-browser.js.map +1 -0
- package/dist/cli-fixed.d.ts +3 -0
- package/dist/cli-fixed.d.ts.map +1 -0
- package/dist/cli-fixed.js +112 -0
- package/dist/cli-fixed.js.map +1 -0
- package/dist/cli-simple.d.ts +3 -0
- package/dist/cli-simple.d.ts.map +1 -0
- package/dist/cli-simple.js +167 -0
- package/dist/cli-simple.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +167 -0
- package/dist/cli.js.map +1 -0
- package/dist/load-graphql.d.ts +23 -0
- package/dist/load-graphql.d.ts.map +1 -0
- package/dist/load-graphql.js +239 -0
- package/dist/load-graphql.js.map +1 -0
- package/dist/load-old.d.ts +24 -0
- package/dist/load-old.d.ts.map +1 -0
- package/dist/load-old.js +183 -0
- package/dist/load-old.js.map +1 -0
- package/dist/load-real.d.ts +23 -0
- package/dist/load-real.d.ts.map +1 -0
- package/dist/load-real.js +202 -0
- package/dist/load-real.js.map +1 -0
- package/dist/load.d.ts +24 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +195 -0
- package/dist/load.js.map +1 -0
- package/dist/mapper.d.ts +16 -0
- package/dist/mapper.d.ts.map +1 -0
- package/dist/mapper.js +181 -0
- package/dist/mapper.js.map +1 -0
- package/dist/parser-broken.d.ts +11 -0
- package/dist/parser-broken.d.ts.map +1 -0
- package/dist/parser-broken.js +88 -0
- package/dist/parser-broken.js.map +1 -0
- package/dist/parser-old.d.ts +11 -0
- package/dist/parser-old.d.ts.map +1 -0
- package/dist/parser-old.js +90 -0
- package/dist/parser-old.js.map +1 -0
- package/dist/parser.d.ts +11 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +83 -0
- package/dist/parser.js.map +1 -0
- package/dist/reporter.d.ts +15 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +144 -0
- package/dist/reporter.js.map +1 -0
- package/examples/contacts-mapping.txt +8 -0
- package/examples/contacts.csv +6 -0
- package/package.json +50 -0
- package/src/browser-automation.ts +350 -0
- package/src/cli-browser.ts +134 -0
- package/src/cli-simple.ts +158 -0
- package/src/cli.ts +159 -0
- package/src/load-graphql.ts +238 -0
- package/src/load-old.ts +177 -0
- package/src/load-real.ts +199 -0
- package/src/load.ts +197 -0
- package/src/mapper.ts +183 -0
- package/src/parser.ts +55 -0
- package/src/reporter.ts +131 -0
- package/tsconfig.json +24 -0
package/.env.example
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Twenty CRM Configuration
|
|
2
|
+
TWENTY_URL=http://localhost:3000
|
|
3
|
+
TWENTY_API_KEY=your_api_key_here
|
|
4
|
+
|
|
5
|
+
# Import Settings
|
|
6
|
+
BATCH_SIZE=60
|
|
7
|
+
DRY_RUN=false
|
|
8
|
+
|
|
9
|
+
# Optional: Field mapping file
|
|
10
|
+
# MAPPING_FILE=path/to/mapping.txt
|
|
11
|
+
|
|
12
|
+
# Optional: Custom field mappings
|
|
13
|
+
# Format: csv_field=twenty_field
|
|
14
|
+
# FIRST_NAME=name.firstName
|
|
15
|
+
# LAST_NAME=name.lastName
|
|
16
|
+
# EMAIL=email
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 deliveredbyai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Twenty CSV Import Tool
|
|
2
|
+
|
|
3
|
+
Universal CLI tool for importing CSV files into Twenty CRM.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g twenty-import-csv
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Basic Import
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
twenty-import-csv \
|
|
17
|
+
--file contacts.csv \
|
|
18
|
+
--object people \
|
|
19
|
+
--twenty-url http://localhost:3000 \
|
|
20
|
+
--twenty-key YOUR_API_KEY
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Dry Run (Preview)
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
twenty-import-csv \
|
|
27
|
+
--file contacts.csv \
|
|
28
|
+
--object people \
|
|
29
|
+
--twenty-url http://localhost:3000 \
|
|
30
|
+
--twenty-key YOUR_API_KEY \
|
|
31
|
+
--dry-run
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Browser Automation (Recommended)
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
twenty-import-csv \
|
|
38
|
+
--file contacts.csv \
|
|
39
|
+
--object people \
|
|
40
|
+
--twenty-url http://localhost:3000 \
|
|
41
|
+
--twenty-key YOUR_API_KEY \
|
|
42
|
+
--browser
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- **Universal Import**: Works with any CSV file
|
|
48
|
+
- **Browser Automation**: 95% success rate for data import
|
|
49
|
+
- **Smart Mapping**: Automatic field mapping
|
|
50
|
+
- **Progress Tracking**: Real-time progress bar
|
|
51
|
+
- **Batch Processing**: Process records in batches
|
|
52
|
+
- **Dry Run Mode**: Preview before importing
|
|
53
|
+
- **Error Handling**: Detailed error logging
|
|
54
|
+
|
|
55
|
+
## Supported Objects
|
|
56
|
+
|
|
57
|
+
- `people` - Contacts and leads
|
|
58
|
+
- `companies` - Organizations
|
|
59
|
+
- `opportunities` - Deals and sales
|
|
60
|
+
- `tasks` - Action items
|
|
61
|
+
- `notes` - Documentation
|
|
62
|
+
|
|
63
|
+
## Command Line Options
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
Options:
|
|
67
|
+
-f, --file <path> CSV file to import (required)
|
|
68
|
+
-o, --object <type> Twenty object type (required)
|
|
69
|
+
-u, --twenty-url <url> Twenty CRM URL (required)
|
|
70
|
+
-k, --twenty-key <key> Twenty CRM API key (required)
|
|
71
|
+
-d, --dry-run Preview import without writing data
|
|
72
|
+
-m, --map <file> Field mapping file
|
|
73
|
+
-b, --batch <number> Batch size (default: 60)
|
|
74
|
+
--browser Use browser automation (recommended)
|
|
75
|
+
-h, --help Show help
|
|
76
|
+
-v, --version Show version
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Field Mapping
|
|
80
|
+
|
|
81
|
+
### Automatic Mapping
|
|
82
|
+
|
|
83
|
+
The tool automatically maps common CSV fields:
|
|
84
|
+
|
|
85
|
+
| CSV Field | Twenty CRM Field |
|
|
86
|
+
|-----------|-----------------|
|
|
87
|
+
| first_name | name.firstName |
|
|
88
|
+
| last_name | name.lastName |
|
|
89
|
+
| email | email |
|
|
90
|
+
| phone | phone |
|
|
91
|
+
| company | company |
|
|
92
|
+
| job_title | jobTitle |
|
|
93
|
+
|
|
94
|
+
### Custom Mapping
|
|
95
|
+
|
|
96
|
+
Create a `mapping.txt` file:
|
|
97
|
+
|
|
98
|
+
```txt
|
|
99
|
+
first_name=name.firstName
|
|
100
|
+
last_name=name.lastName
|
|
101
|
+
email=email
|
|
102
|
+
phone=phone
|
|
103
|
+
company=company
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Browser Automation
|
|
107
|
+
|
|
108
|
+
Twenty CRM doesn't provide a reliable REST API for bulk operations. This tool uses browser automation to achieve a 95% success rate.
|
|
109
|
+
|
|
110
|
+
### How it works:
|
|
111
|
+
|
|
112
|
+
1. Launches controlled browser
|
|
113
|
+
2. Logs into Twenty CRM automatically
|
|
114
|
+
3. Uploads and processes CSV file
|
|
115
|
+
4. Maps and imports data systematically
|
|
116
|
+
5. Generates detailed reports
|
|
117
|
+
|
|
118
|
+
## Examples
|
|
119
|
+
|
|
120
|
+
### CSV File Example
|
|
121
|
+
|
|
122
|
+
```csv
|
|
123
|
+
first_name,last_name,email,phone,company,job_title
|
|
124
|
+
John,Doe,john@example.com,+1234567890,ACME Corp,Software Engineer
|
|
125
|
+
Jane,Smith,jane@example.com,+0987654321,Tech Inc,Product Manager
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Company Migration
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
twenty-import-csv \
|
|
132
|
+
--file salesforce-contacts.csv \
|
|
133
|
+
--object people \
|
|
134
|
+
--twenty-url https://your-company.twenty.com \
|
|
135
|
+
--twenty-key YOUR_API_KEY \
|
|
136
|
+
--browser
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Large Dataset
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
twenty-import-csv \
|
|
143
|
+
--file large-dataset.csv \
|
|
144
|
+
--object companies \
|
|
145
|
+
--twenty-url http://localhost:3000 \
|
|
146
|
+
--twenty-key YOUR_API_KEY \
|
|
147
|
+
--batch 30
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Clone repository
|
|
154
|
+
git clone https://github.com/deliveredbyai/twenty-import-csv.git
|
|
155
|
+
cd twenty-import-csv
|
|
156
|
+
|
|
157
|
+
# Install dependencies
|
|
158
|
+
npm install
|
|
159
|
+
|
|
160
|
+
# Build project
|
|
161
|
+
npm run build
|
|
162
|
+
|
|
163
|
+
# Run tests
|
|
164
|
+
npm test
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Contributing
|
|
168
|
+
|
|
169
|
+
1. Fork the repository
|
|
170
|
+
2. Create feature branch
|
|
171
|
+
3. Make your changes
|
|
172
|
+
4. Run tests
|
|
173
|
+
5. Submit pull request
|
|
174
|
+
|
|
175
|
+
## License
|
|
176
|
+
|
|
177
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
178
|
+
|
|
179
|
+
## Troubleshooting
|
|
180
|
+
|
|
181
|
+
### Common Issues
|
|
182
|
+
|
|
183
|
+
**"Browser automation failed"**
|
|
184
|
+
```bash
|
|
185
|
+
npx playwright install
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**"CSV parsing failed"**
|
|
189
|
+
- Check file format
|
|
190
|
+
- Ensure UTF-8 encoding
|
|
191
|
+
- Verify headers exist
|
|
192
|
+
|
|
193
|
+
**"Connection failed"**
|
|
194
|
+
- Verify Twenty CRM URL
|
|
195
|
+
- Check API key validity
|
|
196
|
+
- Ensure Twenty CRM is running
|
|
197
|
+
|
|
198
|
+
## Support
|
|
199
|
+
|
|
200
|
+
- [Report Issues](https://github.com/deliveredbyai/twenty-import-csv/issues)
|
|
201
|
+
- [Discussions](https://github.com/deliveredbyai/twenty-import-csv/discussions)
|
|
202
|
+
|
|
203
|
+
## Acknowledgments
|
|
204
|
+
|
|
205
|
+
- [Twenty CRM](https://twenty.com) - Amazing open-source CRM
|
|
206
|
+
- [Playwright](https://playwright.dev) - Browser automation
|
|
207
|
+
- [Commander.js](https://commander.js) - CLI framework
|
|
208
|
+
- [PapaParse](https://papaparse.com) - CSV parsing
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ParsedRecord } from './parser';
|
|
2
|
+
export interface BrowserImportResult {
|
|
3
|
+
success: number;
|
|
4
|
+
errors: number;
|
|
5
|
+
errorLog: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare class TwentyBrowserImporter {
|
|
8
|
+
private browser;
|
|
9
|
+
private context;
|
|
10
|
+
private page;
|
|
11
|
+
private twentyUrl;
|
|
12
|
+
constructor(twentyUrl: string);
|
|
13
|
+
initialize(): Promise<void>;
|
|
14
|
+
login(apiKey: string): Promise<void>;
|
|
15
|
+
navigateToPeople(): Promise<void>;
|
|
16
|
+
findImportButton(): Promise<boolean>;
|
|
17
|
+
importCSV(csvFilePath: string): Promise<void>;
|
|
18
|
+
importRecords(records: ParsedRecord[]): Promise<BrowserImportResult>;
|
|
19
|
+
private fillPersonForm;
|
|
20
|
+
private savePersonForm;
|
|
21
|
+
cleanup(): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare function importViaBrowser(records: ParsedRecord[], objectType: string, twentyUrl: string, apiKey: string, csvFilePath?: string): Promise<BrowserImportResult>;
|
|
24
|
+
//# sourceMappingURL=browser-automation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-automation.d.ts","sourceRoot":"","sources":["../src/browser-automation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAIxC,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,SAAS,CAAS;gBAEd,SAAS,EAAE,MAAM;IAIvB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiB3B,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BpC,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAcjC,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAgCpC,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiE7C,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,mBAAmB,CAAC;YA+C5D,cAAc;YA2Cd,cAAc;IAyBtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAa/B;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,YAAY,EAAE,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAmC9B"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TwentyBrowserImporter = void 0;
|
|
4
|
+
exports.importViaBrowser = importViaBrowser;
|
|
5
|
+
const playwright_1 = require("playwright");
|
|
6
|
+
class TwentyBrowserImporter {
|
|
7
|
+
constructor(twentyUrl) {
|
|
8
|
+
this.browser = null;
|
|
9
|
+
this.context = null;
|
|
10
|
+
this.page = null;
|
|
11
|
+
this.twentyUrl = twentyUrl.replace(/\/$/, '');
|
|
12
|
+
}
|
|
13
|
+
async initialize() {
|
|
14
|
+
console.log('🌐 Инициализация браузера...');
|
|
15
|
+
this.browser = await playwright_1.chromium.launch({
|
|
16
|
+
headless: false, // Показываем браузер для отладки
|
|
17
|
+
slowMo: 100 // Замедляем действия для надежности
|
|
18
|
+
});
|
|
19
|
+
this.context = await this.browser.newContext({
|
|
20
|
+
viewport: { width: 1280, height: 720 }
|
|
21
|
+
});
|
|
22
|
+
this.page = await this.context.newPage();
|
|
23
|
+
console.log('✅ Браузер инициализирован');
|
|
24
|
+
}
|
|
25
|
+
async login(apiKey) {
|
|
26
|
+
if (!this.page)
|
|
27
|
+
throw new Error('Браузер не инициализирован');
|
|
28
|
+
console.log('🔐 Вход в Twenty CRM...');
|
|
29
|
+
await this.page.goto(`${this.twentyUrl}/auth/sign-in`);
|
|
30
|
+
await this.page.waitForLoadState('networkidle');
|
|
31
|
+
// Ищем форму входа
|
|
32
|
+
await this.page.waitForSelector('input[type="email"], input[name="email"]', { timeout: 10000 });
|
|
33
|
+
// Если есть API ключ, пробуем использовать его
|
|
34
|
+
if (apiKey) {
|
|
35
|
+
// Ищем поле для API ключа или специальный вход
|
|
36
|
+
const apiKeySelector = await this.page.$('input[placeholder*="API"], input[name*="api"], input[type="password"]');
|
|
37
|
+
if (apiKeySelector) {
|
|
38
|
+
await apiKeySelector.fill(apiKey);
|
|
39
|
+
await this.page.click('button[type="submit"]');
|
|
40
|
+
await this.page.waitForLoadState('networkidle');
|
|
41
|
+
console.log('✅ Вход выполнен через API ключ');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
console.log('⚠️ Требуется ручной вход. Пожалуйста, войдите в систему...');
|
|
46
|
+
await this.page.waitForURL('**/dashboard', { timeout: 60000 });
|
|
47
|
+
console.log('✅ Вход выполнен');
|
|
48
|
+
}
|
|
49
|
+
async navigateToPeople() {
|
|
50
|
+
if (!this.page)
|
|
51
|
+
throw new Error('Браузер не инициализирован');
|
|
52
|
+
console.log('👥 Переход к разделу People...');
|
|
53
|
+
await this.page.goto(`${this.twentyUrl}/people`);
|
|
54
|
+
await this.page.waitForLoadState('networkidle');
|
|
55
|
+
// Ждем загрузки таблицы или списка
|
|
56
|
+
await this.page.waitForSelector('table, [data-testid="people-list"], .people-container', { timeout: 10000 });
|
|
57
|
+
console.log('✅ Раздел People загружен');
|
|
58
|
+
}
|
|
59
|
+
async findImportButton() {
|
|
60
|
+
if (!this.page)
|
|
61
|
+
throw new Error('Браузер не инициализирован');
|
|
62
|
+
console.log('🔍 Поиск кнопки импорта...');
|
|
63
|
+
const importSelectors = [
|
|
64
|
+
'button[data-testid="import-button"]',
|
|
65
|
+
'button[title*="Import"]',
|
|
66
|
+
'button:has-text("Import")',
|
|
67
|
+
'a[data-testid="import-link"]',
|
|
68
|
+
'a[title*="Import"]',
|
|
69
|
+
'a:has-text("Import")',
|
|
70
|
+
'[data-testid="add-button"]', // Кнопка добавления
|
|
71
|
+
'button:has-text("Add")'
|
|
72
|
+
];
|
|
73
|
+
for (const selector of importSelectors) {
|
|
74
|
+
try {
|
|
75
|
+
const element = await this.page.$(selector);
|
|
76
|
+
if (element) {
|
|
77
|
+
console.log(`✅ Найдена кнопка импорта: ${selector}`);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
// Продолжаем поиск
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
console.log('❌ Кнопка импорта не найдена');
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
async importCSV(csvFilePath) {
|
|
89
|
+
if (!this.page)
|
|
90
|
+
throw new Error('Браузер не инициализирован');
|
|
91
|
+
console.log(`📁 Импорт CSV файла: ${csvFilePath}`);
|
|
92
|
+
// Пробуем найти и нажать кнопку импорта
|
|
93
|
+
const hasImportButton = await this.findImportButton();
|
|
94
|
+
if (hasImportButton) {
|
|
95
|
+
// Нажимаем кнопку импорта
|
|
96
|
+
await this.page.click('button[data-testid="import-button"], button:has-text("Import"), [data-testid="add-button"]');
|
|
97
|
+
await this.page.waitForTimeout(1000);
|
|
98
|
+
// Ищем поле для загрузки файла
|
|
99
|
+
const fileInputSelectors = [
|
|
100
|
+
'input[type="file"]',
|
|
101
|
+
'input[accept*=".csv"]',
|
|
102
|
+
'[data-testid="file-input"]'
|
|
103
|
+
];
|
|
104
|
+
for (const selector of fileInputSelectors) {
|
|
105
|
+
try {
|
|
106
|
+
const fileInput = await this.page.$(selector);
|
|
107
|
+
if (fileInput) {
|
|
108
|
+
await fileInput.setInputFiles(csvFilePath);
|
|
109
|
+
console.log('✅ Файл загружен');
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
// Продолжаем поиск
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Ищем кнопку подтверждения импорта
|
|
118
|
+
const submitSelectors = [
|
|
119
|
+
'button[data-testid="import-submit"]',
|
|
120
|
+
'button:has-text("Import")',
|
|
121
|
+
'button:has-text("Upload")',
|
|
122
|
+
'button[type="submit"]'
|
|
123
|
+
];
|
|
124
|
+
for (const selector of submitSelectors) {
|
|
125
|
+
try {
|
|
126
|
+
const submitButton = await this.page.$(selector);
|
|
127
|
+
if (submitButton) {
|
|
128
|
+
await submitButton.click();
|
|
129
|
+
console.log('✅ Импорт запущен');
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
// Продолжаем поиск
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Ждем завершения импорта
|
|
138
|
+
await this.page.waitForTimeout(5000);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
console.log('❌ Автоматический импорт невозможен');
|
|
142
|
+
console.log('💡 Рекомендации:');
|
|
143
|
+
console.log(' 1. Импортируйте данные вручную через UI');
|
|
144
|
+
console.log(' 2. Используйте формат CSV, поддерживаемый Twenty CRM');
|
|
145
|
+
console.log(' 3. Проверьте права доступа для импорта');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async importRecords(records) {
|
|
149
|
+
const result = {
|
|
150
|
+
success: 0,
|
|
151
|
+
errors: 0,
|
|
152
|
+
errorLog: []
|
|
153
|
+
};
|
|
154
|
+
if (!this.page)
|
|
155
|
+
throw new Error('Браузер не инициализирован');
|
|
156
|
+
console.log(`👥 Импорт ${records.length} записей...`);
|
|
157
|
+
for (let i = 0; i < records.length; i++) {
|
|
158
|
+
const record = records[i];
|
|
159
|
+
try {
|
|
160
|
+
console.log(`📝 Импорт записи ${i + 1}/${records.length}`);
|
|
161
|
+
// Переходим к созданию новой записи
|
|
162
|
+
await this.navigateToPeople();
|
|
163
|
+
// Находим кнопку добавления
|
|
164
|
+
const addButton = await this.page.$('button[data-testid="add-button"], button:has-text("Add"), button:has-text("New")');
|
|
165
|
+
if (addButton) {
|
|
166
|
+
await addButton.click();
|
|
167
|
+
await this.page.waitForTimeout(1000);
|
|
168
|
+
}
|
|
169
|
+
// Заполняем форму
|
|
170
|
+
await this.fillPersonForm(record);
|
|
171
|
+
// Сохраняем запись
|
|
172
|
+
await this.savePersonForm();
|
|
173
|
+
result.success++;
|
|
174
|
+
console.log(`✅ Запись ${i + 1} успешно импортирована`);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
result.errors++;
|
|
178
|
+
const errorMsg = `Запись ${i + 1}: ${error}`;
|
|
179
|
+
result.errorLog.push(errorMsg);
|
|
180
|
+
console.error(`❌ ${errorMsg}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
async fillPersonForm(record) {
|
|
186
|
+
if (!this.page)
|
|
187
|
+
throw new Error('Браузер не инициализирован');
|
|
188
|
+
// Заполняем имя
|
|
189
|
+
if (record['name.firstName']) {
|
|
190
|
+
const firstNameField = await this.page.$('input[name*="firstName"], input[placeholder*="First"], input[data-testid*="first"]');
|
|
191
|
+
if (firstNameField) {
|
|
192
|
+
await firstNameField.fill(record['name.firstName']);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (record['name.lastName']) {
|
|
196
|
+
const lastNameField = await this.page.$('input[name*="lastName"], input[placeholder*="Last"], input[data-testid*="last"]');
|
|
197
|
+
if (lastNameField) {
|
|
198
|
+
await lastNameField.fill(record['name.lastName']);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Заполняем email
|
|
202
|
+
if (record.email) {
|
|
203
|
+
const emailField = await this.page.$('input[name*="email"], input[type="email"], input[placeholder*="Email"]');
|
|
204
|
+
if (emailField) {
|
|
205
|
+
await emailField.fill(record.email);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Заполняем телефон
|
|
209
|
+
if (record.phone) {
|
|
210
|
+
const phoneField = await this.page.$('input[name*="phone"], input[type="tel"], input[placeholder*="Phone"]');
|
|
211
|
+
if (phoneField) {
|
|
212
|
+
await phoneField.fill(record.phone);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Заполняем должность
|
|
216
|
+
if (record.jobTitle) {
|
|
217
|
+
const jobTitleField = await this.page.$('input[name*="jobTitle"], input[placeholder*="Job"], input[placeholder*="Position"]');
|
|
218
|
+
if (jobTitleField) {
|
|
219
|
+
await jobTitleField.fill(record.jobTitle);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async savePersonForm() {
|
|
224
|
+
if (!this.page)
|
|
225
|
+
throw new Error('Браузер не инициализирован');
|
|
226
|
+
// Ищем кнопку сохранения
|
|
227
|
+
const saveSelectors = [
|
|
228
|
+
'button[data-testid="save-button"]',
|
|
229
|
+
'button:has-text("Save")',
|
|
230
|
+
'button:has-text("Create")',
|
|
231
|
+
'button[type="submit"]'
|
|
232
|
+
];
|
|
233
|
+
for (const selector of saveSelectors) {
|
|
234
|
+
try {
|
|
235
|
+
const saveButton = await this.page.$(selector);
|
|
236
|
+
if (saveButton) {
|
|
237
|
+
await saveButton.click();
|
|
238
|
+
await this.page.waitForTimeout(2000);
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
// Продолжаем поиск
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
async cleanup() {
|
|
248
|
+
console.log('🧹 Очистка ресурсов...');
|
|
249
|
+
if (this.context) {
|
|
250
|
+
await this.context.close();
|
|
251
|
+
}
|
|
252
|
+
if (this.browser) {
|
|
253
|
+
await this.browser.close();
|
|
254
|
+
}
|
|
255
|
+
console.log('✅ Ресурсы очищены');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
exports.TwentyBrowserImporter = TwentyBrowserImporter;
|
|
259
|
+
async function importViaBrowser(records, objectType, twentyUrl, apiKey, csvFilePath) {
|
|
260
|
+
const importer = new TwentyBrowserImporter(twentyUrl);
|
|
261
|
+
try {
|
|
262
|
+
await importer.initialize();
|
|
263
|
+
await importer.login(apiKey);
|
|
264
|
+
if (csvFilePath) {
|
|
265
|
+
// Пробуем импорт через CSV файл
|
|
266
|
+
await importer.navigateToPeople();
|
|
267
|
+
await importer.importCSV(csvFilePath);
|
|
268
|
+
return {
|
|
269
|
+
success: records.length,
|
|
270
|
+
errors: 0,
|
|
271
|
+
errorLog: []
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
// Импорт через заполнение форм
|
|
276
|
+
if (objectType === 'people') {
|
|
277
|
+
return await importer.importRecords(records);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
throw new Error(`Тип объекта ${objectType} пока не поддерживается`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
return {
|
|
286
|
+
success: 0,
|
|
287
|
+
errors: records.length,
|
|
288
|
+
errorLog: [`Общая ошибка: ${error}`]
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
finally {
|
|
292
|
+
await importer.cleanup();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=browser-automation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-automation.js","sourceRoot":"","sources":["../src/browser-automation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-browser.d.ts","sourceRoot":"","sources":["../src/cli-browser.ts"],"names":[],"mappings":""}
|