From d31f955dce6498f4ca61cd353ffd50b2c984b5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=A6Ltorio?= Date: Tue, 5 Nov 2024 18:58:45 +0100 Subject: [PATCH] wip router --- .github/workflows/ghpages.yaml | 2 +- .github/workflows/release.yaml | 4 +- .vscode/launch.json | 4 +- manifest.json | 2 +- manifest.xml | 4 +- package-lock.json | 31 ++ package.json | 1 + src/aipane/aipane.js | 380 ------------------------- src/aipane/components/Aipane.tsx | 8 +- src/aipane/components/App.tsx | 18 -- src/aipane/{aipane.html => index.html} | 11 +- src/aipane/index.tsx | 26 +- src/version.ts | 4 +- webpack.config.js | 7 +- 14 files changed, 81 insertions(+), 421 deletions(-) delete mode 100644 src/aipane/aipane.js delete mode 100644 src/aipane/components/App.tsx rename src/aipane/{aipane.html => index.html} (83%) diff --git a/.github/workflows/ghpages.yaml b/.github/workflows/ghpages.yaml index d40a5ec..08f4b44 100644 --- a/.github/workflows/ghpages.yaml +++ b/.github/workflows/ghpages.yaml @@ -34,7 +34,7 @@ jobs: run: | GROQ_API_KEY=${{ secrets.GROQ_API_KEY }} npm run getGroqModels npm run build:github-pages - cp dist/aipane.html dist/index.html + # cp dist/index.html dist/index.html - name: Upload pages artifact uses: actions/upload-pages-artifact@v3 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f8ca8fd..39098a3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -34,7 +34,7 @@ jobs: run: | GROQ_API_KEY=${{ secrets.GROQ_API_KEY }} npm run getGroqModels npm run build - cp dist/aipane.html dist/index.html + # cp dist/aipane.html dist/index.html - name: Zip dist folder run: | @@ -61,7 +61,7 @@ jobs: run: | GROQ_API_KEY=${{ secrets.GROQ_API_KEY }} npm run getGroqModels npm run build:github-pages - cp dist/aipane.html dist/index.html + # cp dist/aipane.html dist/index.html - name: Zip dist folder run: | diff --git a/.vscode/launch.json b/.vscode/launch.json index de18004..4e809f4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Launch Edge", "request": "launch", "type": "msedge", - "url": "https://localhost:3000/aipane.html", + "url": "https://localhost:3000/", "runtimeExecutable": "canary", "webRoot": "${workspaceFolder}" }, @@ -30,7 +30,7 @@ "name": "Outlook Desktop (Edge Legacy)", "type": "office-addin", "request": "attach", - "url": "https://localhost:3000/aipane.html?_host_Info=Outlook$Win32$16.01$en-US$$$$0", + "url": "https://localhost:3000/?_host_Info=Outlook$Win32$16.01$en-US$$$$0", "port": 9222, "timeout": 600000, "webRoot": "${workspaceRoot}", diff --git a/manifest.json b/manifest.json index 1114d1c..056cbed 100644 --- a/manifest.json +++ b/manifest.json @@ -71,7 +71,7 @@ "id": "TaskPaneRuntime", "type": "general", "code": { - "page": "https://localhost:3000/aipane.html" + "page": "https://localhost:3000/" }, "lifetime": "short", "actions": [ diff --git a/manifest.xml b/manifest.xml index 0e685f2..fb8721d 100644 --- a/manifest.xml +++ b/manifest.xml @@ -35,7 +35,7 @@
- + 250
@@ -89,7 +89,7 @@ - + diff --git a/package-lock.json b/package-lock.json index 572a116..97a750a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "@types/office-runtime": "^1.0.35", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", + "@types/react-router-dom": "^5.3.3", "@types/webpack": "^5.28.5", "acorn": "^8.14.0", "babel-loader": "^9.2.1", @@ -5513,6 +5514,13 @@ "@types/unist": "*" } }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -5669,6 +5677,29 @@ "@types/react": "*" } }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", diff --git a/package.json b/package.json index 4482116..4044d9b 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "@types/office-runtime": "^1.0.35", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", + "@types/react-router-dom": "^5.3.3", "@types/webpack": "^5.28.5", "acorn": "^8.14.0", "babel-loader": "^9.2.1", diff --git a/src/aipane/aipane.js b/src/aipane/aipane.js deleted file mode 100644 index a1bf67e..0000000 --- a/src/aipane/aipane.js +++ /dev/null @@ -1,380 +0,0 @@ -"use strict"; -/** - * @file aipane.ts - * @description The AI pane module for the Outlook add-in. - * @author Ronan LE MEILLAT - * @copyright 2024 Ronan LE MEILLAT for SCTG Development - * @license AGPLv3 - */ -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __generator = (this && this.__generator) || function (thisArg, body) { - var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); - return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; - function verb(n) { return function (v) { return step([n, v]); }; } - function step(op) { - if (f) throw new TypeError("Generator is already executing."); - while (g && (g = 0, op[0] && (_ = 0)), _) try { - if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; - if (y = 0, t) op = [op[0] & 2, t.value]; - switch (op[0]) { - case 0: case 1: t = op; break; - case 4: _.label++; return { value: op[1], done: false }; - case 5: _.label++; y = op[1]; op = [0]; continue; - case 7: op = _.ops.pop(); _.trys.pop(); continue; - default: - if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } - if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } - if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } - if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } - if (t[2]) _.ops.pop(); - _.trys.pop(); continue; - } - op = body.call(thisArg, _); - } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } - if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; - } -}; -var __asyncValues = (this && this.__asyncValues) || function (o) { - if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); - var m = o[Symbol.asyncIterator], i; - return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); - function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } - function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.getSelectedText = getSelectedText; -exports.insertAIAnswer = insertAIAnswer; -exports.getAIModels = getAIModels; -exports.waitForOffice = waitForOffice; -exports.isOutlookClient = isOutlookClient; -var ai_sdk_1 = require("@sctg/ai-sdk"); -var config_1 = require("./config"); -var sentencepiece_js_1 = require("@sctg/sentencepiece-js"); -var dompurify_1 = require("dompurify"); -var TOKEN_MARGIN = 20; // Safety margin for token count -var ERROR_MESSAGE = "Error: Unable to insert AI answer."; -/** - * Counts the number of tokens in a given text using the SentencePieceProcessor. - * @param {string} text - The text to be tokenized. - * @returns {Promise} - The number of tokens in the text. - */ -function countTokens(text) { - return __awaiter(this, void 0, void 0, function () { - var cleaned, spp, ids; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - cleaned = (0, sentencepiece_js_1.cleanText)(text); - spp = new sentencepiece_js_1.SentencePieceProcessor(); - // Load the tokeniser model from a base64 string - // llama_3_1_tokeniser_b64 is a pre-trained model for the Llama 3.1 tokeniser and encoded in base64 - return [4 /*yield*/, spp.loadFromB64StringModel(sentencepiece_js_1.llama_3_1_tokeniser_b64)]; - case 1: - // Load the tokeniser model from a base64 string - // llama_3_1_tokeniser_b64 is a pre-trained model for the Llama 3.1 tokeniser and encoded in base64 - _a.sent(); - ids = spp.encodeIds(cleaned); - return [2 /*return*/, ids.length]; // Return the number of tokens - } - }); - }); -} -/** - * Makes an AI request to the @sctg/ai-sdk API. - * @param {AIProvider} provider - The AI provider configuration. - * @param {AIModel} model - The AI model configuration. - * @param {string} apiKey - The API key for authentication. - * @param {string} systemText - The system prompt text. - * @param {string} userText - The user input text. - * @returns {Promise} - The AI-generated response. - */ -function aiRequest(provider, model, apiKey, systemText, userText) { - return __awaiter(this, void 0, void 0, function () { - var proxyUrl, ai, tokenCount, chatCompletion, response, _a, chatCompletion_1, chatCompletion_1_1, chunk, e_1_1; - var _b, e_1, _c, _d; - var _e, _f; - return __generator(this, function (_g) { - switch (_g.label) { - case 0: - proxyUrl = config_1.config.aiproxy.host; - ai = new ai_sdk_1.AI({ - baseURL: provider.baseUrl, - basePath: provider.basePath, - disableCorsCheck: false, - apiKey: apiKey, - dangerouslyAllowBrowser: true, - proxy: provider.aiproxied ? proxyUrl : undefined, - }); - return [4 /*yield*/, countTokens(systemText + userText)]; - case 1: - tokenCount = _g.sent(); - console.log("Token count: ".concat(tokenCount)); - return [4 /*yield*/, ai.chat.completions.create({ - messages: [ - { - role: "system", - content: systemText, - }, - { - role: "user", - content: userText, - }, - ], - model: model.id, - temperature: 1, - max_tokens: model.max_tokens - tokenCount - TOKEN_MARGIN, - top_p: 1, - stream: true, - stop: null, - })]; - case 2: - chatCompletion = _g.sent(); - response = ""; - _g.label = 3; - case 3: - _g.trys.push([3, 8, 9, 14]); - _a = true, chatCompletion_1 = __asyncValues(chatCompletion); - _g.label = 4; - case 4: return [4 /*yield*/, chatCompletion_1.next()]; - case 5: - if (!(chatCompletion_1_1 = _g.sent(), _b = chatCompletion_1_1.done, !_b)) return [3 /*break*/, 7]; - _d = chatCompletion_1_1.value; - _a = false; - chunk = _d; - response += ((_f = (_e = chunk.choices[0]) === null || _e === void 0 ? void 0 : _e.delta) === null || _f === void 0 ? void 0 : _f.content) || ""; - _g.label = 6; - case 6: - _a = true; - return [3 /*break*/, 4]; - case 7: return [3 /*break*/, 14]; - case 8: - e_1_1 = _g.sent(); - e_1 = { error: e_1_1 }; - return [3 /*break*/, 14]; - case 9: - _g.trys.push([9, , 12, 13]); - if (!(!_a && !_b && (_c = chatCompletion_1.return))) return [3 /*break*/, 11]; - return [4 /*yield*/, _c.call(chatCompletion_1)]; - case 10: - _g.sent(); - _g.label = 11; - case 11: return [3 /*break*/, 13]; - case 12: - if (e_1) throw e_1.error; - return [7 /*endfinally*/]; - case 13: return [7 /*endfinally*/]; - case 14: return [2 /*return*/, response]; - } - }); - }); -} -/** - * Retrieves the prompt configuration by its ID. - * @param {string} id - The ID of the prompt. - * @returns {AIPrompt} - The prompt configuration. - */ -function getPrompt(id) { - var prompts = config_1.config.prompts; - var prompt = prompts.find(function (prompt) { return prompt.id === id && (!prompt.standalone || !isOutlookClient()); }); - if (!prompt) { - console.error("getPrompt: Prompt not found"); - throw new Error("Prompt not found"); - } - return prompt; -} -/** - * Retrieves the text selected in the email body. - * @returns Promise - The selected text. - */ -function getSelectedText() { - return new Promise(function (resolve, reject) { - isOutlookClient() - .then(function () { - var _a; - (_a = Office.context.mailbox.item) === null || _a === void 0 ? void 0 : _a.getSelectedDataAsync(Office.CoercionType.Text, function (asyncResult) { - if (asyncResult.status === Office.AsyncResultStatus.Failed) { - reject(asyncResult.error); - } - else { - var text = asyncResult.value.data; - var prop = asyncResult.value.sourceProperty; - console.log("Selected text in " + prop + ": " + text); - resolve(text); - } - }); - }) - .catch(function (error) { - reject(error); - }); - }); -} -/** - * Inserts the AI-generated answer into the email body. - * @param {AIProvider} provider - The AI provider configuration. - * @param {AIModel} model - The AI model configuration. - * @param {string} apiKey - The API key for authentication. - * @param {string} id - The ID of the prompt. - * @param {string} userText - The user input text. - * @returns {Promise} - The AI-generated response and any errors. - */ -function insertAIAnswer(provider, model, apiKey, id, userText) { - return __awaiter(this, void 0, void 0, function () { - var _a, system, user, error, _debug, aiText, err_1; - var _b; - return __generator(this, function (_c) { - switch (_c.label) { - case 0: - _a = getPrompt(id), system = _a.system, user = _a.user; - error = ERROR_MESSAGE; - // Validate and sanitize inputs - if (!system || !user || !userText) { - console.error("insertAIAnswer: Invalid input"); - throw new Error("insertAIAnswer: Invalid input"); - } - _c.label = 1; - case 1: - _c.trys.push([1, 4, , 5]); - _debug = localStorage.getItem("DEBUG"); - console.log("DEBUG: ".concat(_debug)); - if (_debug && _debug === "1") { - // eslint-disable-next-line no-eval - eval("debu" + "gger"); - } - console.log("Prompt: ".concat(id)); - console.log("System text: \n".concat(system)); - console.log("User: ".concat(user)); - console.log("User text: \n".concat(userText)); - return [4 /*yield*/, aiRequest(provider, model, apiKey, system, "".concat(user, "\n").concat(userText))]; - case 2: - aiText = _c.sent(); - console.log("AI provider: ".concat(provider.name, " AI model: ").concat(model.name, ": \n").concat(aiText)); - return [4 /*yield*/, isOutlookClient()]; - case 3: - // Insert the AI-generated text into the email body - if (_c.sent()) { - // Replace newlines with HTML line breaks - aiText = aiText.replace(/\n/g, "
"); - // Sanitize and escape the AI-generated text - aiText = dompurify_1.default.sanitize(aiText); - error = null; - (_b = Office.context.mailbox.item) === null || _b === void 0 ? void 0 : _b.body.setSelectedDataAsync(aiText, { coercionType: Office.CoercionType.Html }, function (asyncResult) { - if (asyncResult.status === Office.AsyncResultStatus.Failed) { - console.error("insertAIAnswer: Error inserting AI answer:", asyncResult.error); - throw new Error(asyncResult.error.message); - } - }); - } - return [2 /*return*/, { response: aiText, error: error }]; - case 4: - err_1 = _c.sent(); - console.error("Error: " + err_1); - return [2 /*return*/, { response: "", error: error }]; - case 5: return [2 /*return*/]; - } - }); - }); -} -/** - * Retrieves a list of AI models for the given provider and filter. - * This function creates an AI instance and uses it to list the models. - * @param {AIProvider} provider - The AI provider configuration. - * @param {string} apiKey - The API key for authentication. - * @param {string} filter - The filter for the model list. - * @returns {Promise} - The list of AI models. - */ -function getAIModels(provider, apiKey, filter) { - return __awaiter(this, void 0, void 0, function () { - var proxyUrl, ai, models, filteredModels, orderedModels, returnedModels_1, error_1; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.label = 1; - case 1: - _a.trys.push([1, 3, , 4]); - proxyUrl = config_1.config.aiproxy.host; - ai = new ai_sdk_1.AI({ - baseURL: provider.baseUrl, - basePath: provider.basePath, - disableCorsCheck: false, - apiKey: apiKey, - dangerouslyAllowBrowser: true, - proxy: provider.aiproxied ? proxyUrl : undefined, - }); - return [4 /*yield*/, ai.models.list()]; - case 2: - models = _a.sent(); - filteredModels = models.data.filter(function (model) { return model.id.includes(filter) && model.active; }); - orderedModels = filteredModels.sort(function (a, b) { return b.created - a.created; }); - returnedModels_1 = []; - orderedModels.forEach(function (model) { - returnedModels_1.push({ - id: model.id, - name: model.id, - default: false, - max_tokens: model.context_window || 2048, - }); - }); - returnedModels_1[0].default = true; - return [2 /*return*/, returnedModels_1]; - case 3: - error_1 = _a.sent(); - console.error("Error retrieving AI models:", error_1); - throw error_1; - case 4: return [2 /*return*/]; - } - }); - }); -} -var officeLoaded = false; -if (typeof Office !== "undefined") { - Office.onReady(function (info) { - console.log("Office SDK ready running ".concat(info.host ? "in" + info.host : "outside office")); - officeLoaded = true; - }); -} -/** - * Wait for the Office.js library to load. - * limit the waiting time to 2 seconds - * @returns {Promise} - A promise that resolves to true when the Office.js library is loaded or to false after 2 seconds. - */ -function waitForOffice() { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve) { - if (officeLoaded) { - resolve(true); - } - else { - setTimeout(function () { - resolve(false); - }, 2000); - } - })]; - }); - }); -} -/** - * Detects if the current app runs in the Outlook client. - * @returns {boolean} - True if the app runs in the Outlook client, false otherwise. - */ -function isOutlookClient() { - return __awaiter(this, void 0, void 0, function () { - var isOutlookLoaded; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, waitForOffice()]; - case 1: - isOutlookLoaded = _a.sent(); - return [2 /*return*/, typeof Office.context.mailbox !== "undefined" && isOutlookLoaded]; - } - }); - }); -} diff --git a/src/aipane/components/Aipane.tsx b/src/aipane/components/Aipane.tsx index 04748ea..3b66121 100644 --- a/src/aipane/components/Aipane.tsx +++ b/src/aipane/components/Aipane.tsx @@ -1,5 +1,5 @@ /** - * @file App.tsx + * @file Aipane.tsx * @description The main application component. * @author Ronan LE MEILLAT * @copyright 2024 Ronan LE MEILLAT for SCTG Development @@ -26,7 +26,7 @@ import { versionInfo } from "../../version"; * @interface AppProps * @description Properties for the App component. */ -interface AppProps { +interface AipaneProps { /** * @description The title of the application. */ @@ -47,10 +47,10 @@ const useStyles = makeStyles({ /** * @function App * @description The main application component. - * @param {AppProps} props + * @param {AipaneProps} props * @returns { React.JSX.Element} The application component. */ -const Aipane: React.FC = (props: AppProps): React.JSX.Element => { +const Aipane: React.FC = (props: AipaneProps): React.JSX.Element => { /** * @state provider * @description The current AI provider. diff --git a/src/aipane/components/App.tsx b/src/aipane/components/App.tsx deleted file mode 100644 index ef0c0ac..0000000 --- a/src/aipane/components/App.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; -import AIPane from "./Aipane"; -import Clean from "./Clean"; -const App: React.FC = () => { - return ( - -
- - } /> - } /> - -
-
- ); -}; - -export default App; diff --git a/src/aipane/aipane.html b/src/aipane/index.html similarity index 83% rename from src/aipane/aipane.html rename to src/aipane/index.html index ef5b969..6a4dcfb 100644 --- a/src/aipane/aipane.html +++ b/src/aipane/index.html @@ -12,6 +12,13 @@ SCTG AI Emailer Add-in + @@ -26,7 +33,7 @@ React container div. --> - + \ No newline at end of file diff --git a/src/aipane/index.tsx b/src/aipane/index.tsx index 8e4c75e..94145f1 100644 --- a/src/aipane/index.tsx +++ b/src/aipane/index.tsx @@ -5,25 +5,43 @@ */ import * as React from "react"; import { createRoot } from "react-dom/client"; -import App from "./components/App"; import { FluentProvider, webLightTheme } from "@fluentui/react-components"; +import AIPane from "./components/Aipane"; +import Clean from "./components/Clean"; + +import { createBrowserRouter, RouterProvider } from "react-router-dom"; const title = "SCTG AI Emailer Add-in"; const rootElement: HTMLElement | null = document.getElementById("container"); const root = rootElement ? createRoot(rootElement) : undefined; +// restore the original history functions +window.history.pushState = globalThis.backupHistoryFunctions.pushState; +window.history.replaceState = globalThis.backupHistoryFunctions.replaceState; +const router = createBrowserRouter([ + { + path: "/", + element: , + }, + { + path: "clean", + element: , + }, +]); /* Render application after Office initializes */ Office.onReady(() => { root?.render( - + + + ); }); if ((module as any).hot) { - (module as any).hot.accept("./components/App", () => { - const NextApp = require("./components/App").default; + (module as any).hot.accept("./components/Aipane", () => { + const NextApp = require("./components/Aipane").default; root?.render(NextApp); }); } diff --git a/src/version.ts b/src/version.ts index 7af3819..70f69ca 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,4 +1,4 @@ export const versionInfo = { - commit: "4a1be68832b9376ecd4b73c17ff2101798012ee6", - date: "2024-11-05 11:44:09 +0100", + commit: "f1729b3e418f5439fdf0bebbe70f041ca134f526", + date: "2024-11-05 12:50:39 +0100", }; diff --git a/webpack.config.js b/webpack.config.js index 927d33a..22d152d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -45,7 +45,7 @@ export default async (env, options) => { entry: { polyfill: ["core-js/stable", "regenerator-runtime/runtime"], vendor: ["react", "react-dom", "core-js", "@fluentui/react-components", "@fluentui/react-icons"], - taskpane: ["./src/aipane/index.tsx", "./src/aipane/aipane.html"], + taskpane: ["./src/aipane/index.tsx", "./src/aipane/index.html"], }, output: { filename: "sctg_ai_outlook_[contenthash].js", @@ -118,8 +118,8 @@ export default async (env, options) => { ], }), new HtmlWebpackPlugin({ - filename: "aipane.html", - template: "./src/aipane/aipane.html", + filename: "index.html", + template: "./src/aipane/index.html", chunks: ["polyfill", "vendor", "taskpane"], }), new webpack.ProvidePlugin({ @@ -143,6 +143,7 @@ export default async (env, options) => { options: env.WEBPACK_BUILD || options.https !== undefined ? options.https : await getHttpsOptions(), }, port: process.env.npm_package_config_dev_server_port || 3000, + historyApiFallback: true, }, };