@rashidazarang/airtable-mcp 2.1.0 → 2.1.1
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/package.json +10 -1
- package/.github/ISSUE_TEMPLATE/bug-report.yml +0 -173
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
- package/.github/ISSUE_TEMPLATE/custom.md +0 -10
- package/.github/ISSUE_TEMPLATE/feature-request.yml +0 -209
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
- package/.github/ISSUE_TEMPLATE/security-report.yml +0 -216
- package/.github/pull_request_template.md +0 -245
- package/.github/workflows/ci-cd.yml +0 -408
- package/.github/workflows/security-audit.yml +0 -316
- package/API_DOCUMENTATION.md +0 -897
- package/CAPABILITY_REPORT.md +0 -118
- package/CLAUDE_INTEGRATION.md +0 -96
- package/CODE_OF_CONDUCT.md +0 -181
- package/CONTRIBUTING.md +0 -81
- package/DEVELOPMENT.md +0 -190
- package/Dockerfile +0 -39
- package/Dockerfile.node +0 -20
- package/Dockerfile.production +0 -127
- package/IMPROVEMENT_PROPOSAL.md +0 -371
- package/INSTALLATION.md +0 -183
- package/ISSUE_RESPONSES.md +0 -171
- package/MCP_REVIEW_SUMMARY.md +0 -142
- package/QUICK_START.md +0 -60
- package/RELEASE_NOTES_v1.2.0.md +0 -50
- package/RELEASE_NOTES_v1.2.1.md +0 -40
- package/RELEASE_NOTES_v1.2.2.md +0 -48
- package/RELEASE_NOTES_v1.2.3.md +0 -105
- package/RELEASE_NOTES_v1.2.4.md +0 -60
- package/RELEASE_NOTES_v1.4.0.md +0 -104
- package/RELEASE_NOTES_v1.5.0.md +0 -185
- package/RELEASE_NOTES_v1.6.0.md +0 -248
- package/SECURITY_NOTICE.md +0 -40
- package/airtable-clipper/CHANGELOG.md +0 -198
- package/airtable-clipper/CHROME_STORE_SUBMISSION.md +0 -343
- package/airtable-clipper/LAUNCH_STRATEGY.md +0 -495
- package/airtable-clipper/LICENSE +0 -21
- package/airtable-clipper/OAUTH_SETUP.md +0 -51
- package/airtable-clipper/PRIVACY_POLICY.md +0 -187
- package/airtable-clipper/README.md +0 -575
- package/airtable-clipper/SUBMIT_TO_CHROME_STORE.md +0 -273
- package/airtable-clipper/build.sh +0 -85
- package/airtable-clipper/docs/QUICK_START.md +0 -99
- package/airtable-clipper/docs/SETUP.md +0 -291
- package/airtable-clipper/extension/background.js +0 -337
- package/airtable-clipper/extension/base-setup.html +0 -324
- package/airtable-clipper/extension/base-setup.js +0 -471
- package/airtable-clipper/extension/content.js +0 -771
- package/airtable-clipper/extension/icons/README.md +0 -69
- package/airtable-clipper/extension/icons/icon-16.png +0 -3
- package/airtable-clipper/extension/manifest.json +0 -73
- package/airtable-clipper/extension/popup.html +0 -144
- package/airtable-clipper/extension/popup.js +0 -475
- package/airtable-clipper/extension/styles/content.css +0 -229
- package/airtable-clipper/extension/styles/popup.css +0 -477
- package/airtable-clipper/privacy-policy.md +0 -63
- package/airtable-clipper/releases/v1.0.0/background.js +0 -337
- package/airtable-clipper/releases/v1.0.0/base-setup.html +0 -324
- package/airtable-clipper/releases/v1.0.0/base-setup.js +0 -471
- package/airtable-clipper/releases/v1.0.0/content.js +0 -771
- package/airtable-clipper/releases/v1.0.0/icons/README.md +0 -69
- package/airtable-clipper/releases/v1.0.0/icons/icon-128.png +0 -2
- package/airtable-clipper/releases/v1.0.0/icons/icon-16.png +0 -3
- package/airtable-clipper/releases/v1.0.0/icons/icon-32.png +0 -2
- package/airtable-clipper/releases/v1.0.0/icons/icon-48.png +0 -2
- package/airtable-clipper/releases/v1.0.0/manifest.json +0 -73
- package/airtable-clipper/releases/v1.0.0/popup.html +0 -144
- package/airtable-clipper/releases/v1.0.0/popup.js +0 -475
- package/airtable-clipper/releases/v1.0.0/sidepanel.html +0 -25
- package/airtable-clipper/releases/v1.0.0/styles/content.css +0 -229
- package/airtable-clipper/releases/v1.0.0/styles/popup.css +0 -477
- package/airtable-clipper/releases/v1.0.1/background.js +0 -337
- package/airtable-clipper/releases/v1.0.1/base-setup.html +0 -324
- package/airtable-clipper/releases/v1.0.1/base-setup.js +0 -471
- package/airtable-clipper/releases/v1.0.1/content.js +0 -771
- package/airtable-clipper/releases/v1.0.1/icons/README.md +0 -69
- package/airtable-clipper/releases/v1.0.1/icons/icon-128.png +0 -2
- package/airtable-clipper/releases/v1.0.1/icons/icon-16.png +0 -3
- package/airtable-clipper/releases/v1.0.1/icons/icon-32.png +0 -2
- package/airtable-clipper/releases/v1.0.1/icons/icon-48.png +0 -2
- package/airtable-clipper/releases/v1.0.1/manifest.json +0 -70
- package/airtable-clipper/releases/v1.0.1/popup.html +0 -157
- package/airtable-clipper/releases/v1.0.1/popup.js +0 -562
- package/airtable-clipper/releases/v1.0.1/sidepanel.html +0 -25
- package/airtable-clipper/releases/v1.0.1/styles/content.css +0 -229
- package/airtable-clipper/releases/v1.0.1/styles/popup.css +0 -647
- package/airtable-clipper/releases/v1.0.2/background.js +0 -337
- package/airtable-clipper/releases/v1.0.2/base-setup.html +0 -324
- package/airtable-clipper/releases/v1.0.2/base-setup.js +0 -471
- package/airtable-clipper/releases/v1.0.2/content.js +0 -771
- package/airtable-clipper/releases/v1.0.2/icons/README.md +0 -69
- package/airtable-clipper/releases/v1.0.2/icons/icon-128.png +0 -2
- package/airtable-clipper/releases/v1.0.2/icons/icon-16.png +0 -3
- package/airtable-clipper/releases/v1.0.2/icons/icon-32.png +0 -2
- package/airtable-clipper/releases/v1.0.2/icons/icon-48.png +0 -2
- package/airtable-clipper/releases/v1.0.2/manifest.json +0 -62
- package/airtable-clipper/releases/v1.0.2/popup.html +0 -157
- package/airtable-clipper/releases/v1.0.2/popup.js +0 -567
- package/airtable-clipper/releases/v1.0.2/sidepanel.html +0 -25
- package/airtable-clipper/releases/v1.0.2/styles/content.css +0 -229
- package/airtable-clipper/releases/v1.0.2/styles/popup.css +0 -647
- package/airtable-clipper/terms-of-service.md +0 -124
- package/airtable-clipper/test-credentials.md +0 -61
- package/airtable-clipper/test-extension/background.js +0 -337
- package/airtable-clipper/test-extension/base-setup.html +0 -324
- package/airtable-clipper/test-extension/base-setup.js +0 -471
- package/airtable-clipper/test-extension/content.js +0 -873
- package/airtable-clipper/test-extension/icons/README.md +0 -69
- package/airtable-clipper/test-extension/icons/icon-128.png +0 -2
- package/airtable-clipper/test-extension/icons/icon-16.png +0 -3
- package/airtable-clipper/test-extension/icons/icon-32.png +0 -2
- package/airtable-clipper/test-extension/icons/icon-48.png +0 -2
- package/airtable-clipper/test-extension/manifest.json +0 -72
- package/airtable-clipper/test-extension/popup.html +0 -274
- package/airtable-clipper/test-extension/popup.js +0 -729
- package/airtable-clipper/test-extension/sidepanel.html +0 -25
- package/airtable-clipper/test-extension/styles/content.css +0 -229
- package/airtable-clipper/test-extension/styles/popup.css +0 -794
- package/airtable_mcp/__init__.py +0 -5
- package/airtable_mcp/src/server.py +0 -329
- package/airtable_mcp_v2.js +0 -1505
- package/airtable_mcp_v2_oauth.js +0 -1048
- package/airtable_mcp_v3_advanced.js +0 -1161
- package/cleanup.sh +0 -71
- package/docker-compose.production.yml +0 -366
- package/helm/airtable-mcp/Chart.yaml +0 -122
- package/helm/airtable-mcp/values.yaml +0 -538
- package/index.js +0 -179
- package/inspector.py +0 -148
- package/inspector_server.py +0 -337
- package/k8s/deployment.yaml +0 -402
- package/k8s/namespace.yaml +0 -108
- package/k8s/service.yaml +0 -194
- package/monitoring/alerts.yml +0 -289
- package/monitoring/prometheus.yml +0 -224
- package/publish-steps.txt +0 -27
- package/quick_test.sh +0 -30
- package/requirements.txt +0 -10
- package/setup.py +0 -29
- package/simple_airtable_server.py +0 -151
- package/smithery.yaml +0 -45
- package/test_all_features.sh +0 -146
- package/test_all_operations.sh +0 -120
- package/test_client.py +0 -70
- package/test_enhanced_features.js +0 -389
- package/test_mcp_comprehensive.js +0 -163
- package/test_mock_server.js +0 -180
- package/test_v1.4.0_final.sh +0 -131
- package/test_v1.5.0_comprehensive.sh +0 -96
- package/test_v1.5.0_final.sh +0 -224
- package/test_v1.6.0_comprehensive.sh +0 -187
- package/test_webhooks.sh +0 -105
|
@@ -1,471 +0,0 @@
|
|
|
1
|
-
// Airtable Clipper Base Setup Wizard
|
|
2
|
-
import { BaseTemplate } from './lib/base-template.js';
|
|
3
|
-
import { AirtableClient } from './lib/airtable-client.js';
|
|
4
|
-
|
|
5
|
-
class BaseSetupWizard {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.currentStep = 1;
|
|
8
|
-
this.maxStep = 4;
|
|
9
|
-
this.setupMethod = 'template';
|
|
10
|
-
this.template = null;
|
|
11
|
-
this.baseTemplate = new BaseTemplate();
|
|
12
|
-
this.init();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
init() {
|
|
16
|
-
this.bindEvents();
|
|
17
|
-
this.updateStepIndicator();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
bindEvents() {
|
|
21
|
-
// Setup method radio buttons
|
|
22
|
-
document.querySelectorAll('input[name="setupMethod"]').forEach(radio => {
|
|
23
|
-
radio.addEventListener('change', (e) => {
|
|
24
|
-
this.setupMethod = e.target.value;
|
|
25
|
-
this.updateStep2Content();
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
// Table checkboxes
|
|
30
|
-
document.querySelectorAll('#step2 input[type="checkbox"]').forEach(checkbox => {
|
|
31
|
-
checkbox.addEventListener('change', () => {
|
|
32
|
-
this.updatePreview();
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Base name input
|
|
37
|
-
document.getElementById('baseName').addEventListener('input', () => {
|
|
38
|
-
this.updatePreview();
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
updateStep2Content() {
|
|
43
|
-
const step2 = document.getElementById('step2');
|
|
44
|
-
const step3NextBtn = document.getElementById('step3NextBtn');
|
|
45
|
-
|
|
46
|
-
if (this.setupMethod === 'existing') {
|
|
47
|
-
step2.querySelector('h2').textContent = '🔍 Validate Existing Base';
|
|
48
|
-
step2.querySelector('p').textContent = 'We\'ll check your current Airtable base structure and suggest improvements.';
|
|
49
|
-
step3NextBtn.textContent = 'Validate Base';
|
|
50
|
-
} else {
|
|
51
|
-
step2.querySelector('h2').textContent = '📋 Configure Your Database';
|
|
52
|
-
step2.querySelector('p').textContent = 'Customize which tables to include based on your use case:';
|
|
53
|
-
step3NextBtn.textContent = 'Create Database';
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async nextStep() {
|
|
58
|
-
if (this.currentStep < this.maxStep) {
|
|
59
|
-
this.currentStep++;
|
|
60
|
-
this.updateStepDisplay();
|
|
61
|
-
|
|
62
|
-
if (this.currentStep === 3) {
|
|
63
|
-
await this.generatePreview();
|
|
64
|
-
} else if (this.currentStep === 4) {
|
|
65
|
-
await this.prepareValidation();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
prevStep() {
|
|
71
|
-
if (this.currentStep > 1) {
|
|
72
|
-
this.currentStep--;
|
|
73
|
-
this.updateStepDisplay();
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
updateStepDisplay() {
|
|
78
|
-
// Hide all steps
|
|
79
|
-
document.querySelectorAll('.wizard-step').forEach(step => {
|
|
80
|
-
step.classList.remove('active');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
// Show current step
|
|
84
|
-
document.getElementById(`step${this.currentStep}`).classList.add('active');
|
|
85
|
-
|
|
86
|
-
// Update step indicator
|
|
87
|
-
this.updateStepIndicator();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
updateStepIndicator() {
|
|
91
|
-
document.querySelectorAll('.step-dot').forEach((dot, index) => {
|
|
92
|
-
dot.classList.remove('active', 'completed');
|
|
93
|
-
|
|
94
|
-
if (index + 1 < this.currentStep) {
|
|
95
|
-
dot.classList.add('completed');
|
|
96
|
-
} else if (index + 1 === this.currentStep) {
|
|
97
|
-
dot.classList.add('active');
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async generatePreview() {
|
|
103
|
-
this.showLoading('Generating template...');
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const config = this.getConfiguration();
|
|
107
|
-
this.template = await this.baseTemplate.createOptimalBase(config);
|
|
108
|
-
|
|
109
|
-
if (this.template.success) {
|
|
110
|
-
this.displayTemplatePreview();
|
|
111
|
-
|
|
112
|
-
if (this.setupMethod === 'template') {
|
|
113
|
-
this.showTemplateLink();
|
|
114
|
-
} else {
|
|
115
|
-
this.showManualInstructions();
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
throw new Error(this.template.error || 'Failed to generate template');
|
|
119
|
-
}
|
|
120
|
-
} catch (error) {
|
|
121
|
-
console.error('Template generation failed:', error);
|
|
122
|
-
this.showError('Failed to generate template: ' + error.message);
|
|
123
|
-
} finally {
|
|
124
|
-
this.hideLoading();
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
getConfiguration() {
|
|
129
|
-
return {
|
|
130
|
-
baseName: document.getElementById('baseName').value || 'Airtable Clipper Database',
|
|
131
|
-
includeContacts: document.getElementById('includeContacts').checked,
|
|
132
|
-
includeClips: document.getElementById('includeClips').checked,
|
|
133
|
-
includeCompanies: document.getElementById('includeCompanies').checked,
|
|
134
|
-
includeTasks: document.getElementById('includeTasks').checked
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
displayTemplatePreview() {
|
|
139
|
-
const preview = document.getElementById('templatePreview');
|
|
140
|
-
|
|
141
|
-
let html = `<h3>📊 ${this.template.template.baseName}</h3>`;
|
|
142
|
-
html += `<p style="margin-bottom: 16px; color: #6b7280;">${this.template.template.description}</p>`;
|
|
143
|
-
|
|
144
|
-
this.template.template.tables.forEach(table => {
|
|
145
|
-
html += `
|
|
146
|
-
<div class="table-preview">
|
|
147
|
-
<h4>${table.name}</h4>
|
|
148
|
-
<p>${table.description}</p>
|
|
149
|
-
<div class="field-list">
|
|
150
|
-
${table.fields.slice(0, 8).map(field =>
|
|
151
|
-
`<span class="field-tag">${field.name}</span>`
|
|
152
|
-
).join('')}
|
|
153
|
-
${table.fields.length > 8 ?
|
|
154
|
-
`<span class="field-tag">+${table.fields.length - 8} more</span>` :
|
|
155
|
-
''
|
|
156
|
-
}
|
|
157
|
-
</div>
|
|
158
|
-
</div>
|
|
159
|
-
`;
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Add automation recommendations
|
|
163
|
-
if (this.template.template.automations.length > 0) {
|
|
164
|
-
html += `
|
|
165
|
-
<div style="margin-top: 16px; padding: 12px; background-color: #f0f9ff; border-radius: 6px;">
|
|
166
|
-
<h4 style="margin: 0 0 8px 0; color: #0369a1;">🤖 Recommended Automations</h4>
|
|
167
|
-
<ul style="margin: 0; padding-left: 16px; font-size: 12px;">
|
|
168
|
-
${this.template.template.automations.map(auto =>
|
|
169
|
-
`<li>${auto.name}: ${auto.description}</li>`
|
|
170
|
-
).join('')}
|
|
171
|
-
</ul>
|
|
172
|
-
</div>
|
|
173
|
-
`;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
preview.innerHTML = html;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
showTemplateLink() {
|
|
180
|
-
const templateSection = document.getElementById('templateLinkSection');
|
|
181
|
-
const manualSection = document.getElementById('manualSetupSection');
|
|
182
|
-
|
|
183
|
-
templateSection.style.display = 'block';
|
|
184
|
-
manualSection.style.display = 'none';
|
|
185
|
-
|
|
186
|
-
// In a real implementation, this would be a working Airtable template URL
|
|
187
|
-
const templateLink = document.getElementById('templateLink');
|
|
188
|
-
templateLink.href = this.template.templateUrl || 'https://airtable.com/universe';
|
|
189
|
-
|
|
190
|
-
// For now, show manual instructions as fallback
|
|
191
|
-
setTimeout(() => {
|
|
192
|
-
templateSection.style.display = 'none';
|
|
193
|
-
manualSection.style.display = 'block';
|
|
194
|
-
this.showManualInstructions();
|
|
195
|
-
}, 100);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
showManualInstructions() {
|
|
199
|
-
const manualSection = document.getElementById('manualSetupSection');
|
|
200
|
-
const baseNameDisplay = document.getElementById('baseNameDisplay');
|
|
201
|
-
const creationScript = document.getElementById('creationScript');
|
|
202
|
-
|
|
203
|
-
manualSection.style.display = 'block';
|
|
204
|
-
baseNameDisplay.textContent = this.template.template.baseName;
|
|
205
|
-
|
|
206
|
-
// Generate creation script
|
|
207
|
-
const script = this.baseTemplate.generateCreationScript(this.template.template);
|
|
208
|
-
creationScript.value = script;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
async prepareValidation() {
|
|
212
|
-
// Pre-populate credentials if available
|
|
213
|
-
const existingSettings = await this.getExistingSettings();
|
|
214
|
-
|
|
215
|
-
if (existingSettings.airtableToken) {
|
|
216
|
-
document.getElementById('validationToken').value = existingSettings.airtableToken;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (existingSettings.baseId) {
|
|
220
|
-
document.getElementById('validationBaseId').value = existingSettings.baseId;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// If both are available, auto-validate
|
|
224
|
-
if (existingSettings.airtableToken && existingSettings.baseId) {
|
|
225
|
-
setTimeout(() => this.validateBase(), 500);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async getExistingSettings() {
|
|
230
|
-
try {
|
|
231
|
-
const response = await chrome.runtime.sendMessage({
|
|
232
|
-
action: 'getSettings'
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
return response.success ? response.settings : {};
|
|
236
|
-
} catch (error) {
|
|
237
|
-
console.error('Failed to get existing settings:', error);
|
|
238
|
-
return {};
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
async validateBase() {
|
|
243
|
-
const token = document.getElementById('validationToken').value.trim();
|
|
244
|
-
const baseId = document.getElementById('validationBaseId').value.trim();
|
|
245
|
-
|
|
246
|
-
if (!token || !baseId) {
|
|
247
|
-
this.showError('Please enter both Personal Access Token and Base ID');
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
this.showLoading('Validating base structure...');
|
|
252
|
-
|
|
253
|
-
try {
|
|
254
|
-
const client = new AirtableClient(token, baseId);
|
|
255
|
-
const baseTemplate = new BaseTemplate(client);
|
|
256
|
-
const validation = await baseTemplate.validateBaseStructure(baseId);
|
|
257
|
-
|
|
258
|
-
this.displayValidationResults(validation);
|
|
259
|
-
|
|
260
|
-
// Save settings if validation is successful
|
|
261
|
-
if (validation.score >= 40) {
|
|
262
|
-
await this.saveSettings(token, baseId);
|
|
263
|
-
document.getElementById('completeBtn').style.display = 'block';
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
} catch (error) {
|
|
267
|
-
console.error('Validation failed:', error);
|
|
268
|
-
this.showError('Validation failed: ' + error.message);
|
|
269
|
-
} finally {
|
|
270
|
-
this.hideLoading();
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
displayValidationResults(validation) {
|
|
275
|
-
const resultsDiv = document.getElementById('validationResults');
|
|
276
|
-
|
|
277
|
-
let html = `
|
|
278
|
-
<div class="validation-result ${validation.status}">
|
|
279
|
-
<h3>
|
|
280
|
-
${this.getStatusIcon(validation.status)}
|
|
281
|
-
Base Score: ${validation.score}/${validation.maxScore || 100}
|
|
282
|
-
</h3>
|
|
283
|
-
<p><strong>Status:</strong> ${this.getStatusText(validation.status)}</p>
|
|
284
|
-
`;
|
|
285
|
-
|
|
286
|
-
if (validation.issues && validation.issues.length > 0) {
|
|
287
|
-
html += `
|
|
288
|
-
<div style="margin-top: 12px;">
|
|
289
|
-
<strong>Issues Found:</strong>
|
|
290
|
-
<ul style="margin: 4px 0 0 20px; font-size: 13px;">
|
|
291
|
-
${validation.issues.map(issue => `<li>${issue}</li>`).join('')}
|
|
292
|
-
</ul>
|
|
293
|
-
</div>
|
|
294
|
-
`;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
if (validation.recommendations && validation.recommendations.length > 0) {
|
|
298
|
-
html += `
|
|
299
|
-
<div style="margin-top: 12px;">
|
|
300
|
-
<strong>Recommendations:</strong>
|
|
301
|
-
<ul style="margin: 4px 0 0 20px; font-size: 13px;">
|
|
302
|
-
${validation.recommendations.map(rec => `<li>${rec}</li>`).join('')}
|
|
303
|
-
</ul>
|
|
304
|
-
</div>
|
|
305
|
-
`;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
html += '</div>';
|
|
309
|
-
|
|
310
|
-
if (validation.status === 'excellent' || validation.status === 'good') {
|
|
311
|
-
html += `
|
|
312
|
-
<div style="margin-top: 16px; padding: 12px; background-color: #d1fae5; border-radius: 6px;">
|
|
313
|
-
<strong>🎉 Great news!</strong> Your base is ready for Airtable Clipper.
|
|
314
|
-
You can start saving LinkedIn profiles and web content right away.
|
|
315
|
-
</div>
|
|
316
|
-
`;
|
|
317
|
-
} else if (validation.status === 'fair') {
|
|
318
|
-
html += `
|
|
319
|
-
<div style="margin-top: 16px; padding: 12px; background-color: #fef3c7; border-radius: 6px;">
|
|
320
|
-
<strong>⚠️ Base needs some work.</strong> The extension will work, but you'll get
|
|
321
|
-
better results by adding the recommended fields and tables.
|
|
322
|
-
</div>
|
|
323
|
-
`;
|
|
324
|
-
} else {
|
|
325
|
-
html += `
|
|
326
|
-
<div style="margin-top: 16px; padding: 12px; background-color: #fee2e2; border-radius: 6px;">
|
|
327
|
-
<strong>❌ Base needs significant improvements.</strong> Please create the missing
|
|
328
|
-
tables and fields for the best experience.
|
|
329
|
-
</div>
|
|
330
|
-
`;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
resultsDiv.innerHTML = html;
|
|
334
|
-
resultsDiv.style.display = 'block';
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
getStatusIcon(status) {
|
|
338
|
-
const icons = {
|
|
339
|
-
'excellent': '🌟',
|
|
340
|
-
'good': '✅',
|
|
341
|
-
'fair': '⚠️',
|
|
342
|
-
'needs-work': '❌',
|
|
343
|
-
'error': '🚫'
|
|
344
|
-
};
|
|
345
|
-
return icons[status] || '❓';
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
getStatusText(status) {
|
|
349
|
-
const texts = {
|
|
350
|
-
'excellent': 'Perfect! Your base is optimally configured.',
|
|
351
|
-
'good': 'Great! Your base is well set up for clipping.',
|
|
352
|
-
'fair': 'Good start, but could use some improvements.',
|
|
353
|
-
'needs-work': 'Significant setup needed for best results.',
|
|
354
|
-
'error': 'Unable to validate. Check your credentials.'
|
|
355
|
-
};
|
|
356
|
-
return texts[status] || 'Unknown status';
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
async saveSettings(token, baseId) {
|
|
360
|
-
try {
|
|
361
|
-
await chrome.runtime.sendMessage({
|
|
362
|
-
action: 'saveSettings',
|
|
363
|
-
settings: {
|
|
364
|
-
airtableToken: token,
|
|
365
|
-
baseId: baseId
|
|
366
|
-
}
|
|
367
|
-
});
|
|
368
|
-
} catch (error) {
|
|
369
|
-
console.error('Failed to save settings:', error);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
async completeSetup() {
|
|
374
|
-
this.showLoading('Completing setup...');
|
|
375
|
-
|
|
376
|
-
try {
|
|
377
|
-
// Close setup wizard and return to main popup
|
|
378
|
-
window.close();
|
|
379
|
-
|
|
380
|
-
// Open main popup to show completed setup
|
|
381
|
-
chrome.action.openPopup();
|
|
382
|
-
|
|
383
|
-
} catch (error) {
|
|
384
|
-
console.error('Failed to complete setup:', error);
|
|
385
|
-
this.showError('Setup completion failed: ' + error.message);
|
|
386
|
-
} finally {
|
|
387
|
-
this.hideLoading();
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
showLoading(message = 'Loading...') {
|
|
392
|
-
const overlay = document.getElementById('loadingOverlay');
|
|
393
|
-
const text = document.getElementById('loadingText');
|
|
394
|
-
|
|
395
|
-
text.textContent = message;
|
|
396
|
-
overlay.style.display = 'flex';
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
hideLoading() {
|
|
400
|
-
const overlay = document.getElementById('loadingOverlay');
|
|
401
|
-
overlay.style.display = 'none';
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
showError(message) {
|
|
405
|
-
// Create a simple error display
|
|
406
|
-
const errorDiv = document.createElement('div');
|
|
407
|
-
errorDiv.style.cssText = `
|
|
408
|
-
position: fixed;
|
|
409
|
-
top: 20px;
|
|
410
|
-
left: 20px;
|
|
411
|
-
right: 20px;
|
|
412
|
-
background-color: #fee2e2;
|
|
413
|
-
color: #991b1b;
|
|
414
|
-
padding: 12px;
|
|
415
|
-
border-radius: 6px;
|
|
416
|
-
border: 1px solid #fca5a5;
|
|
417
|
-
z-index: 10000;
|
|
418
|
-
font-size: 14px;
|
|
419
|
-
`;
|
|
420
|
-
errorDiv.innerHTML = `❌ ${message}`;
|
|
421
|
-
|
|
422
|
-
document.body.appendChild(errorDiv);
|
|
423
|
-
|
|
424
|
-
// Auto-remove after 5 seconds
|
|
425
|
-
setTimeout(() => {
|
|
426
|
-
if (errorDiv.parentNode) {
|
|
427
|
-
errorDiv.parentNode.removeChild(errorDiv);
|
|
428
|
-
}
|
|
429
|
-
}, 5000);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// Global functions for HTML onclick handlers
|
|
434
|
-
window.nextStep = function() {
|
|
435
|
-
wizard.nextStep();
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
window.prevStep = function() {
|
|
439
|
-
wizard.prevStep();
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
window.validateBase = function() {
|
|
443
|
-
wizard.validateBase();
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
window.completeSetup = function() {
|
|
447
|
-
wizard.completeSetup();
|
|
448
|
-
};
|
|
449
|
-
|
|
450
|
-
window.copyScript = function() {
|
|
451
|
-
const script = document.getElementById('creationScript');
|
|
452
|
-
script.select();
|
|
453
|
-
document.execCommand('copy');
|
|
454
|
-
|
|
455
|
-
// Show feedback
|
|
456
|
-
const button = event.target;
|
|
457
|
-
const originalText = button.textContent;
|
|
458
|
-
button.textContent = 'Copied!';
|
|
459
|
-
button.style.backgroundColor = '#10b981';
|
|
460
|
-
|
|
461
|
-
setTimeout(() => {
|
|
462
|
-
button.textContent = originalText;
|
|
463
|
-
button.style.backgroundColor = '';
|
|
464
|
-
}, 2000);
|
|
465
|
-
};
|
|
466
|
-
|
|
467
|
-
// Initialize wizard when page loads
|
|
468
|
-
let wizard;
|
|
469
|
-
document.addEventListener('DOMContentLoaded', () => {
|
|
470
|
-
wizard = new BaseSetupWizard();
|
|
471
|
-
});
|