sample-ui-component-library 0.0.46-dev → 0.0.48-dev

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sample-ui-component-library",
3
- "version": "0.0.46-dev",
3
+ "version": "0.0.48-dev",
4
4
  "description": "A library which contains sample UI elements that can be used for populating layouts.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -46,11 +46,13 @@
46
46
  "@storybook/test": "^8.6.11",
47
47
  "@storybook/theming": "^8.6.11",
48
48
  "css-loader": "^7.1.2",
49
+ "dal-engine-core-js-lib-dev": "^0.0.4",
49
50
  "gh-pages": "^6.3.0",
50
51
  "prop-types": "^15.8.1",
51
52
  "raw-loader": "^4.0.2",
52
53
  "react": "^18.2.0",
53
54
  "react-dom": "^18.2.0",
55
+ "reaflow": "^5.4.1",
54
56
  "rollup": "^4.37.0",
55
57
  "rollup-plugin-peer-deps-external": "^2.2.4",
56
58
  "rollup-plugin-postcss": "^4.0.2",
@@ -69,7 +71,6 @@
69
71
  "@dagrejs/dagre": "^1.1.4",
70
72
  "@monaco-editor/react": "^4.7.0",
71
73
  "@xyflow/react": "^12.6.0",
72
- "dal-engine-core-js-lib-dev": "^0.0.4",
73
74
  "react-bootstrap-icons": "^1.11.5"
74
75
  }
75
76
  }
package/rollup.config.mjs CHANGED
@@ -1,13 +1,19 @@
1
1
  import resolve from '@rollup/plugin-node-resolve';
2
2
  import commonjs from '@rollup/plugin-commonjs';
3
3
  import terser from '@rollup/plugin-terser';
4
- import external from 'rollup-plugin-peer-deps-external';
4
+ import peerDepsExternal from 'rollup-plugin-peer-deps-external';
5
5
  import postcss from 'rollup-plugin-postcss';
6
6
  import json from '@rollup/plugin-json';
7
7
  import { babel } from '@rollup/plugin-babel';
8
8
 
9
9
  export default {
10
10
  input: 'src/index.js',
11
+ external: [
12
+ 'react',
13
+ 'react-dom',
14
+ '@dnd-kit/core',
15
+ "reaflow"
16
+ ],
11
17
  output: [
12
18
  {
13
19
  file: 'dist/cjs/index.js',
@@ -21,7 +27,7 @@ export default {
21
27
  },
22
28
  ],
23
29
  plugins: [
24
- external(['react', 'react-dom', '@dnd-kit/core',"reaflow"]),
30
+ peerDepsExternal(),
25
31
  resolve({
26
32
  extensions: ['.js', '.jsx'],
27
33
  }),
@@ -53,7 +53,9 @@ export const BehavioralGraphBuilder = forwardRef(({connectBehaviors, deleteTrans
53
53
 
54
54
  // Callbacks
55
55
  const handleWheel = useCallback((e) => {
56
- (e.deltaY < 0)?canvasRef.current.zoomIn():canvasRef.current.zoomOut();
56
+ if (canvasRef.current) {
57
+ (e.deltaY < 0)?canvasRef.current.zoomIn():canvasRef.current.zoomOut();
58
+ }
57
59
  }, [canvasRef]);
58
60
 
59
61
  const nodeClick = useCallback((e, node) => {
@@ -7,6 +7,6 @@
7
7
  overflow:hidden;
8
8
  }
9
9
 
10
- canvas {
10
+ .canvas-wrapper > canvas {
11
11
  overflow: hidden;
12
12
  }
@@ -1,19 +1,18 @@
1
1
 
2
2
  /**
3
- * Converts a DAL design specification object into React Flow elements (nodes and edges).
4
- * @param {Object} design
3
+ * Converts a DAL design specification object into nodes and edges for reaflow.
4
+ * @param {Object} engine - The engine instance containing the design specification.
5
5
  * @returns {Object} An object containing nodes and edges for React Flow
6
6
  */
7
7
  export const designToNodes = (engine) => {
8
-
9
8
  let edges = [];
10
9
  let nodes = [];
11
10
 
12
11
  for (let i = 0; i < engine.graph.nodes.length; i++) {
13
12
  const node = engine.graph.nodes[i];
14
13
  nodes.push({
15
- id: node.getBehavior().name,
16
- text: node.getBehavior().name,
14
+ id: node.getBehavior().getName(),
15
+ text: node.getBehavior().getName(),
17
16
  });
18
17
  }
19
18
 
@@ -25,8 +24,8 @@ export const designToNodes = (engine) => {
25
24
 
26
25
  node.getGoToBehaviors().forEach((goTo) => {
27
26
  edges.push({
28
- id: `${node.getBehavior().name}->${goTo}`,
29
- from: node.getBehavior().name,
27
+ id: `${node.getBehavior().getName()}->${goTo}`,
28
+ from: node.getBehavior().getName(),
30
29
  to: goTo,
31
30
  });
32
31
  });
@@ -17,6 +17,11 @@ import { EditorContext } from "./EditorContext";
17
17
 
18
18
  import { editorReducer, initialState } from "./EditorReducer";
19
19
 
20
+ const MODES = {
21
+ MAPPING: 1,
22
+ IMPLEMENTATION: 2
23
+ }
24
+
20
25
  /**
21
26
  * Renders the editor component with support for tabs.
22
27
  *
@@ -45,6 +50,10 @@ export const Editor = forwardRef(({ }, ref) => {
45
50
  dispatch({ type: "RESET_STATE"});
46
51
  dispatch({ type: "SET_PARENT_TAB_GROUP_ID", payload: id });
47
52
  }, []);
53
+
54
+ const setMapping = useCallback((fileName, mapping) => {
55
+ dispatch({ type: "SET_MAPPING", payload: { fileName, mapping } });
56
+ }, []);
48
57
 
49
58
  const api = useMemo(() => {
50
59
  return {
@@ -53,9 +62,10 @@ export const Editor = forwardRef(({ }, ref) => {
53
62
  setTabGroupId,
54
63
  selectTab,
55
64
  closeTab,
56
- moveTab
65
+ moveTab,
66
+ setMapping
57
67
  };
58
- }, [state, addTab, selectTab, closeTab, moveTab, setTabGroupId]);
68
+ }, [state, addTab, selectTab, closeTab, moveTab, setTabGroupId, setMapping]);
59
69
 
60
70
  useImperativeHandle(ref, () => api, [api]);
61
71
 
@@ -99,6 +99,25 @@ export const editorReducer = (state, action) => {
99
99
  tabs: prevTabs
100
100
  };
101
101
  }
102
+
103
+ case "SET_MAPPING": {
104
+ const { mapping, fileName } = action.payload;
105
+ console.log(state);
106
+ for (let i = 0; i < state.tabs.length; i++) {
107
+ const tab = state.tabs[i];
108
+ if (tab.name === fileName) {
109
+ const updatedTab = { ...tab, mapping: mapping };
110
+ const newTabs = [...state.tabs];
111
+ newTabs[i] = updatedTab;
112
+ return {
113
+ ...state,
114
+ tabs: newTabs,
115
+ activeTab: updatedTab
116
+ };
117
+ }
118
+ }
119
+ return state;
120
+ }
102
121
 
103
122
  case "RESET_STATE": {
104
123
  return initialState;
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef, useState } from 'react';
1
+ import React, { useCallback, useLayoutEffect, useEffect, useRef, useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
 
4
4
  import Editor from '@monaco-editor/react';
@@ -17,14 +17,22 @@ export const MonacoInstance = ({ }) => {
17
17
  const containerRef = useRef(null);
18
18
  const frameRef = useRef(0);
19
19
 
20
- useEffect(() => {
20
+ const [overlayDivs, setOverlayDivs] = useState();
21
+ const [overlayRanges, setOverlayRanges] = useState();
22
+
23
+ useLayoutEffect(() => {
21
24
  if (state.activeTab) {
22
25
  setEditorContent(state.activeTab.content);
23
26
  setShowEditor(true);
27
+ if (state.activeTab.mapping) {
28
+ addOverlays(state.activeTab.mapping);
29
+ } else {
30
+ setOverlayDivs([]);
31
+ }
24
32
  } else {
25
33
  setShowEditor(false);
26
34
  }
27
- }, [state.activeTab]);
35
+ }, [state.activeTab, editorRef]);
28
36
 
29
37
  useEffect(() => {
30
38
  content.current = editorContent;
@@ -38,13 +46,53 @@ export const MonacoInstance = ({ }) => {
38
46
  * @param {Object} editor
39
47
  * @param {Object} monaco
40
48
  */
41
- const handleEditorDidMount = (editor, monaco) => {
49
+ const handleEditorDidMount = useCallback((editor, monaco) => {
42
50
  editorRef.current = editor;
43
51
  if (content?.current) {
44
52
  editorRef.current.setValue(content.current);
45
53
  }
46
54
  editorRef.current.layout();
47
- }
55
+ if (state.activeTab?.mapping) {
56
+ addOverlays(state.activeTab.mapping);
57
+ } else {
58
+ setOverlayDivs([]);
59
+ }
60
+ }, [state.activeTab]);
61
+
62
+ // Add overlays to editor for the given line ranges.
63
+ const addOverlays = useCallback((ranges) => {
64
+ if (!editorRef.current) return;
65
+
66
+ const lineCount = editorRef.current.getModel().getLineCount();
67
+ const lineHeight = editorRef.current.getOption(monaco.editor.EditorOption.lineHeight);
68
+
69
+ const divs = [];
70
+ ranges.forEach((entry) => {
71
+ const top = editorRef.current.getTopForLineNumber(entry.start_line) - editorRef.current.getScrollTop();
72
+ let bottom = editorRef.current.getTopForLineNumber(entry.end_line + 1) - editorRef.current.getScrollTop();
73
+ if (entry.end_line >= lineCount) {
74
+ bottom = bottom + lineHeight;
75
+ }
76
+ const overlayDiv = <div className="line-block-overlay" style={{ top: top + "px", height: (bottom - top) + "px" }}></div>;
77
+ divs.push(overlayDiv);
78
+ });
79
+ setOverlayDivs(divs);
80
+ }, [editorRef?.current]);
81
+
82
+ // Scroll the editor and update overlays on wheel event.
83
+ const handleWheel = useCallback((e) => {
84
+ if (!editorRef.current) return;
85
+ const deltaY = e.deltaY;
86
+ const currentScrollTop = editorRef.current.getScrollTop();
87
+ editorRef.current.setScrollTop(currentScrollTop + deltaY);
88
+ if (state.activeTab?.mapping) {
89
+ addOverlays(state.activeTab.mapping);
90
+ } else {
91
+ setOverlayDivs([]);
92
+ }
93
+ }, [overlayRanges, state.activeTab]);
94
+
95
+
48
96
 
49
97
  // Editor options for Monaco Editor.
50
98
  const editorOptions = {
@@ -70,6 +118,7 @@ export const MonacoInstance = ({ }) => {
70
118
  cancelAnimationFrame(frameRef.current);
71
119
  frameRef.current = requestAnimationFrame(() => {
72
120
  editorRef.current?.layout();
121
+ addOverlays(state.activeTab.mapping);
73
122
  });
74
123
  });
75
124
 
@@ -79,7 +128,7 @@ export const MonacoInstance = ({ }) => {
79
128
  cancelAnimationFrame(frameRef.current);
80
129
  ro.disconnect();
81
130
  };
82
- }, []);
131
+ }, [state.activeTab, addOverlays]);
83
132
 
84
133
  /**
85
134
  * Render the editor if there is an active tab, otherwise render a placeholder message.
@@ -104,6 +153,9 @@ export const MonacoInstance = ({ }) => {
104
153
  return (
105
154
  <div className="editor-container" ref={containerRef}>
106
155
  {renderEditor()}
156
+ <div className="overlay-layer" onWheel={handleWheel}>
157
+ {overlayDivs}
158
+ </div>
107
159
  </div>
108
160
  )
109
161
  }
@@ -11,4 +11,24 @@
11
11
  position:relative;
12
12
  width:100%;
13
13
  height: 100%;
14
+ }
15
+
16
+ .overlay-layer {
17
+ position: absolute;
18
+ left: 0;
19
+ right: 0;
20
+ inset: 0;
21
+ overflow:hidden;
22
+ }
23
+
24
+ .line-block-overlay {
25
+ z-index: 999;
26
+ position: absolute;
27
+ left: 0;
28
+ right: 0;
29
+ }
30
+
31
+ .line-block-overlay:hover {
32
+ background-color: rgba(255, 166, 0, 0.3);
33
+ cursor: pointer;
14
34
  }
@@ -46,19 +46,19 @@ const Template = (args) => {
46
46
  activeTool: activeTool,
47
47
  design: design,
48
48
  });
49
- }, []);
49
+ }, [activeTool, design]);
50
50
 
51
51
  useEffect(() => {
52
52
  if (editorRef.current) {
53
53
  const engine = new DALEngine({ name: "testEngine" });
54
- // engine.deserialize(JSON.stringify(design));
55
54
  setEngine(engine);
56
55
  editorRef.current.updateEngine(engine);
57
- setTimeout(() => {
56
+ const timerId = setTimeout(() => {
58
57
  engine.addNode("testBehavior", []);
59
58
  engine.addNode("testBehavior2", []);
60
59
  editorRef.current.updateEngine(engine);
61
60
  }, 4000);
61
+ return () => clearTimeout(timerId);
62
62
  }
63
63
  }, [design, editorRef]);
64
64
 
@@ -11,6 +11,8 @@ import {
11
11
  } from "@dnd-kit/core";
12
12
 
13
13
  import WorkspaceSampleTree from "./data/FileBrowser/workspace_sample.json"
14
+ import transactiondb_mapping from "./data/Mapping/TransactionDB_mapping.json"
15
+ import mapping from "./data/Mapping/mapping.json"
14
16
 
15
17
  import "./EditorStories.scss"
16
18
 
@@ -52,15 +54,12 @@ const Template = (args) => {
52
54
  }
53
55
  });
54
56
 
55
-
56
- const node = {
57
- "name": "SAMPLE",
58
- "type": "file",
59
- "uid": "dissr-f6459410-1634-4dbc-8d76-35896822158d",
60
- "content": "1234"
61
- }
62
-
63
- editorRef.current.addTab(node,2);
57
+ const result = flattenTree(WorkspaceSampleTree.tree).find(
58
+ (obj) => obj.name === "TransactionDB.py"
59
+ );
60
+ editorRef.current.addTab(result);
61
+ // editorRef.current.setMapping("FrenchTranslator.py", mapping);
62
+ editorRef.current.setMapping("TransactionDB.py", transactiondb_mapping);
64
63
  }, []);
65
64
 
66
65
  const [dragging, setDragging] = useState(false);
@@ -30,12 +30,13 @@ export function ToolBar({ onSelectTool }) {
30
30
  className="icon"
31
31
  />
32
32
  </div>
33
- <div className="toolbarContainer bottom"></div>
33
+ <div className="toolbarContainer bottom">
34
34
  <Floppy
35
35
  onClick={(e) => selectTool("save")}
36
36
  title="Save Design"
37
37
  className="icon"
38
38
  />
39
+ </div>
39
40
  </div>
40
41
  );
41
42
  }
@@ -1 +1,66 @@
1
- {"tree":[{"name":"library_manager_single_threaded","type":"folder","uid":"dir-ba56de84-31dd-4ccf-ae98-a98b0581f803","children":[{"name":"library_manager.py","type":"file","uid":"dir-3d7aaf8e-6224-4eb7-8301-936447fef430","content":"import sys\n\ndef place_book_on_shelf(book_shelf, name, genre):\n '''\n This function places the given book on the shelf \n in a slot determined by the first letter of its name.\n \n :param book_shelf: Bookshelf to place the book on.\n :param name: Name of the book.\n :param genre: Genre of the book.\n '''\n print(f\"Accepted book: {name} (Genre: {genre})\")\n \n firstLetter = name[0].upper()\n\n if (firstLetter not in book_shelf):\n book_shelf[firstLetter] = []\n else:\n print(\"Slot for book already exists.\")\n\n book_shelf[firstLetter].append(name)\n\n return book_shelf\n\ndef accept_book():\n '''\n Accepts a book and genre from the user and returns it.\n '''\n print(\"\\nEnter book details:\")\n \n name = input(\"Book name: \")\n\n genre = input(\"Genre: \")\n\n return {\"name\":name, \"genre\":genre}\n\n\ndef library_manager():\n '''\n Runs the library manager to accept books until the user decides to stop.\n '''\n book_shelf = {}\n\n while True:\n book_details = accept_book()\n book_shelf = place_book_on_shelf(\n book_shelf, \n book_details[\"name\"], \n book_details[\"genre\"]\n )\n\n more = input(\"Add another book? (y): \").lower()\n \n if more != \"y\":\n break\n\n print(\"Exiting library manager, goodbye.\")\n\nif __name__ == \"__main__\":\n sys.exit(library_manager())\n "},{"name":"readme","type":"file","uid":"dir-5aa507ee-e43d-4d77-b49a-b6e0b1da36f5","content":"This is version 1 of the library manager and it contains a simple implementation that accepts a book name and genre before placing it on the shelf. It places it on the shelf using the first letter of the book name. It continues to accept books until the user decides to stop.\n\nThis version of the library manager will also use instrumentation to identify abstractions by line to overcome the limitations of existing techniques."}]},{"name":"text_translator","type":"folder","uid":"dir-cbb97582-e3da-403e-aa7f-a524a5a7cff7","children":[{"name":"FrenchTranslator.py","type":"file","uid":"dir-516008b2-e80c-4a3a-bb00-d651885ac15d","content":"import threading\nimport queue\nfrom deep_translator import GoogleTranslator # type: ignore\n\nclass FrenchTranslator(threading.Thread):\n def __init__(self, id, queue, packerQueue):\n super().__init__(daemon=True)\n self.queue = queue\n self.id = id\n self.packerQueue = packerQueue\n self.start()\n\n def run(self):\n while True:\n try:\n job = self.queue.get(timeout=10)\n except queue.Empty:\n continue\n\n translatedMsg = GoogleTranslator(source=\"auto\", target=\"french\").translate(job[\"value\"][\"data\"])\n self.packerQueue.put({\n \"uid\": job[\"uid\"],\n \"value\": {\n \"language\": \"french\",\n \"original\": job[\"value\"][\"data\"],\n \"translated\": translatedMsg\n }\n })"},{"name":"Packer.py","type":"file","uid":"dir-e5085241-ff4f-434d-85ab-7f50e673ea4d","content":"import threading\nimport queue\nfrom TransactionDB import TransactionDB\n\nclass PackerThread(threading.Thread):\n def __init__(self, queue):\n super().__init__(daemon=True)\n self.queue = queue\n self.items = {}\n self.start()\n\n def run(self):\n self.db = TransactionDB()\n while True:\n try:\n translatedJobPart = self.queue.get(timeout=10)\n except queue.Empty:\n continue\n\n self.db.addTranslation(translatedJobPart)\n\n if self.db.isDone(translatedJobPart[\"uid\"]):\n self.db.setDone(translatedJobPart[\"uid\"])"},{"name":"SpanishTranslator.py","type":"file","uid":"dir-b2a78dfd-aa94-4068-a5f7-24c396d88825","content":"import threading\nimport queue\nfrom deep_translator import GoogleTranslator # type: ignore\n\nclass SpanishTranslator(threading.Thread):\n def __init__(self, id, queue, packerQueue):\n super().__init__(daemon=True)\n self.queue = queue\n self.id = id\n self.packerQueue = packerQueue\n self.start()\n\n def run(self):\n while True:\n try:\n job = self.queue.get(timeout=10)\n except queue.Empty:\n continue\n\n translatedMsg = GoogleTranslator(source=\"auto\", target=\"spanish\").translate(job[\"value\"][\"data\"])\n self.packerQueue.put({\n \"uid\": job[\"uid\"],\n \"value\": {\n \"language\": \"spanish\",\n \"original\": job[\"value\"][\"data\"],\n \"translated\": translatedMsg\n }\n })"},{"name":"TamilTranslator.py","type":"file","uid":"dir-594ff411-b916-4a88-9077-3d5b8ff7f871","content":"import threading\nimport queue\nfrom deep_translator import GoogleTranslator # type: ignore\n\nclass TamilTranslator(threading.Thread):\n def __init__(self, id, queue, packerQueue):\n super().__init__(daemon=True)\n self.queue = queue\n self.id = id\n self.packerQueue = packerQueue\n self.start()\n\n def run(self):\n while True:\n try:\n job = self.queue.get(timeout=10)\n except queue.Empty:\n continue\n\n translatedMsg = GoogleTranslator(source=\"auto\", target=\"tamil\").translate(job[\"value\"][\"data\"])\n self.packerQueue.put({\n \"uid\": job[\"uid\"],\n \"value\": {\n \"language\": \"tamil\",\n \"original\": job[\"value\"][\"data\"],\n \"translated\": translatedMsg\n }\n })"},{"name":"readme","type":"file","uid":"dir-f6459410-1634-4dbc-8d76-35896822158d","content":"This folder contains a text translator that uses three workers to translate the text and uses a packer to add the results to a cabinet."}]}]}
1
+ {
2
+ "tree": [
3
+ {
4
+ "name": "library_manager_single_threaded",
5
+ "type": "folder",
6
+ "uid": "dir-ba56de84-31dd-4ccf-ae98-a98b0581f803",
7
+ "children": [
8
+ {
9
+ "name": "library_manager.py",
10
+ "type": "file",
11
+ "uid": "dir-3d7aaf8e-6224-4eb7-8301-936447fef430",
12
+ "content": "import sys\n\ndef place_book_on_shelf(book_shelf, name, genre):\n '''\n This function places the given book on the shelf \n in a slot determined by the first letter of its name.\n \n :param book_shelf: Bookshelf to place the book on.\n :param name: Name of the book.\n :param genre: Genre of the book.\n '''\n print(f\"Accepted book: {name} (Genre: {genre})\")\n \n firstLetter = name[0].upper()\n\n if (firstLetter not in book_shelf):\n book_shelf[firstLetter] = []\n else:\n print(\"Slot for book already exists.\")\n\n book_shelf[firstLetter].append(name)\n\n return book_shelf\n\ndef accept_book():\n '''\n Accepts a book and genre from the user and returns it.\n '''\n print(\"\\nEnter book details:\")\n \n name = input(\"Book name: \")\n\n genre = input(\"Genre: \")\n\n return {\"name\":name, \"genre\":genre}\n\n\ndef library_manager():\n '''\n Runs the library manager to accept books until the user decides to stop.\n '''\n book_shelf = {}\n\n while True:\n book_details = accept_book()\n book_shelf = place_book_on_shelf(\n book_shelf, \n book_details[\"name\"], \n book_details[\"genre\"]\n )\n\n more = input(\"Add another book? (y): \").lower()\n \n if more != \"y\":\n break\n\n print(\"Exiting library manager, goodbye.\")\n\nif __name__ == \"__main__\":\n sys.exit(library_manager())\n "
13
+ },
14
+ {
15
+ "name": "readme",
16
+ "type": "file",
17
+ "uid": "dir-5aa507ee-e43d-4d77-b49a-b6e0b1da36f5",
18
+ "content": "This is version 1 of the library manager and it contains a simple implementation that accepts a book name and genre before placing it on the shelf. It places it on the shelf using the first letter of the book name. It continues to accept books until the user decides to stop.\n\nThis version of the library manager will also use instrumentation to identify abstractions by line to overcome the limitations of existing techniques."
19
+ }
20
+ ]
21
+ },
22
+ {
23
+ "name": "text_translator",
24
+ "type": "folder",
25
+ "uid": "dir-cbb97582-e3da-403e-aa7f-a524a5a7cff7",
26
+ "children": [
27
+ {
28
+ "name": "FrenchTranslator.py",
29
+ "type": "file",
30
+ "uid": "dir-516008b2-e80c-4a3a-bb00-d651885ac15d",
31
+ "content": "import threading\nimport queue\nfrom deep_translator import GoogleTranslator # type: ignore\n\nclass FrenchTranslator(threading.Thread):\n def __init__(self, id, queue, packerQueue):\n super().__init__(daemon=True)\n self.queue = queue\n self.id = id\n self.packerQueue = packerQueue\n self.start()\n\n def run(self):\n while True:\n try:\n job = self.queue.get(timeout=10)\n except queue.Empty:\n continue\n\n translatedMsg = GoogleTranslator(source=\"auto\", target=\"french\").translate(job[\"value\"][\"data\"])\n self.packerQueue.put({\n \"uid\": job[\"uid\"],\n \"value\": {\n \"language\": \"french\",\n \"original\": job[\"value\"][\"data\"],\n \"translated\": translatedMsg\n }\n })"
32
+ },
33
+ {
34
+ "name": "Packer.py",
35
+ "type": "file",
36
+ "uid": "dir-e5085241-ff4f-434d-85ab-7f50e673ea4d",
37
+ "content": "import threading\nimport queue\nfrom TransactionDB import TransactionDB\n\nclass PackerThread(threading.Thread):\n def __init__(self, queue):\n super().__init__(daemon=True)\n self.queue = queue\n self.items = {}\n self.start()\n\n def run(self):\n self.db = TransactionDB()\n while True:\n try:\n translatedJobPart = self.queue.get(timeout=10)\n except queue.Empty:\n continue\n\n self.db.addTranslation(translatedJobPart)\n\n if self.db.isDone(translatedJobPart[\"uid\"]):\n self.db.setDone(translatedJobPart[\"uid\"])"
38
+ },
39
+ {
40
+ "name": "SpanishTranslator.py",
41
+ "type": "file",
42
+ "uid": "dir-b2a78dfd-aa94-4068-a5f7-24c396d88825",
43
+ "content": "import threading\nimport queue\nfrom deep_translator import GoogleTranslator # type: ignore\n\nclass SpanishTranslator(threading.Thread):\n def __init__(self, id, queue, packerQueue):\n super().__init__(daemon=True)\n self.queue = queue\n self.id = id\n self.packerQueue = packerQueue\n self.start()\n\n def run(self):\n while True:\n try:\n job = self.queue.get(timeout=10)\n except queue.Empty:\n continue\n\n translatedMsg = GoogleTranslator(source=\"auto\", target=\"spanish\").translate(job[\"value\"][\"data\"])\n self.packerQueue.put({\n \"uid\": job[\"uid\"],\n \"value\": {\n \"language\": \"spanish\",\n \"original\": job[\"value\"][\"data\"],\n \"translated\": translatedMsg\n }\n })"
44
+ },
45
+ {
46
+ "name": "TamilTranslator.py",
47
+ "type": "file",
48
+ "uid": "dir-594ff411-b916-4a88-9077-3d5b8ff7f871",
49
+ "content": "import threading\nimport queue\nfrom deep_translator import GoogleTranslator # type: ignore\n\nclass TamilTranslator(threading.Thread):\n def __init__(self, id, queue, packerQueue):\n super().__init__(daemon=True)\n self.queue = queue\n self.id = id\n self.packerQueue = packerQueue\n self.start()\n\n def run(self):\n while True:\n try:\n job = self.queue.get(timeout=10)\n except queue.Empty:\n continue\n\n translatedMsg = GoogleTranslator(source=\"auto\", target=\"tamil\").translate(job[\"value\"][\"data\"])\n self.packerQueue.put({\n \"uid\": job[\"uid\"],\n \"value\": {\n \"language\": \"tamil\",\n \"original\": job[\"value\"][\"data\"],\n \"translated\": translatedMsg\n }\n })"
50
+ },
51
+ {
52
+ "name": "readme",
53
+ "type": "file",
54
+ "uid": "dir-f6459410-1634-4dbc-8d76-35896822158d",
55
+ "content": "This folder contains a text translator that uses three workers to translate the text and uses a packer to add the results to a cabinet."
56
+ },
57
+ {
58
+ "name": "TransactionDB.py",
59
+ "type": "file",
60
+ "uid": "dir-f6459410-1634-4dbc-8d76-35sfdvsd6822158d",
61
+ "content": "import sqlite3\nimport atexit\nimport uuid\n\nclass TransactionDB():\n\n def __init__(self):\n atexit.register(self.cleanup_function)\n self.initializeDB()\n\n def cleanup_function(self):\n self.conn.close()\n\n def initializeDB(self):\n\n self.conn = sqlite3.connect(\"translations.db\")\n self.cursor = self.conn.cursor()\n\n self.cursor.execute(\"\"\"\n CREATE TABLE IF NOT EXISTS translation_jobs (\n job_id INTEGER PRIMARY KEY AUTOINCREMENT,\n uid TEXT NOT NULL UNIQUE,\n english TEXT NOT NULL,\n french TEXT,\n spanish TEXT,\n tamil TEXT,\n done INTEGER NOT NULL DEFAULT 0\n );\n \"\"\")\n self.conn.commit()\n\n def addJob(self, data):\n uid = str(uuid.uuid4())\n self.conn.execute(\n \"\"\"\n INSERT INTO translation_jobs (uid, english)\n VALUES (?, ?)\n \"\"\",\n (uid, data)\n )\n self.conn.commit()\n\n return {\n \"uid\": uid,\n \"value\": {\"data\": data}\n }\n \n def addTranslation(self, msg):\n self.conn.execute(\n f\"\"\"\n UPDATE translation_jobs\n SET {msg[\"value\"][\"language\"]} = ?\n WHERE uid = ?\n \"\"\",\n (msg[\"value\"][\"translated\"], msg[\"uid\"])\n )\n self.conn.commit()\n\n\n def isDone(self, uid):\n cur = self.conn.execute(\n \"\"\"\n SELECT\n french IS NOT NULL\n AND spanish IS NOT NULL\n AND tamil IS NOT NULL\n FROM translation_jobs\n WHERE uid = ?\n \"\"\",\n (uid,)\n )\n row = cur.fetchone()\n return bool(row[0]) if row else False\n \n def setDone(self, uid):\n self.conn.execute(\n \"\"\"\n UPDATE translation_jobs\n SET done = 1\n WHERE uid = ?\n \"\"\",\n (uid,)\n )\n self.conn.commit()\n\n\n "
62
+ }
63
+ ]
64
+ }
65
+ ]
66
+ }
@@ -0,0 +1,149 @@
1
+ [
2
+ {
3
+ "type": "Import",
4
+ "uid": "41375952-c2b0-4d81-9833-f7e38afe5130",
5
+ "start_line": 1,
6
+ "end_line": 1,
7
+ "source": "import sqlite3"
8
+ },
9
+ {
10
+ "type": "Import",
11
+ "uid": "a8ceb80a-390d-4d0e-a3b4-db9f299a067b",
12
+ "start_line": 2,
13
+ "end_line": 2,
14
+ "source": "import atexit"
15
+ },
16
+ {
17
+ "type": "Import",
18
+ "uid": "eccfad0c-1487-4d39-84e2-24107925be66",
19
+ "start_line": 3,
20
+ "end_line": 3,
21
+ "source": "import uuid"
22
+ },
23
+ {
24
+ "type": "Expr",
25
+ "uid": "b13d053d-b448-42cf-adce-2720d7026c28",
26
+ "start_line": 8,
27
+ "end_line": 8,
28
+ "source": "atexit.register(self.cleanup_function)"
29
+ },
30
+ {
31
+ "type": "Expr",
32
+ "uid": "d735f8a9-b2d9-4af7-b8d0-021bbb8a8945",
33
+ "start_line": 9,
34
+ "end_line": 9,
35
+ "source": "self.initializeDB()"
36
+ },
37
+ {
38
+ "type": "Expr",
39
+ "uid": "f96705c3-5afb-4ad2-ad3b-66e0f8c1fa44",
40
+ "start_line": 12,
41
+ "end_line": 12,
42
+ "source": "self.conn.close()"
43
+ },
44
+ {
45
+ "type": "Assign",
46
+ "uid": "3597725d-8fba-486f-9788-4f346ba91be9",
47
+ "start_line": 16,
48
+ "end_line": 16,
49
+ "source": "self.conn = sqlite3.connect(\"translations.db\")"
50
+ },
51
+ {
52
+ "type": "Assign",
53
+ "uid": "8e34543e-d1a8-4f0b-9945-9fc61b192e88",
54
+ "start_line": 17,
55
+ "end_line": 17,
56
+ "source": "self.cursor = self.conn.cursor()"
57
+ },
58
+ {
59
+ "type": "Expr",
60
+ "uid": "3071e179-638f-428c-9afc-e7c92997cec8",
61
+ "start_line": 19,
62
+ "end_line": 29,
63
+ "source": "self.cursor.execute(\"\"\"\n CREATE TABLE IF NOT EXISTS translation_jobs (\n job_id INTEGER PRIMARY KEY AUTOINCREMENT,\n uid TEXT NOT NULL UNIQUE,\n english TEXT NOT NULL,\n french TEXT,\n spanish TEXT,\n tamil TEXT,\n done INTEGER NOT NULL DEFAULT 0\n );\n \"\"\")"
64
+ },
65
+ {
66
+ "type": "Expr",
67
+ "uid": "053a69cc-9959-4011-83b9-9cd01948d560",
68
+ "start_line": 30,
69
+ "end_line": 30,
70
+ "source": "self.conn.commit()"
71
+ },
72
+ {
73
+ "type": "Assign",
74
+ "uid": "c0c88646-99fc-45de-b441-1efbfb617467",
75
+ "start_line": 33,
76
+ "end_line": 33,
77
+ "source": "uid = str(uuid.uuid4())"
78
+ },
79
+ {
80
+ "type": "Expr",
81
+ "uid": "a0dc4483-bf8d-4790-b6ee-11d4c3ff6747",
82
+ "start_line": 34,
83
+ "end_line": 40,
84
+ "source": "self.conn.execute(\n \"\"\"\n INSERT INTO translation_jobs (uid, english)\n VALUES (?, ?)\n \"\"\",\n (uid, data)\n )"
85
+ },
86
+ {
87
+ "type": "Expr",
88
+ "uid": "5daf0842-9da2-473f-906f-177b2297e42a",
89
+ "start_line": 41,
90
+ "end_line": 41,
91
+ "source": "self.conn.commit()"
92
+ },
93
+ {
94
+ "type": "Return",
95
+ "uid": "e5507376-e78c-49a8-953f-a50f7d534e91",
96
+ "start_line": 43,
97
+ "end_line": 46,
98
+ "source": "return {\n \"uid\": uid,\n \"value\": {\"data\": data}\n }"
99
+ },
100
+ {
101
+ "type": "Expr",
102
+ "uid": "5c91cc00-0bab-45f4-8c44-52b9cbba0033",
103
+ "start_line": 49,
104
+ "end_line": 56,
105
+ "source": "self.conn.execute(\n f\"\"\"\n UPDATE translation_jobs\n SET {msg[\"value\"][\"language\"]} = ?\n WHERE uid = ?\n \"\"\",\n (msg[\"value\"][\"translated\"], msg[\"uid\"])\n )"
106
+ },
107
+ {
108
+ "type": "Expr",
109
+ "uid": "50dbde63-e2af-4788-bba3-72ce9aa6cd4b",
110
+ "start_line": 57,
111
+ "end_line": 57,
112
+ "source": "self.conn.commit()"
113
+ },
114
+ {
115
+ "type": "Assign",
116
+ "uid": "709389e7-985b-433e-b2cb-e77d5a4b8b54",
117
+ "start_line": 61,
118
+ "end_line": 71,
119
+ "source": "cur = self.conn.execute(\n \"\"\"\n SELECT\n french IS NOT NULL\n AND spanish IS NOT NULL\n AND tamil IS NOT NULL\n FROM translation_jobs\n WHERE uid = ?\n \"\"\",\n (uid,)\n )"
120
+ },
121
+ {
122
+ "type": "Assign",
123
+ "uid": "31c90fb9-89a3-45d9-a2cf-ab0941b26668",
124
+ "start_line": 72,
125
+ "end_line": 72,
126
+ "source": "row = cur.fetchone()"
127
+ },
128
+ {
129
+ "type": "Return",
130
+ "uid": "2273d6fc-aa36-4abf-9f98-8259a9d3fd0b",
131
+ "start_line": 73,
132
+ "end_line": 73,
133
+ "source": "return bool(row[0]) if row else False"
134
+ },
135
+ {
136
+ "type": "Expr",
137
+ "uid": "695d4481-ba24-458d-80db-0e600296cf2b",
138
+ "start_line": 76,
139
+ "end_line": 83,
140
+ "source": "self.conn.execute(\n \"\"\"\n UPDATE translation_jobs\n SET done = 1\n WHERE uid = ?\n \"\"\",\n (uid,)\n )"
141
+ },
142
+ {
143
+ "type": "Expr",
144
+ "uid": "7d6571df-d51f-461a-8a2f-59ce793a3444",
145
+ "start_line": 84,
146
+ "end_line": 84,
147
+ "source": "self.conn.commit()"
148
+ }
149
+ ]