@crowdin/app-project-module 0.86.0 → 0.87.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.
@@ -114,5 +114,6 @@ export declare class PostgreStorage implements Storage {
114
114
  saveSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
115
115
  updateSyncedData(files: any, integrationId: string, crowdinId: string, type: string): Promise<void>;
116
116
  getSyncedData(integrationId: string, crowdinId: string, type: string): Promise<IntegrationSyncedData | undefined>;
117
+ resetSequences(): Promise<void>;
117
118
  }
118
119
  export {};
@@ -204,6 +204,9 @@ class PostgreStorage {
204
204
  this._res && this._res();
205
205
  // TODO: temporary code
206
206
  yield this.executeQuery((client) => this.alterTables(client));
207
+ // Reset sequences for tables with serial primary keys
208
+ // TODO: remove this after migration
209
+ yield this.resetSequences();
207
210
  }
208
211
  catch (e) {
209
212
  console.error(e);
@@ -798,6 +801,8 @@ class PostgreStorage {
798
801
  fs_1.default.renameSync(filePath, filePath.replace('dump_table_', 'error_dump_table_'));
799
802
  }
800
803
  }
804
+ // Reset sequences for tables with serial primary keys
805
+ yield this.resetSequences();
801
806
  });
802
807
  }
803
808
  saveUnsyncedFiles({ integrationId, crowdinId, files }) {
@@ -918,5 +923,38 @@ class PostgreStorage {
918
923
  }));
919
924
  });
920
925
  }
926
+ resetSequences() {
927
+ return __awaiter(this, void 0, void 0, function* () {
928
+ yield this.dbPromise;
929
+ yield this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
930
+ const tables = Object.keys(this.tables);
931
+ for (const table of tables) {
932
+ try {
933
+ const primaryKeyResult = yield client.query(`
934
+ SELECT a.attname
935
+ FROM pg_index i
936
+ JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
937
+ WHERE i.indrelid = '${table}'::regclass
938
+ AND i.indisprimary;
939
+ `);
940
+ if (primaryKeyResult.rows.length === 0) {
941
+ continue;
942
+ }
943
+ const primaryKey = primaryKeyResult.rows[0].attname;
944
+ const maxIdResult = yield client.query(`SELECT MAX(${primaryKey}) FROM ${table}`);
945
+ const maxId = maxIdResult.rows[0].max;
946
+ // Skip if maxId is not a valid integer
947
+ if (maxId === null || isNaN(Number(maxId))) {
948
+ continue;
949
+ }
950
+ yield client.query(`SELECT setval('${table}_${primaryKey}_seq', ${Number(maxId)}, true)`);
951
+ }
952
+ catch (error) {
953
+ console.error(`Error resetting sequence for table ${table}:`, error);
954
+ }
955
+ }
956
+ }));
957
+ });
958
+ }
921
959
  }
922
960
  exports.PostgreStorage = PostgreStorage;
package/out/types.d.ts CHANGED
@@ -72,6 +72,10 @@ export interface ClientConfig extends ImagePath {
72
72
  * app description
73
73
  */
74
74
  description: string;
75
+ /**
76
+ * link to the app's description/detail page
77
+ */
78
+ detailPage?: string;
75
79
  /**
76
80
  * Set default app permissions
77
81
  */
@@ -0,0 +1,102 @@
1
+ <html>
2
+ <head>
3
+ <title>{{name}}</title>
4
+ <meta charset="utf-8" />
5
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+
8
+ {{#if storeLink}}
9
+ <link rel="canonical" href="{{storeLink}}">
10
+ {{/if}}
11
+
12
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
13
+ <link href="/assets/css/about.css" media="screen" rel="stylesheet" type="text/css">
14
+ </head>
15
+ <body>
16
+ <header id="header" class="navbar navbar-expand-lg fixed-top crowdin-navbar">
17
+ <a itemprop="url" class="navbar-brand crowdin-navbar__logo" href="https://crowdin.com" title="Crowdin — Localization Management Platform">
18
+ <svg class="d-none d-md-block d-lg-block default-logo" width="180" height="54" aria-labelledby="crowdinLogoTitle">
19
+ <title id="crowdinLogoTitle">Crowdin</title>
20
+ <image class="d-none d-md-block d-lg-block" href="/assets/img/crowdin.svg" width="180" height="54" alt="Crowdin" />
21
+ </svg>
22
+ <svg class="d-block d-md-none d-lg-none default-logo" width="173" height="32">
23
+ <image class="d-block d-md-none d-lg-none" href="/assets/img/crowdin_small.svg" width="173" height="32" alt="Crowdin"/>
24
+ </svg>
25
+ </a>
26
+ <div class="flex-nowrap justify-content-lg-end ml-auto my-lg-0">
27
+ <div class="pr-0 ml-2 my-2">
28
+ <span class="crowdin-navbar__nav-link contact ">
29
+ <a title="Contact" href="https://crowdin.com/contacts">Contact</a>
30
+ </span>
31
+ </div>
32
+ </div>
33
+ </header>
34
+ <div class="main">
35
+ <div class="container">
36
+ <div class="row crwd__product-template__header align-items-center">
37
+
38
+ <div class="offset-lg-1 col-lg-2 product-single__photo-wrapper crwd__product-single__photo-wrapper">
39
+ <div class="product-single__photo text-center mb-3 mb-lg-0">
40
+ <div class="image-holder">
41
+ <img width="200" src="{{logo}}" alt="{{name}}" id="FeaturedImage-product-template" class="img-fluid lazyloaded ls-is-cached product-featured-img" style="position: unset;">
42
+ </div>
43
+ </div>
44
+ </div>
45
+ <div class=" col-lg-8 crwd__product-template__header__title-container">
46
+ <div class="product-single__meta">
47
+ <div class="section-header">
48
+ <h1 class="product-single__title text-center text-lg-left">
49
+ <span>{{name}}</span>
50
+ </h1>
51
+ <div class="description">
52
+ {{name}} extends the default functionality available in Crowdin and Crowdin Enterprise by providing additional capabilities to enhance your localization workflows.
53
+ </div>
54
+ </div>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ <div class="row">
59
+ <div class="offset-lg-1 col-lg-10">
60
+ <p>To install this app, you can use either of the following methods: </p>
61
+ <ol>
62
+ <li>Install it directly from the <a href="https://store.crowdin.com/" target="_blank">Crowdin Store</a>, if available.</li>
63
+ <li>Install it manually using the manifest URL below.</li>
64
+ </ol>
65
+ <p>For detailed steps, follow the <a href="https://support.crowdin.com/developer/crowdin-apps-installation/" target="_blank">App Installation</a></p>
66
+
67
+ <div class="mb-3">
68
+ <label for="manifest-url" class="form-label">Paste the following manifest URL when prompted during manual installation:</label>
69
+ <div class="input-group">
70
+ <input
71
+ type="text"
72
+ class="form-control"
73
+ id="manifest-url"
74
+ value="{{manifest}}"
75
+ readonly
76
+ >
77
+ <button class="btn btn-outline-secondary" type="button" id="copy-button">
78
+ Copy
79
+ </button>
80
+ </div>
81
+ </div>
82
+
83
+
84
+
85
+ {{#if storeLink}}
86
+ <div>Read more about <a href="{{storeLink}}" target="_blank" title="{{name}} on Crowdin Store">{{name}}</a>.</div>
87
+ {{/if}}
88
+ </div>
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </body>
93
+ <script>
94
+ document.getElementById('copy-button').addEventListener('click', async () => {
95
+ const text = document.getElementById('manifest-url').value;
96
+ await navigator.clipboard.writeText(text);
97
+ const btn = document.getElementById('copy-button');
98
+ btn.textContent = 'Copied!';
99
+ setTimeout(() => btn.textContent = 'Copy', 1500);
100
+ });
101
+ </script>
102
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",