PageSourceSearch

https://squidex.io/scripts/components.js?v=MlchShh6jZmxoEJ1FAnw-cgCKur4toLk3UcHik5RM1U

js squidex.io collected 2026-10-03 20:18:37 UTC 14,377 bytes, 318 lines download raw bytes

1import { html, LitElement } from 'https://cdn.jsdelivr.net/npm/[email protected]/+esm';
2
3const formattedUS = new Intl.NumberFormat('en-US', {
4    minimumFractionDigits: 3,
5    maximumFractionDigits: 3,
6});
7
8const HOURS_PER_MONTH = 24 * 30;
9
10class ServerCalculator extends LitElement {
11    static properties = {
12        serverSize: { type: String },
13        serverBackups: { type: Boolean },
14        traffic: { type: Number },
15    };
16
17    constructor() {
18        super();
19        this.serverSize = 'cores_4';
20        this.serverBackups = false;
21        this.traffic = 1000;
22        this.pricePerTrafficGBMonth = 0.02;
23    }
24
25    createRenderRoot() {
26        return this;
27    }
28
29    serverSizeOptions = [
30        { value: 'cores_4', label: '4 Cores, 8 GB RAM, 160 GB SSD' },
31        { value: 'cores_6', label: '6 Cores, 16 GB RAM, 320 GB SSD' },
32        { value: 'cores_8', label: '8 Cores, 32 GB RAM, 640 GB SSD' },
33        { value: 'cores_16', label: '16 Cores, 64 GB RAM, 1280 GB SSD' },
34    ];
35
36    getPricing() {
37        let hourlyMachine = 0;
38        let hourlyBackup = 0;
39        let includedTraffic = 0;
40
41        switch (this.serverSize) {
42            case 'cores_4':
43                hourlyMachine = 0.12;
44                includedTraffic = 4000;
45                break;
46            case 'cores_6':
47                hourlyMachine = 0.24;
48                includedTraffic = 5000;
49                break;
50            case 'cores_8':
51                hourlyMachine = 0.48;
52                includedTraffic = 6000;
53                break;
54            case 'cores_16':
55                hourlyMachine = 0.96;
56                includedTraffic = 10000;
57                break;
58        }
59
60        if (this.serverBackups) {
61            hourlyBackup = hourlyMachine * 0.5;
62        }
63
64        const trafficMonthly = Math.max(0, this.traffic - includedTraffic) * this.pricePerTrafficGBMonth;
65        const trafficHourly = trafficMonthly / HOURS_PER_MONTH;
66
67        const hourlyTotal = hourlyMachine + hourlyBackup + trafficHourly;
68        const monthlyMachine = hourlyMachine * HOURS_PER_MONTH;
69        const monthlyBackup = hourlyBackup * HOURS_PER_MONTH;
70        const monthlyTotal = monthlyMachine + monthlyBackup + trafficMonthly;
71
72        return {
73            hourlyBackup,
74            hourlyMachine,
75            hourlyTotal,
76            hourlyTraffic: trafficHourly,
77            includedTraffic,
78            monthlyMachine,
79            monthlyTotal,
80            monthlyTraffic: trafficMonthly,
81        };
82    }
83
84    render() {
85        const pricing = this.getPricing();
86
87        return html`
88<div class="pricing-options pricing-section row">
89    <div class="pricing-option col-6">
90        <h5>Choose your Server Size</h5>
91        <form class="mt-8">
92            <div class="mb-3">
93                <label class="form-label" for="serverSize">Server Size</label>
94                <select class="form-select" id="serverSize" .value=${this.serverSize} @input=${e => this.serverSize = e.target.value}>
95                    ${this.serverSizeOptions.map(option => html`
96                        <option value=${option.value} ?selected=${this.serverSize === option.value}>${option.label}</option>
97                    `)}
98                </select>
99            </div>
100            <div class="mb-3">
101                <input type="checkbox" class="form-check-input" id="serverBackups" .checked=${this.serverBackups} @input=${e => this.serverBackups = e.target.checked}>
102                <label class="form-check-label" for="serverBackups">Automatic Backups</label>
103            </div>
104
105            <hr class="mt-4 mb-4">
106
107            <div class="mb-3">
108                <label for="traffic" class="form-label w-100">Traffic (${pricing.includedTraffic} GB included) <strong class="float-end"> ${this.traffic} GB</strong ></label>
109                <input type="range" class="form-range" id="storage" min="100" max="50000" step="10" .value=${this.traffic} @input=${e => this.traffic = parseInt(e.target.value)}>
110            </div>
111        </form>
112    </div>
113    <div class="pricing-option pricing-option-button col-6">
114        <table class="table">
115            <tr>
116                <td>Server</td>
117                <td class="text-end"><span>${formattedUS.format(pricing.hourlyMachine)}</span> &euro; <small>/ hour</small></td>
118                <td class="text-end"><span>${formattedUS.format(pricing.monthlyMachine)}</span> &euro; <small>/ month</small></td>
119            </tr>
120            <tr>
121                <td>Backup</td>
122                <td class="text-end"><span>${formattedUS.format(pricing.hourlyBackup)}</span> &euro; <small>/ hour</small></td>
123                <td class="text-end"><span>${formattedUS.format(pricing.monthlyTraffic)}</span> &euro; <small>/ month</small></td>
124            </tr>
125            <tr>
126                <td>Traffic</td>
127                <td class="text-end"><span>${formattedUS.format(pricing.hourlyTraffic)}</span> &euro; <small>/ hour</small></td>
128                <td class="text-end"><span>${formattedUS.format(pricing.monthlyTraffic)}</span> &euro; <small>/ month</small></td>
129            </tr>
130            <tr>
131                <th>Total</th>
132                <th class="text-end"><span>${formattedUS.format(pricing.hourlyTotal)}</span> &euro; <small>/ hour</small></th>
133                <th class="text-end"><span>${formattedUS.format(pricing.monthlyTotal)}</span> &euro; <small>/ month</small></th>
134            </tr>
135        </table>
136        
137        <small>Prices are estimated and bases on an average of 30 days per month</small>
138
139        <div>
140            <a class="lead-button xl text-center pricing-toggle mt-8" href="https://hosting.squidex.io" target="_blank" rel="noopener">Create Server</a>
141        </div>
142    </div>
143</div>`;
144    }
145}
146
147customElements.define('server-calculator', ServerCalculator);
148
149class ClusterCalculator extends LitElement {
150    static properties = {
151        databaseCoreMemory: { type: Number },
152        databaseCores: { type: Number },
153        databaseCount: { type: Number },
154        databaseDisk: { type: Number },
155        storage: { type: Number },
156        traffic: { type: Number },
157        webCoreMemory: { type: Number },
158        webCores: { type: Number },
159        webCount: { type: Number },
160    };
161
162    constructor() {
163        super();
164        this.databaseCoreMemory = 2;
165        this.databaseCores = 2;
166        this.databaseCount = 3;
167        this.databaseDisk = 100;
168        this.storage = 100;
169        this.webCoreMemory = 2;
170        this.webCores = 2;
171        this.webCount = 3;
172        this.traffic = 1000;
173
174        this.pricePerCore = 0.02;
175        this.pricePerDiskGBHour = 0.0005;
176        this.pricePerGBMemory = 0.01;
177        this.pricePerStorageGBMonth = 0.025;
178        this.pricePerTrafficGBMonth = 0.02;
179    }
180
181    createRenderRoot() {
182        return this;
183    }
184
185    getPricing() {
186        const webTotalCores = this.webCount * this.webCores;
187        const webTotalMemory = this.webCoreMemory * webTotalCores;
188
189        const databaseTotalCores = this.databaseCount * this.databaseCores;
190        const databaseTotalMemory = this.databaseCoreMemory * databaseTotalCores;
191
192        const storageMonthly = this.storage * this.pricePerStorageGBMonth;
193        const storageHourly = storageMonthly / HOURS_PER_MONTH;
194
195        const trafficMonthly = this.traffic * this.pricePerTrafficGBMonth;
196        const trafficHourly = trafficMonthly / HOURS_PER_MONTH;
197
198        const hourlyWeb = webTotalCores * this.pricePerCore + webTotalMemory * this.pricePerGBMemory;
199        const hourlyDatabase = databaseTotalMemory * this.pricePerCore + this.databaseCoreMemory * this.pricePerGBMemory + this.databaseDisk * this.pricePerDiskGBHour;
200        const hourlyTotal = hourlyWeb + hourlyDatabase + storageHourly + trafficHourly;
201
202        const monthlyWeb = hourlyWeb * HOURS_PER_MONTH;
203        const monthlyDatabase = hourlyDatabase * HOURS_PER_MONTH;
204        const monthlyTotal = monthlyWeb + monthlyDatabase + storageMonthly + trafficMonthly;
205
206        return {
207            hourlyDatabase,
208            hourlyTotal,
209            hourlyWeb,
210            monthlyDatabase,
211            monthlyTotal,
212            monthlyWeb,
213            storageHourly,
214            storageMonthly,
215            trafficHourly,
216            trafficMonthly,
217        };
218    }
219
220    render() {
221        const pricing = this.getPricing();
222        return html`
223<div class="pricing-options pricing-section row">
224    <div class="pricing-option col-6">
225        <h5>Cluster Configuration</h5>
226        <form class="mt-8">
227            <div class="mb-4">
228                <label for="webCount" class="form-label w-100">Number of Squidex Servers<strong class="float-end">${this.webCount}</strong></label>
229                <input type="range" class="form-range" id="webCount" min="2" max="20" step="1" .value=${this.webCount} @input=${e => this.webCount = parseInt(e.target.value)}>
230            
231                <small>Requires two instances: one for background jobs.</small>
232            </div>
233
234            <div class="mb-3">
235                <label for="webCores" class="form-label w-100">Cores per Squidex Server<strong class="float-end">${this.webCores}</strong></label>
236                <input type="range" class="form-range" id="webCores" min="1" max="6" step="1" .value=${this.webCores} @input=${e => this.webCores = parseInt(e.target.value)}>
237            </div>
238            <div class="mb-3">
239                <label for="webCoreMemory" class="form-label w-100">Memory per Core<strong class="float-end">${this.webCoreMemory} GB</strong></label>
240                <input type="range" class="form-range" id="webCoreMemory" min="2" max="4" step="1" .value=${this.webCoreMemory} @input=${e => this.webCoreMemory = parseInt(e.target.value)}>
241            </div>
242
243            <hr class="mt-4 mb-4">
244
245            <div class="mb-4">
246                <label for="databaseCount" class="form-label w-100">Number of Database Servers (min 3)<strong class="float-end">${this.databaseCount}</strong></label>
247                <input type="range" class="form-range" id="databaseCount" min="3" max="20" step="1" .value=${this.databaseCount} @input=${e => this.databaseCount = parseInt(e.target.value)}>
248            
249                <small>Requires three instances for replica set.</small>
250            </div>
251            <div class="mb-3">
252                <label for="databaseCores" class="form-label w-100">Cores per Database Server<strong class="float-end">${this.databaseCores}</strong></label>
253                <input type="range" class="form-range" id="databaseCores" min="1" max="6" step="1" .value=${this.databaseCores} @input=${e => this.databaseCores = parseInt(e.target.value)}>
254            </div>
255            <div class="mb-3">
256                <label for="databaseCoreMemory" class="form-label w-100">Memory per Core<strong class="float-end">${this.databaseCoreMemory} GB</strong></label>
257                <input type="range" class="form-range" id="databaseCoreMemory" min="2" max="4" step="1" .value=${this.databaseCoreMemory} @input=${e => this.databaseCoreMemory = parseInt(e.target.value)}>
258            </div>
259            <div class="mb-3">
260                <label for="databaseDisk" class="form-label w-100">Disk Size per Database Server<strong class="float-end">${this.databaseDisk} GB</strong></label>
261                <input type="range" class="form-range" id="databaseDisk" min="50" max="1000" step="10" .value=${this.databaseDisk} @input=${e => this.databaseDisk = parseInt(e.target.value)}>
262            </div>
263
264            <hr class="mt-4 mb-4">
265
266            <div class="mb-3">
267                <label for="storage" class="form-label w-100">Shared Storage<strong class="float-end">${this.storage} GB</strong></label>
268                <input type="range" class="form-range" id="storage" min="0" max="2000" step="10" .value=${this.storage} @input=${e => this.storage = parseInt(e.target.value)}>
269            </div>
270
271            <hr class="mt-4 mb-4">
272
273            <div class="mb-3">
274                <label for="traffic" class="form-label w-100">Traffic<strong class="float-end">${this.traffic} GB</strong></label>
275                <input type="range" class="form-range" id="storage" min="100" max="50000" step="10" .value=${this.traffic} @input=${e => this.traffic = parseInt(e.target.value)}>
276            </div>
277        </form>
278    </div>
279    <div class="pricing-option col-6">
280        <table class="table mt-6">
281            <tr>
282                <td>Squidex</td>
283                <td class="text-end"><span>${formattedUS.format(pricing.hourlyWeb)}</span> &euro; <small>/ hour</small></td>
284                <td class="text-end"><span>${formattedUS.format(pricing.monthlyWeb)}</span> &euro; <small>/ month</small></td>
285            </tr>
286            <tr>
287                <td>
287Database</td>
288                <td class="text-end"><span>${formattedUS.format(pricing.hourlyDatabase)}</span> &euro; <small>/ hour</small></td>
289                <td class="text-end"><span>${formattedUS.format(pricing.monthlyDatabase)}</span> &euro; <small>/ month</small></td>
290            </tr>
291            <tr>
292                <td>Storage</td>
293                <td class="text-end"><span>${formattedUS.format(pricing.storageHourly)}</span> &euro; <small>/ hour</small></td>
294                <td class="text-end"><span>${formattedUS.format(pricing.storageMonthly)}</span> &euro; <small>/ month</small></td>
295            </tr>
296            <tr>
297                <td>Traffic</td>
298                <td class="text-end"><span>${formattedUS.format(pricing.trafficHourly)}</span> &euro; <small>/ hour</small></td>
299                <td class="text-end"><span>${formattedUS.format(pricing.trafficMonthly)}</span> &euro; <small>/ month</small></td>
300            </tr>
301            <tr>
302                <th>Total</th>
303                <th class="text-end"><span>${formattedUS.format(pricing.hourlyTotal)}</span> &euro; <small>/ hour</small></th>
304                <th class="text-end"><span>${formattedUS.format(pricing.monthlyTotal)}</span> &euro; <small>/ month</small></th>
305            </tr>
306        </table>
307        
308        <small>Prices are estimated and bases on an average of 30 days per month</small>
309
310        <div class="mt-8">
311            <a class="lead-button xl text-center pricing-toggle" disabled="true">Create Cluster (SOON)</a>
312        </div>
313    </div>
314</div>`;
315    }
316}
317
318customElements.define('cluster-calculator', ClusterCalculator);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.