@datagrok/sequence-translator 1.9.10 → 1.9.11

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.
@@ -4,13 +4,13 @@
4
4
  "linkRules": [
5
5
  {
6
6
  "firstMonomers": [
7
- "NH2"
7
+ "D"
8
8
  ],
9
9
  "secondMonomers": [
10
- "D"
10
+ "NH2"
11
11
  ],
12
- "firstLinkingGroup": "2",
13
- "secondLinkingGroup": "3",
12
+ "firstLinkingGroup": "3",
13
+ "secondLinkingGroup": "2",
14
14
  "code": "2"
15
15
  },
16
16
  {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.9.10",
4
+ "version": "1.9.11",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
@@ -22,7 +22,7 @@
22
22
  }
23
23
  ],
24
24
  "dependencies": {
25
- "@datagrok-libraries/bio": "^5.54.7",
25
+ "@datagrok-libraries/bio": "^5.54.8",
26
26
  "@datagrok-libraries/chem-meta": "^1.2.8",
27
27
  "@datagrok-libraries/tutorials": "^1.6.1",
28
28
  "@datagrok-libraries/utils": "^4.6.3",
@@ -54,7 +54,7 @@
54
54
  "@typescript-eslint/eslint-plugin": "^7.2.0",
55
55
  "@typescript-eslint/parser": "^7.2.0",
56
56
  "css-loader": "^6.7.3",
57
- "datagrok-tools": "^4.14.47",
57
+ "datagrok-tools": "^4.14.48",
58
58
  "eslint": "^8.57.0",
59
59
  "eslint-config-google": "^0.14.0",
60
60
  "style-loader": "^3.3.1",
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-len */
1
2
  import * as grok from 'datagrok-api/grok';
2
3
  import * as ui from 'datagrok-api/ui';
3
4
  import * as DG from 'datagrok-api/dg';
@@ -13,6 +14,7 @@ import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-he
13
14
  import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
14
15
  import {getOverriddenLibrary} from './pt-synthetic';
15
16
  import {helmToMol} from './pt-atomic';
17
+ import {execMonomerHoverLinks} from '@datagrok-libraries/bio/src/monomer-works/monomer-hover';
16
18
 
17
19
  class MonomerCard {
18
20
  root: HTMLElement = ui.divV([], {classes: 'monomer-card-rule-root'});
@@ -24,11 +26,12 @@ class MonomerCard {
24
26
  this.root.style.border = value ? '2px solid var(--green-2)' : '2px solid var(--grey-2)';
25
27
  }
26
28
 
27
- constructor(public monomer: Monomer | null) {}
29
+ constructor(public monomer: Monomer | null, public monomerSymbol: string) {}
28
30
 
29
31
  render() {
32
+ ui.empty(this.root);
33
+ this.root.appendChild(ui.h2(this.monomerSymbol, {style: {textAlign: 'center'}}));
30
34
  if (this.monomer) {
31
- ui.empty(this.root);
32
35
  const monomerMolSvg = this.monomer.smiles && grok.chem.checkSmiles(this.monomer.smiles) ?
33
36
  grok.chem.drawMolecule(this.monomer.smiles, 150, 120) :
34
37
  grok.chem.drawMolecule(this.monomer.molfile ?? '', 150, 120);
@@ -52,6 +55,9 @@ class MonomerCard {
52
55
  ui.tooltip.bind(monomerType, this.monomer.polymerType);
53
56
 
54
57
  ui.tooltip.bind(this.root, 'Select Monomer');
58
+ } else {
59
+ this.root.appendChild(ui.divV([`Monomer ${this.monomerSymbol} not found in libraries`],
60
+ {style: {textAlign: 'center', height: '100%'}}));
55
61
  }
56
62
  }
57
63
  }
@@ -59,7 +65,6 @@ class MonomerCard {
59
65
  export class RuleCards {
60
66
  root: HTMLElement = ui.divH([],
61
67
  {style: {
62
- alignItems: 'center',
63
68
  width: '100%',
64
69
  overflow: 'hidden',
65
70
  visibility: 'visible',
@@ -74,47 +79,53 @@ export class RuleCards {
74
79
 
75
80
  constructor(public firstMonomers: string[], public secondMonomers: string[],
76
81
  lib: IMonomerLib, public code: number, public rules: Rules) {
77
- if (firstMonomers.length > 0) {
78
- this.actionable = true;
79
- const monomerGalleryFirst = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
80
- const monomerGallerySecond = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
81
- this.resulting = ui.divH([], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}});
82
- const galleries = ui.divV([monomerGalleryFirst, monomerGallerySecond, this.resulting]);
83
- this.cardsFirst = firstMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol)));
84
- this.cardsSecond = secondMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol)));
85
-
86
- this.cardsFirst.forEach((card) => {
87
- card.root.onclick = () => {
88
- this.cardsFirst.forEach((c) => c.selected = false);
89
- card.selected = true;
90
- this.firstCard = card;
91
- this.reset();
92
- //onMonomerSelected(card.monomer);
93
- };
94
- monomerGalleryFirst.appendChild(card.root);
95
- });
96
-
97
- this.cardsSecond.forEach((card) => {
98
- card.root.onclick = () => {
99
- this.cardsSecond.forEach((c) => c.selected = false);
100
- card.selected = true;
101
- this.secondCard = card;
102
- this.reset();
103
- //onMonomerSelected(card.monomer);
104
- };
105
- monomerGallerySecond.appendChild(card.root);
106
- });
107
-
108
- this.cardsFirst[0].selected = true;
109
- this.cardsSecond[0].selected = true;
110
- this.firstCard = this.cardsFirst[0];
111
- this.secondCard = this.cardsSecond[0];
112
- this.root.appendChild(galleries);
113
- } else {
114
- const es = ui.divV(['Rule is active for all monomers, no examples to show']);
115
- this.root.appendChild(es);
116
- this.actionable = false;
117
- }
82
+ const emptyFirst = !firstMonomers?.length;
83
+ const emptySecond = !secondMonomers?.length;
84
+ // if one of the lists is empty, it means that the rule is active for all monomers
85
+ if (emptyFirst)
86
+ this.firstMonomers = firstMonomers = ['C', 'D', 'E', 'F', 'G'];
87
+ if (emptySecond)
88
+ this.secondMonomers = secondMonomers = ['D', 'C', 'E', 'F', 'G'];
89
+ this.actionable = true;
90
+ const monomerGalleryFirst = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
91
+ const monomerGallerySecond = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
92
+
93
+ this.resulting = ui.divH([], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}});
94
+ const headerFirst = ui.h2('First Monomer' + (!emptyFirst ? '' : ' (Applied to all monomers, example list shown)'),
95
+ {style: {width: '100%'}});
96
+ const headerSecond = ui.h2('Second Monomer' + (!emptySecond ? '' : ' (Applied to all monomers, example list shown)'),
97
+ {style: {width: '100%'}});
98
+ const galleries = ui.divV([headerFirst, monomerGalleryFirst, headerSecond, monomerGallerySecond, this.resulting]);
99
+ this.cardsFirst = firstMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol), symbol));
100
+ this.cardsSecond = secondMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol), symbol));
101
+
102
+ this.cardsFirst.forEach((card) => {
103
+ card.root.onclick = () => {
104
+ this.cardsFirst.forEach((c) => c.selected = false);
105
+ card.selected = true;
106
+ this.firstCard = card;
107
+ this.reset();
108
+ //onMonomerSelected(card.monomer);
109
+ };
110
+ monomerGalleryFirst.appendChild(card.root);
111
+ });
112
+
113
+ this.cardsSecond.forEach((card) => {
114
+ card.root.onclick = () => {
115
+ this.cardsSecond.forEach((c) => c.selected = false);
116
+ card.selected = true;
117
+ this.secondCard = card;
118
+ this.reset();
119
+ //onMonomerSelected(card.monomer);
120
+ };
121
+ monomerGallerySecond.appendChild(card.root);
122
+ });
123
+
124
+ this.cardsFirst[0].selected = true;
125
+ this.cardsSecond[0].selected = true;
126
+ this.firstCard = this.cardsFirst[0];
127
+ this.secondCard = this.cardsSecond[0];
128
+ this.root.appendChild(galleries);
118
129
  }
119
130
 
120
131
  async reset() {
@@ -122,6 +133,7 @@ export class RuleCards {
122
133
  const seqs: string[] = [
123
134
  `${this.firstCard.monomer?.symbol}(${this.code})-A-A-A-A-${this.secondCard.monomer?.symbol}(${this.code})`
124
135
  ];
136
+ 'PEPTIDE1{[NH2].A.A.A.A.D}$PEPTIDE1,PEPTIDE1,1:R2-6:R3$$$V2.0';
125
137
 
126
138
  const helmHelper = await getHelmHelper();
127
139
  const [helms, isLinear, positionMaps] = doPolyToolConvert(seqs, this.rules, helmHelper);
@@ -143,11 +155,28 @@ export class RuleCards {
143
155
 
144
156
  const mol = resMolCol.get(0);
145
157
  const monomerMolSvg = mol && grok.chem.checkSmiles(mol) ?
146
- grok.chem.drawMolecule(mol, 150, 120) :
147
- grok.chem.drawMolecule(mol ?? '', 150, 120);
158
+ grok.chem.drawMolecule(mol, 200, 200) :
159
+ grok.chem.drawMolecule(mol ?? '', 200, 200);
160
+
161
+ if (mol) {
162
+ monomerMolSvg.style.cursor = 'pointer';
163
+ monomerMolSvg.onclick = () => {
164
+ const width = window.innerWidth - 200;
165
+ const height = window.innerHeight - 200;
166
+ const bigMol = grok.chem.checkSmiles(mol) ?
167
+ grok.chem.drawMolecule(mol, width, height) :
168
+ grok.chem.drawMolecule(mol ?? '', width, height);
169
+ ui.dialog({title: 'Molecule'}).add(bigMol).showModal(true);
170
+ };
171
+ ui.tooltip.bind(monomerMolSvg, 'Click to expand');
172
+ }
173
+
174
+ const exampleDiv = ui.divV([
175
+ ui.h2('Example Result:'), ui.h2(seqs[0])
176
+ ], {style: {width: '200px'}});
148
177
 
149
178
  ui.empty(this.resulting);
150
- this.resulting.append(ui.divH([monomerMolSvg], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}}));
179
+ this.resulting.append(ui.divH([exampleDiv, monomerMolSvg], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}}));
151
180
  }
152
181
  }
153
182
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-len */
1
2
  import * as DG from 'datagrok-api/dg';
2
3
  import * as grok from 'datagrok-api/grok';
3
4
  import * as ui from 'datagrok-api/ui';
@@ -6,7 +7,8 @@ import {RulesManager} from './rule-manager';
6
7
  import {RuleCards} from './pt-rule-cards';
7
8
  import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
8
9
  import {
9
- PackageFunctions} from '../../package';
10
+ PackageFunctions} from '../../package';
11
+ import {MmcrTemps} from '@datagrok-libraries/bio/src/utils/cell-renderer-consts';
10
12
 
11
13
  export const RULES_PATH = 'System:AppData/SequenceTranslator/polytool-rules/';
12
14
  export const RULES_STORAGE_NAME = 'Polytool';
@@ -63,6 +65,15 @@ export type RuleReaction = {
63
65
  name: string
64
66
  }
65
67
 
68
+ export type LinkRuleRowArgs = {
69
+ row?: number,
70
+ code: number,
71
+ firstMonomers: string,
72
+ secondMonomers: string,
73
+ firstLinkingGroup: number,
74
+ secondLinkingGroup: number
75
+ }
76
+
66
77
  export class Rules {
67
78
  homodimerCode: string | null;
68
79
  heterodimerCode: string | null;
@@ -95,39 +106,54 @@ export class Rules {
95
106
  this.reactionRules.push(rules[j]);
96
107
  }
97
108
 
98
- getLinkRulesDf(): DG.DataFrame {
109
+ getLinkRulesDf() {
99
110
  const length = this.linkRules.length;
100
111
  const codeCol = DG.Column.int(NAME_CODE, length);
101
112
  codeCol.setTag('friendlyName', 'Code');
102
113
  //ui.tooltip.bind(codeCol.root, 'Click to zoom');
103
114
  const firstMonomerCol = DG.Column.string(NAME_FIRST_MONOMERS, length);
115
+ firstMonomerCol.temp[MmcrTemps.fontSize] = 16;
104
116
  firstMonomerCol.setTag('friendlyName', 'First monomers');
105
117
  firstMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
106
118
  PackageFunctions.applyNotationProviderForCyclized(firstMonomerCol, ',');
107
119
 
108
120
  const secondMonomerCol = DG.Column.string(NAME_SECOND_MONOMERS, length);
109
121
  secondMonomerCol.setTag('friendlyName', 'Second monomers');
122
+ secondMonomerCol.temp[MmcrTemps.fontSize] = 16;
110
123
  secondMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
111
124
  PackageFunctions.applyNotationProviderForCyclized(secondMonomerCol, ',');
112
125
 
113
- const firstLinkingGroup = DG.Column.int(NAME_FIRST_LINK, length);
114
- firstLinkingGroup.setTag('friendlyName', 'First group');
115
- const secondLinkingGroup = DG.Column.int(NAME_SECOND_LINK, length);
116
- secondLinkingGroup.setTag('friendlyName', 'Second group');
126
+ const firstLinkingGroupCol = DG.Column.int(NAME_FIRST_LINK, length);
127
+ firstLinkingGroupCol.setTag('friendlyName', 'First group');
128
+ const secondLinkingGroupCol = DG.Column.int(NAME_SECOND_LINK, length);
129
+ secondLinkingGroupCol.setTag('friendlyName', 'Second group');
117
130
 
118
131
  for (let i = 0; i < length; i++) {
119
132
  codeCol.set(i, this.linkRules[i].code);
120
133
  firstMonomerCol.set(i, this.linkRules[i].firstMonomers.toString());
121
134
  secondMonomerCol.set(i, this.linkRules[i].secondMonomers.toString());
122
- firstLinkingGroup.set(i, this.linkRules[i].firstLinkingGroup);
123
- secondLinkingGroup.set(i, this.linkRules[i].secondLinkingGroup);
135
+ firstLinkingGroupCol.set(i, this.linkRules[i].firstLinkingGroup);
136
+ secondLinkingGroupCol.set(i, this.linkRules[i].secondLinkingGroup);
124
137
  }
125
138
 
126
139
  const res = DG.DataFrame.fromColumns([
127
- codeCol, firstMonomerCol, secondMonomerCol, firstLinkingGroup, secondLinkingGroup
140
+ codeCol, firstMonomerCol, secondMonomerCol, firstLinkingGroupCol, secondLinkingGroupCol
128
141
  ]);
129
142
 
130
- return res;
143
+ const addNewRow = (rowObj: LinkRuleRowArgs) => {
144
+ if (rowObj.row != undefined && rowObj.row < res.rowCount && rowObj.row >= 0) {
145
+ codeCol.set(rowObj.row, rowObj.code);
146
+ firstMonomerCol.set(rowObj.row, rowObj.firstMonomers);
147
+ secondMonomerCol.set(rowObj.row, rowObj.secondMonomers);
148
+ firstLinkingGroupCol.set(rowObj.row, rowObj.firstLinkingGroup);
149
+ secondLinkingGroupCol.set(rowObj.row, rowObj.secondLinkingGroup);
150
+ } else {
151
+ const {code, firstMonomers, secondMonomers, firstLinkingGroup, secondLinkingGroup} = rowObj;
152
+ res.rows.addNew([code, firstMonomers ?? '', secondMonomers ?? '', firstLinkingGroup ?? 1, secondLinkingGroup ?? 2]);
153
+ }
154
+ };
155
+
156
+ return {res, addNewRow};
131
157
  }
132
158
 
133
159
  async getLinkCards(): Promise<RuleCards[]> {
@@ -1,7 +1,8 @@
1
+ /* eslint-disable max-len */
1
2
  import * as DG from 'datagrok-api/dg';
2
3
  import * as grok from 'datagrok-api/grok';
3
4
  import * as ui from 'datagrok-api/ui';
4
- import {getMonomerPairs, getRules, Rules} from './pt-rules';
5
+ import {getMonomerPairs, getRules, LinkRuleRowArgs, Rules} from './pt-rules';
5
6
  import {_package, PackageFunctions} from '../../package';
6
7
  import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
7
8
  import {doPolyToolConvert} from './pt-conversion';
@@ -24,13 +25,16 @@ export class RulesManager {
24
25
  heteroDimerInput: DG.InputBase;
25
26
 
26
27
  linkCards: RuleCards[];
28
+ addLinkRulesFunc: (rowObj: LinkRuleRowArgs) => void;
27
29
 
28
30
  // every rule set will have its editor instance
29
31
  private static instances: Record<string, RulesManager> = {};
30
32
 
31
33
  protected constructor(rules: Rules, fileName: string) {
32
34
  this.rules = rules;
33
- this.linkRuleDataFrame = this.rules.getLinkRulesDf();
35
+ const linksRes = this.rules.getLinkRulesDf();
36
+ this.linkRuleDataFrame = linksRes.res;
37
+ this.addLinkRulesFunc = linksRes.addNewRow;
34
38
 
35
39
  this.synthRuleDataFrame = this.rules.getSynthesisRulesDf();
36
40
  this.fileName = fileName;
@@ -179,10 +183,26 @@ export class RulesManager {
179
183
  }
180
184
 
181
185
  async getForm() {
182
- inputsTabControl: DG.TabControl;
186
+ const gridOptions: Partial<DG.IGridSettings> = {showAddNewRowIcon: false, allowEdit: false, rowHeight: 60};
187
+
188
+ const linksGrid = this.linkRuleDataFrame.plot.grid(gridOptions);
189
+ linksGrid.onCellDoubleClick.subscribe(() => {
190
+ if (!linksGrid.dataFrame || linksGrid.dataFrame.currentRowIdx == -1 || linksGrid.dataFrame.currentRowIdx == undefined)
191
+ return;
192
+ const idx = linksGrid.dataFrame.currentRowIdx;
193
+ const editArgs: LinkRuleRowArgs = {
194
+ row: idx,
195
+ code: this.linkRuleDataFrame.get('code', idx),
196
+ firstMonomers: this.linkRuleDataFrame.get('firstMonomers', idx),
197
+ secondMonomers: this.linkRuleDataFrame.get('secondMonomers', idx),
198
+ firstLinkingGroup: this.linkRuleDataFrame.get('firstLinkingGroup', idx),
199
+ secondLinkingGroup: this.linkRuleDataFrame.get('secondLinkingGroup', idx),
200
+ };
201
+ this.getAddNewLinkRuleDialog(editArgs);
202
+ });
183
203
 
184
204
  const linksGridDiv = this.createGridDiv('Rules',
185
- this.linkRuleDataFrame.plot.grid({showAddNewRowIcon: true}),
205
+ linksGrid,
186
206
  'specification for monomers to link and linking positions');
187
207
  const linkExamples = this.createGridDiv('Examples', await this.getLinkExamplesGrid(),
188
208
  'specification for monomers to link and linking positions');
@@ -205,7 +225,7 @@ export class RulesManager {
205
225
  this.linkRuleDataFrame.currentRowIdx = 0;
206
226
  this.linkRuleDataFrame.onCurrentRowChanged.subscribe(async () => {
207
227
  const idx = this.linkRuleDataFrame.currentRowIdx;
208
- if (idx !== -1) {
228
+ if (idx !== -1 && idx != undefined) {
209
229
  ui.empty(gridDiv);
210
230
  gridDiv.append(ui.splitV([
211
231
  ui.box(
@@ -214,10 +234,9 @@ export class RulesManager {
214
234
  ),
215
235
  this.linkCards[idx].root,
216
236
  ]));
237
+ this.linkCards[idx].render();
238
+ await this.linkCards[idx].reset();
217
239
  }
218
-
219
- this.linkCards[idx].render();
220
- await this.linkCards[idx].reset();
221
240
  });
222
241
 
223
242
  const links = ui.splitH([linksGridDiv, gridDiv], null, true);
@@ -260,7 +279,7 @@ export class RulesManager {
260
279
  const addButton = ui.button('Add rule', () => {
261
280
  const currentTab = inputsTabControl.currentPane.name;
262
281
  if (currentTab == TAB_LINKS)
263
- this.linkRuleDataFrame.rows.addNew();
282
+ this.getAddNewLinkRuleDialog();
264
283
  else if (currentTab == TAB_REACTIONS)
265
284
  this.synthRuleDataFrame.rows.addNew();
266
285
  });
@@ -272,5 +291,39 @@ export class RulesManager {
272
291
 
273
292
  return inputsTabControl.root;
274
293
  }
294
+
295
+ getAddNewLinkRuleDialog(preset?: Partial<LinkRuleRowArgs>): void {
296
+ const codeInput = ui.input.int('Code', {nullable: false, value: preset?.code});
297
+ const firstMonomersInput = ui.input.string('First monomers', {placeholder: 'E.g. C,D,E', value: preset?.firstMonomers,
298
+ tooltipText: 'Comma separated list of first monomers applicable for the rule. If left empty, all monomers will be considered', nullable: true});
299
+ const secondMonomersInput = ui.input.string('Second monomers', {placeholder: 'E.g. C,D,E', value: preset?.secondMonomers,
300
+ tooltipText: 'Comma separated list of second monomers applicable for the rule. If left empty, all monomers will be considered', nullable: true});
301
+ const firstLinkingGroup = preset?.firstLinkingGroup ? `R${preset.firstLinkingGroup}` : 'R3';
302
+ const secondLinkingGroup = preset?.secondLinkingGroup ? `R${preset.secondLinkingGroup}` : 'R3';
303
+ const firstLinkingGroupInput = ui.input.choice('First linking group', {value: firstLinkingGroup, items: ['R1', 'R2', 'R3', 'R4'],
304
+ tooltipText: 'Specifies which R-group of the first monomer will be used for linking', nullable: false});
305
+ const secondLinkingGroupInput = ui.input.choice('Second linking group', {value: secondLinkingGroup, items: ['R1', 'R2', 'R3', 'R4'],
306
+ tooltipText: 'Specifies which R-group of the second monomer will be used for linking', nullable: false});
307
+ ui.dialog('Add new link rule')
308
+ .add(codeInput)
309
+ .add(firstMonomersInput)
310
+ .add(secondMonomersInput)
311
+ .add(firstLinkingGroupInput)
312
+ .add(secondLinkingGroupInput)
313
+ .onOK(async () => {
314
+ // we rely on validation of inputs by DG inputs
315
+ const code = codeInput.value!;
316
+ const firstMonomers = (firstMonomersInput.value ?? '').split(',').map((s) => s.trim()).filter((s) => s).join(',');
317
+ const secondMonomers = (secondMonomersInput.value ?? '').split(',').map((s) => s.trim()).filter((s) => s).join(',');
318
+ const firstLinkingGroup = parseInt(firstLinkingGroupInput.value!.substring(1));
319
+ const secondLinkingGroup = parseInt(secondLinkingGroupInput.value!.substring(1));
320
+ this.addLinkRulesFunc({code, firstMonomers: firstMonomers ?? '', secondMonomers: secondMonomers ?? '',
321
+ firstLinkingGroup, secondLinkingGroup, row: preset?.row});
322
+
323
+ this.rules.setLinkRules(this.linkRuleDataFrame);
324
+ this.linkCards = await this.rules.getLinkCards();
325
+ this.save();
326
+ }).show();
327
+ }
275
328
  }
276
329
 
@@ -7,9 +7,9 @@
7
7
  align-items: center;
8
8
  cursor: pointer;
9
9
  width: 200px;
10
- height: 210px;
10
+ height: 240px;
11
11
  min-width: 200px;
12
- min-height: 210px;
12
+ min-height: 240px;
13
13
  }
14
14
 
15
15
  .monomer-card-info-rules {
@@ -76,14 +76,14 @@ category('PolyTool: Convert', () => {
76
76
  'cyclized-D(2)-NH2(2)-3-0': {
77
77
  src: {seq: 'R-F-D(2)-T-G-H-F-Y-P-NH2(2)'},
78
78
  tgt: {
79
- helm: 'PEPTIDE1{R.F.D.T.G.H.F.Y.P.[NH2]}$PEPTIDE1,PEPTIDE1,10:R2-3:R3$$$V2.0',
79
+ helm: 'PEPTIDE1{R.F.D.T.G.H.F.Y.P.[NH2]}$PEPTIDE1,PEPTIDE1,3:R3-10:R2$$$V2.0',
80
80
  mol: {atomCount: 81, bondCount: 86, inchiKey: 'CBMGNYKOZWNVNK-AHGCAHLCSA-N'},
81
81
  }
82
82
  },
83
83
  'cyclized-D(2)-NH2(2)-0-0': {
84
84
  src: {seq: 'D(2)-T-G-H-F-Y-P-NH2(2)'},
85
85
  tgt: {
86
- helm: 'PEPTIDE1{D.T.G.H.F.Y.P.[NH2]}$PEPTIDE1,PEPTIDE1,8:R2-1:R3$$$V2.0',
86
+ helm: 'PEPTIDE1{D.T.G.H.F.Y.P.[NH2]}$PEPTIDE1,PEPTIDE1,1:R3-8:R2$$$V2.0',
87
87
  mol: {atomCount: 59, bondCount: 63, inchiKey: 'HGRHAUQBJXFERJ-MUFWPYSASA-N'},
88
88
  }
89
89
  },