This commit is contained in:
Pavel Torbeev 2023-09-10 00:19:19 +03:00
commit e3cca280be
71 changed files with 305031 additions and 0 deletions

8
.eslintrc.json Normal file
View File

@ -0,0 +1,8 @@
{
"plugins": [
"office-addins"
],
"extends": [
"plugin:office-addins/react"
]
}

23
.gitignore vendored Normal file
View File

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

5
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -0,0 +1,157 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<HTMLCodeStyleSettings>
<option name="HTML_ATTRIBUTE_WRAP" value="4" />
<option name="HTML_ALIGN_ATTRIBUTES" value="false" />
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
<option name="HTML_ENFORCE_QUOTES" value="true" />
<option name="HTML_NEWLINE_BEFORE_FIRST_ATTRIBUTE" value="When multiline" />
<option name="HTML_NEWLINE_AFTER_LAST_ATTRIBUTE" value="When multiline" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
<option name="SPACES_WITHIN_INTERPOLATION_EXPRESSIONS" value="true" />
</JSCodeStyleSettings>
<PHPCodeStyleSettings>
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="ELSE_IF_STYLE" value="SEPARATE" />
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
</PHPCodeStyleSettings>
<SqlCodeStyleSettings>
<option name="ALIGN_AS_IN_SELECT_STATEMENT" value="false" />
<option name="ALIGN_TYPE_IN_CREATE_STATEMENT" value="false" />
<option name="ALIGN_TYPE_IN_BLOCK_STATEMENT" value="false" />
<option name="ALIGN_TYPE_IN_ARGUMENT_DEFINITION" value="false" />
<option name="ALIGN_INSIDE_BINARY_EXPRESSION" value="false" />
<option name="ALIGN_INSIDE_QUERY_EXPRESSION" value="false" />
<option name="ALIGN_EQ_INSIDE_SET_CLAUSE" value="false" />
<option name="NEW_LINE_BEFORE_QUERY_INSIDE_PARENTHESIS" value="true" />
<option name="KEYWORD_CASE" value="1" />
</SqlCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</TypeScriptCodeStyleSettings>
<VueCodeStyleSettings>
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
</VueCodeStyleSettings>
<codeStyleSettings language="Blade">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="CSS">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="GraphQL">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="HTML">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JSON">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="WRAP_ON_TYPING" value="0" />
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PHP">
<option name="METHOD_BRACE_STYLE" value="1" />
<option name="INDENT_CASE_FROM_SWITCH" value="false" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="5" />
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_CALL_CHAIN_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
</codeStyleSettings>
<codeStyleSettings language="SCSS">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="SQL">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="CALL_PARAMETERS_WRAP" value="5" />
<option name="CALL_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="CALL_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Vue">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="ruby">
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EslintConfiguration">
<option name="fix-on-save" value="true" />
</component>
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/cp-press-release-word-plugin.iml" filepath="$PROJECT_DIR$/.idea/cp-press-release-word-plugin.iml" />
</modules>
</component>
</project>

7
.idea/prettier.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PrettierConfiguration">
<option name="myConfigurationMode" value="AUTOMATIC" />
<option name="myRunOnSave" value="true" />
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

14
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,14 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"ms-edgedevtools.vscode-edge-devtools",
"msoffice.microsoft-office-add-in-debugger",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []
}

93
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,93 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Excel Desktop (Edge Chromium)",
"type": "msedge",
"request": "attach",
"port": 9229,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: Excel Desktop",
"postDebugTask": "Stop Debug"
},
{
"name": "Excel Desktop (Edge Legacy)",
"type": "office-addin",
"request": "attach",
"url": "https://localhost:3000/taskpane.html?_host_Info=Excel$Win32$16.01$en-US$$$$0",
"port": 9222,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: Excel Desktop",
"postDebugTask": "Stop Debug"
},
{
"name": "Outlook Desktop (Edge Chromium)",
"type": "msedge",
"request": "attach",
"useWebView": true,
"port": 9229,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: Outlook Desktop",
"postDebugTask": "Stop Debug"
},
{
"name": "Outlook Desktop (Edge Legacy)",
"type": "office-addin",
"request": "attach",
"url": "https://localhost:3000/taskpane.html?_host_Info=Outlook$Win32$16.01$en-US$$$$0",
"port": 9222,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: Outlook Desktop",
"postDebugTask": "Stop Debug"
},
{
"name": "PowerPoint Desktop (Edge Chromium)",
"type": "msedge",
"request": "attach",
"port": 9229,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: PowerPoint Desktop",
"postDebugTask": "Stop Debug"
},
{
"name": "PowerPoint Desktop (Edge Legacy)",
"type": "office-addin",
"request": "attach",
"url": "https://localhost:3000/taskpane.html?_host_Info=PowerPoint$Win32$16.01$en-US$$$$0",
"port": 9222,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: PowerPoint Desktop",
"postDebugTask": "Stop Debug"
},
{
"name": "Word Desktop (Edge Chromium)",
"type": "msedge",
"request": "attach",
"port": 9229,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: Word Desktop",
"postDebugTask": "Stop Debug"
},
{
"name": "Word Desktop (Edge Legacy)",
"type": "office-addin",
"request": "attach",
"url": "https://localhost:3000/taskpane.html?_host_Info=Word$Win32$16.01$en-US$$$$0",
"port": 9222,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: Word Desktop",
"postDebugTask": "Stop Debug"
}
]
}

8
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript"
]
}

130
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,130 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build (Development)",
"type": "npm",
"script": "build:dev",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
}
},
{
"label": "Build (Production)",
"type": "npm",
"script": "build",
"group": "build",
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
}
},
{
"label": "Debug: Excel Desktop",
"type": "npm",
"script": "start:desktop -- --app excel",
"presentation": {
"clear": true,
"panel": "dedicated",
},
"problemMatcher": []
},
{
"label": "Debug: Outlook Desktop",
"type": "npm",
"script": "start:desktop -- --app outlook",
"presentation": {
"clear": true,
"panel": "dedicated",
},
"problemMatcher": []
},
{
"label": "Debug: PowerPoint Desktop",
"type": "npm",
"script": "start:desktop -- --app powerpoint",
"presentation": {
"clear": true,
"panel": "dedicated",
},
"problemMatcher": []
},
{
"label": "Debug: Word Desktop",
"type": "npm",
"script": "start:desktop -- --app word",
"presentation": {
"clear": true,
"panel": "dedicated",
},
"problemMatcher": []
},
{
"label": "Dev Server",
"type": "npm",
"script": "dev-server",
"presentation": {
"clear": true,
"panel": "dedicated"
},
"problemMatcher": []
},
{
"label": "Install",
"type": "npm",
"script": "install",
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
},
{
"label": "Lint: Check for problems",
"type": "npm",
"script": "lint",
"problemMatcher": [
"$eslint-stylish"
]
},
{
"label": "Lint: Fix all auto-fixable problems",
"type": "npm",
"script": "lint:fix",
"problemMatcher": [
"$eslint-stylish"
]
},
{
"label": "Stop Debug",
"type": "npm",
"script": "stop",
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
},
{
"label": "Watch",
"type": "npm",
"script": "watch",
"presentation": {
"clear": true,
"panel": "dedicated"
},
"problemMatcher": []
},
]
}

BIN
assets/icon-128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
assets/icon-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
assets/icon-32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
assets/icon-64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
assets/icon-80.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
assets/logo-filled.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

3
babel.config.json Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-typescript"]
}

80
dist/8d9dfc10165c310961fd.css vendored Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
* See LICENSE in the project root for license information.
*/
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
ul {
margin: 0;
padding: 0;
}
.ms-welcome__header {
padding: 20px;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
align-items: center;
}
.ms-welcome__main {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-flex-wrap: nowrap;
flex-wrap: nowrap;
/*-webkit-align-items: center;*/
/*align-items: center;*/
-webkit-flex: 1 0 0;
flex: 1 0 0;
padding: 10px 20px;
}
/* */
/* .ms-welcome__main > h2 {*/
/* width: 100%;*/
/* text-align: center;*/
/* }*/
/* */
/* .ms-welcome__features {*/
/* list-style-type: none;*/
/* margin-top: 20px;*/
/* }*/
/* */
/* .ms-welcome__features.ms-List .ms-ListItem {*/
/* padding-bottom: 20px;*/
/* display: -webkit-flex;*/
/* display: flex;*/
/* }*/
/* */
/* .ms-welcome__features.ms-List .ms-ListItem > .ms-Icon {*/
/* margin-right: 10px;*/
/* }*/
/* */
/* .ms-welcome__action.ms-Button--hero {*/
/* margin-top: 30px;*/
/* }*/
/* */
/*.ms-Button.ms-Button--hero .ms-Button-label {*/
/* color: #0078d7;*/
/*}*/
/*.ms-Button.ms-Button--hero:hover .ms-Button-label,*/
/*.ms-Button.ms-Button--hero:focus .ms-Button-label{*/
/* color: #005a9e;*/
/* cursor: pointer;*/
/*}*/
/*b {*/
/* font-weight: bold;*/
/*}*/

BIN
dist/assets/icon-128.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
dist/assets/icon-16.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
dist/assets/icon-32.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
dist/assets/icon-64.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
dist/assets/icon-80.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
dist/assets/logo-filled.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

18
dist/commands.html vendored Normal file
View File

@ -0,0 +1,18 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!-- Office JavaScript API -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script>
<script defer src="commands.js"></script></head>
<body>
</body>
</html>

97
dist/commands.js vendored Normal file
View File

@ -0,0 +1,97 @@
/******/ (function() { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./src/commands/commands.ts":
/*!**********************************!*\
!*** ./src/commands/commands.ts ***!
\**********************************/
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
* See LICENSE in the project root for license information.
*/
/* global global, Office, self, window */
Office.onReady(function () {
// If needed, Office.js is ready to be called
});
/**
* Shows a notification when the add-in command is executed.
* @param event
*/
function action(event) {
var message = {
type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage,
message: "Performed action.",
icon: "Icon.80x80",
persistent: true
};
// Show a notification message
Office.context.mailbox.item.notificationMessages.replaceAsync("action", message);
// Be sure to indicate when the add-in command function is complete
event.completed();
}
function getGlobal() {
return typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : typeof __webpack_require__.g !== "undefined" ? __webpack_require__.g : undefined;
}
var g = getGlobal();
// The add-in command functions need to be available in global scope
g.action = action;
void function register() {
/* react-hot-loader/webpack */var reactHotLoader = typeof reactHotLoaderGlobal !== 'undefined' ? reactHotLoaderGlobal.default : undefined;
if (!reactHotLoader) {
return;
} /* eslint-disable camelcase, no-undef */
var webpackExports = typeof __webpack_exports__ !== 'undefined' ? __webpack_exports__ : exports; /* eslint-enable camelcase, no-undef */
if (!webpackExports) {
return;
}
if (typeof webpackExports === 'function') {
reactHotLoader.register(webpackExports, 'module.exports', "/Users/pavel/work/cp-press-release-word-plugin/src/commands/commands.ts");
return;
} /* eslint-disable no-restricted-syntax */
for (var key in webpackExports) {
/* eslint-enable no-restricted-syntax */if (!Object.prototype.hasOwnProperty.call(webpackExports, key)) {
continue;
}
var namedExport = void 0;
try {
namedExport = webpackExports[key];
} catch (err) {
continue;
}
reactHotLoader.register(namedExport, key, "/Users/pavel/work/cp-press-release-word-plugin/src/commands/commands.ts");
}
}();
/***/ })
/******/ });
/************************************************************************/
/******/ // The require scope
/******/ var __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/global */
/******/ !function() {
/******/ __webpack_require__.g = (function() {
/******/ if (typeof globalThis === 'object') return globalThis;
/******/ try {
/******/ return this || new Function('return this')();
/******/ } catch (e) {
/******/ if (typeof window === 'object') return window;
/******/ }
/******/ })();
/******/ }();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = {};
/******/ __webpack_modules__["./src/commands/commands.ts"](0, __webpack_exports__, __webpack_require__);
/******/
/******/ })()
;
//# sourceMappingURL=commands.js.map

1
dist/commands.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"file":"commands.js","mappings":";;;;;;;;;AAAA;;;;AAKA;AAEAA,MAAM,CAACC,OAAO,CAAC;EACb;AAAA,CACD,CAAC;AAEF;;;;AAIA,SAASC,MAAMA,CAACC,KAAiC;EAC/C,IAAMC,OAAO,GAAsC;IACjDC,IAAI,EAAEL,MAAM,CAACM,YAAY,CAACC,2BAA2B,CAACC,oBAAoB;IAC1EJ,OAAO,EAAE,mBAAmB;IAC5BK,IAAI,EAAE,YAAY;IAClBC,UAAU,EAAE;GACb;EAED;EACAV,MAAM,CAACW,OAAO,CAACC,OAAO,CAACC,IAAI,CAACC,oBAAoB,CAACC,YAAY,CAAC,QAAQ,EAAEX,OAAO,CAAC;EAEhF;EACAD,KAAK,CAACa,SAAS,EAAE;AACnB;AAEA,SAASC,SAASA,CAAA;EAChB,OAAO,OAAOC,IAAI,KAAK,WAAW,GAC9BA,IAAI,GACJ,OAAOC,MAAM,KAAK,WAAW,GAC7BA,MAAM,GACN,OAAOC,qBAAM,KAAK,WAAW,GAC7BA,qBAAM,GACNC,SAAS;AACf;AAEA,IAAMC,CAAC,GAAGL,SAAS,EAAS;AAE5B;AACAK,CAAC,CAACpB,MAAM,GAAGA,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UC3CjB;UACA;;;;;WCDA;WACA;WACA;WACA;WACA,GAAG;WACH;WACA;WACA,CAAC;;;;;UEPD;UACA;UACA;UACA;UACA","sources":["webpack://office-addin-taskpane-react/./src/commands/commands.ts","webpack://office-addin-taskpane-react/webpack/bootstrap","webpack://office-addin-taskpane-react/webpack/runtime/global","webpack://office-addin-taskpane-react/webpack/before-startup","webpack://office-addin-taskpane-react/webpack/startup","webpack://office-addin-taskpane-react/webpack/after-startup"],"sourcesContent":["/*\n * Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.\n * See LICENSE in the project root for license information.\n */\n\n/* global global, Office, self, window */\n\nOffice.onReady(() => {\n // If needed, Office.js is ready to be called\n});\n\n/**\n * Shows a notification when the add-in command is executed.\n * @param event\n */\nfunction action(event: Office.AddinCommands.Event) {\n const message: Office.NotificationMessageDetails = {\n type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage,\n message: \"Performed action.\",\n icon: \"Icon.80x80\",\n persistent: true,\n };\n\n // Show a notification message\n Office.context.mailbox.item.notificationMessages.replaceAsync(\"action\", message);\n\n // Be sure to indicate when the add-in command function is complete\n event.completed();\n}\n\nfunction getGlobal() {\n return typeof self !== \"undefined\"\n ? self\n : typeof window !== \"undefined\"\n ? window\n : typeof global !== \"undefined\"\n ? global\n : undefined;\n}\n\nconst g = getGlobal() as any;\n\n// The add-in command functions need to be available in global scope\ng.action = action;\n","// The require scope\nvar __webpack_require__ = {};\n\n","__webpack_require__.g = (function() {\n\tif (typeof globalThis === 'object') return globalThis;\n\ttry {\n\t\treturn this || new Function('return this')();\n\t} catch (e) {\n\t\tif (typeof window === 'object') return window;\n\t}\n})();","","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = {};\n__webpack_modules__[\"./src/commands/commands.ts\"](0, __webpack_exports__, __webpack_require__);\n",""],"names":["Office","onReady","action","event","message","type","MailboxEnums","ItemNotificationMessageType","InformationalMessage","icon","persistent","context","mailbox","item","notificationMessages","replaceAsync","completed","getGlobal","self","window","global","undefined","g"],"sourceRoot":""}

85
dist/manifest.xml vendored Normal file
View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp">
<Id>9a463859-68ff-41ed-8f96-d418dffb73b3</Id>
<Version>1.0.0.0</Version>
<ProviderName>Contoso</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="cp-press-release-word-plugin"/>
<Description DefaultValue="A template to get started."/>
<IconUrl DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-64.png"/>
<SupportUrl DefaultValue="https://www.contoso.com/help"/>
<AppDomains>
<AppDomain>https://www.contoso.com</AppDomain>
</AppDomains>
<Hosts>
<Host Name="Document"/>
</Hosts>
<DefaultSettings>
<SourceLocation DefaultValue="https://localhost:3000/taskpane.html"/>
</DefaultSettings>
<Permissions>ReadWriteDocument</Permissions>
<VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
<Hosts>
<Host xsi:type="Document">
<DesktopFormFactor>
<GetStarted>
<Title resid="GetStarted.Title"/>
<Description resid="GetStarted.Description"/>
<LearnMoreUrl resid="GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="Commands.Url"/>
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<Group id="CommandsGroup">
<Label resid="CommandsGroup.Label"/>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Control xsi:type="Button" id="TaskpaneButton">
<Label resid="TaskpaneButton.Label"/>
<Supertip>
<Title resid="TaskpaneButton.Label"/>
<Description resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<TaskpaneId>ButtonId1</TaskpaneId>
<SourceLocation resid="Taskpane.Url"/>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/>
<bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GetStarted.Title" DefaultValue="Get started with your sample add-in!"/>
<bt:String id="CommandsGroup.Label" DefaultValue="Commands Group"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show Taskpane"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="GetStarted.Description" DefaultValue="Your sample add-in loaded succesfully. Go to the HOME tab and click the 'Show Taskpane' button to get started."/>
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Click to Show a Taskpane"/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</OfficeApp>

23118
dist/polyfill.js vendored Normal file

File diff suppressed because it is too large Load Diff

1
dist/polyfill.js.map vendored Normal file

File diff suppressed because one or more lines are too long

27
dist/taskpane.html vendored Normal file
View File

@ -0,0 +1,27 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -->
<!-- See LICENSE in the project root for license information -->
<!doctype html>
<html lang="en" data-framework="typescript">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Press-release analyzer</title>
<!-- Office JavaScript API -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script>
<!-- For more information on Fluent UI, visit https://developer.microsoft.com/fluentui#/. -->
<link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/11.0.0/css/fabric.min.css"/>
<!-- Template styles -->
<link href="8d9dfc10165c310961fd.css" rel="stylesheet" type="text/css" />
<script defer src="vendor.js"></script><script defer src="taskpane.js"></script></head>
<body class="ms-font-m ms-Fabric">
<div id="container"></div>
</body>
</html>

115508
dist/taskpane.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/taskpane.js.map vendored Normal file

File diff suppressed because one or more lines are too long

137659
dist/vendor.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/vendor.js.map vendored Normal file

File diff suppressed because one or more lines are too long

85
manifest.xml Normal file
View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0" xmlns:ov="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="TaskPaneApp">
<Id>9a463859-68ff-41ed-8f96-d418dffb73b3</Id>
<Version>1.0.0.0</Version>
<ProviderName>Contoso</ProviderName>
<DefaultLocale>en-US</DefaultLocale>
<DisplayName DefaultValue="cp-press-release-word-plugin"/>
<Description DefaultValue="A template to get started."/>
<IconUrl DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<HighResolutionIconUrl DefaultValue="https://localhost:3000/assets/icon-64.png"/>
<SupportUrl DefaultValue="https://www.contoso.com/help"/>
<AppDomains>
<AppDomain>https://www.contoso.com</AppDomain>
</AppDomains>
<Hosts>
<Host Name="Document"/>
</Hosts>
<DefaultSettings>
<SourceLocation DefaultValue="https://localhost:3000/taskpane.html"/>
</DefaultSettings>
<Permissions>ReadWriteDocument</Permissions>
<VersionOverrides xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides" xsi:type="VersionOverridesV1_0">
<Hosts>
<Host xsi:type="Document">
<DesktopFormFactor>
<GetStarted>
<Title resid="GetStarted.Title"/>
<Description resid="GetStarted.Description"/>
<LearnMoreUrl resid="GetStarted.LearnMoreUrl"/>
</GetStarted>
<FunctionFile resid="Commands.Url"/>
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<OfficeTab id="TabHome">
<Group id="CommandsGroup">
<Label resid="CommandsGroup.Label"/>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Control xsi:type="Button" id="TaskpaneButton">
<Label resid="TaskpaneButton.Label"/>
<Supertip>
<Title resid="TaskpaneButton.Label"/>
<Description resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<TaskpaneId>ButtonId1</TaskpaneId>
<SourceLocation resid="Taskpane.Url"/>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16" DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32" DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80" DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="GetStarted.LearnMoreUrl" DefaultValue="https://go.microsoft.com/fwlink/?LinkId=276812"/>
<bt:Url id="Commands.Url" DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="Taskpane.Url" DefaultValue="https://localhost:3000/taskpane.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GetStarted.Title" DefaultValue="Get started with your sample add-in!"/>
<bt:String id="CommandsGroup.Label" DefaultValue="Commands Group"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show Taskpane"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="GetStarted.Description" DefaultValue="Your sample add-in loaded succesfully. Go to the HOME tab and click the 'Show Taskpane' button to get started."/>
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Click to Show a Taskpane"/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</OfficeApp>

26831
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

77
package.json Normal file
View File

@ -0,0 +1,77 @@
{
"name": "office-addin-taskpane-react",
"version": "0.0.1",
"repository": {
"type": "git",
"url": "https://github.com/OfficeDev/Office-Addin-TaskPane-React.git"
},
"license": "MIT",
"config": {
"app_to_debug": "word",
"app_type_to_debug": "desktop",
"dev_server_port": 3000
},
"scripts": {
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"dev-server": "webpack serve --mode development",
"lint": "office-addin-lint check",
"lint:fix": "office-addin-lint fix",
"prettier": "office-addin-lint prettier",
"start": "office-addin-debugging start manifest.xml",
"start:desktop": "office-addin-debugging start manifest.xml desktop",
"start:web": "office-addin-debugging start manifest.xml web",
"stop": "office-addin-debugging stop manifest.xml",
"validate": "office-addin-manifest validate manifest.xml",
"watch": "webpack --mode development --watch"
},
"dependencies": {
"@fluentui/react": "^8.52.3",
"@tanstack/react-query": "^4.35.0",
"axios": "^1.5.0",
"core-js": "^3.9.1",
"es6-promise": "^4.2.8",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"regenerator-runtime": "^0.13.7"
},
"devDependencies": {
"@babel/core": "^7.13.10",
"@babel/preset-typescript": "^7.13.0",
"@types/office-js": "^1.0.256",
"@types/office-runtime": "^1.0.23",
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"@types/react-hot-loader": "^4.1.1",
"@types/webpack": "^4.4.34",
"@types/webpack-dev-server": "^4.1.0",
"acorn": "^8.5.0",
"babel-loader": "^8.2.2",
"copy-webpack-plugin": "^9.0.1",
"eslint-plugin-office-addins": "^2.1.5",
"eslint-plugin-react": "^7.28.0",
"file-loader": "^6.2.0",
"html-loader": "^4.1.0",
"html-webpack-plugin": "^5.5.0",
"less": "^3.9.0",
"less-loader": "^10.0.1",
"office-addin-cli": "^1.5.5",
"office-addin-debugging": "^5.0.5",
"office-addin-dev-certs": "^1.11.3",
"office-addin-lint": "^2.2.5",
"office-addin-manifest": "^1.12.3",
"office-addin-prettier-config": "^1.2.0",
"os-browserify": "^0.3.0",
"process": "^0.11.10",
"source-map-loader": "^3.0.0",
"ts-loader": "^9.4.1",
"typescript": "^4.3.5",
"webpack": "^5.76.3",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "4.13.1"
},
"prettier": "office-addin-prettier-config",
"browserslist": [
"ie 11"
]
}

View File

@ -0,0 +1,18 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT License. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!-- Office JavaScript API -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script>
</head>
<body>
</body>
</html>

44
src/commands/commands.ts Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
* See LICENSE in the project root for license information.
*/
/* global global, Office, self, window */
Office.onReady(() => {
// If needed, Office.js is ready to be called
});
/**
* Shows a notification when the add-in command is executed.
* @param event
*/
function action(event: Office.AddinCommands.Event) {
const message: Office.NotificationMessageDetails = {
type: Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage,
message: "Performed action.",
icon: "Icon.80x80",
persistent: true,
};
// Show a notification message
Office.context.mailbox.item.notificationMessages.replaceAsync("action", message);
// Be sure to indicate when the add-in command function is complete
event.completed();
}
function getGlobal() {
return typeof self !== "undefined"
? self
: typeof window !== "undefined"
? window
: typeof global !== "undefined"
? global
: undefined;
}
const g = getGlobal() as any;
// The add-in command functions need to be available in global scope
g.action = action;

View File

@ -0,0 +1,57 @@
import { useMutation } from "@tanstack/react-query";
import { MutationConfig, queryClient } from "../../lib/react-query";
import { axios } from "../../lib/axios";
import { TextDescriptor } from "./types";
import { PROCESS_API_URL } from "./urlKeys";
import { QUERY_KEY_PROCESSES } from "./queryKeys";
export type CreateProcessDTO = Partial<Pick<TextDescriptor, "text">> & {
files?: File[];
};
export type CreateProcessResponse = {
id: string;
};
export const createProcess = (data: CreateProcessDTO): Promise<CreateProcessResponse> => {
const isForm = data.files?.length !== 0;
let inputData: any;
if (isForm) {
inputData = new FormData();
if (data.text) {
inputData.append("text", `${data.text}`);
}
data.files?.forEach((file, index) => {
inputData.append(`file_${index + 1}`, file);
});
} else {
inputData = {
text: data.text,
};
}
return axios.post(`${PROCESS_API_URL}/`, inputData, {
headers: isForm
? {
"Content-Type": "multipart/form-data",
}
: {},
});
};
type UseCreateProcessOptions = {
config?: MutationConfig<typeof createProcess>;
};
export const useCreateProcess = ({ config }: UseCreateProcessOptions = {}) => {
return useMutation({
onMutate: async () => {
await queryClient.cancelQueries([QUERY_KEY_PROCESSES]);
},
...config,
mutationFn: createProcess,
});
};

View File

@ -0,0 +1,29 @@
import { useQuery } from "@tanstack/react-query";
import { axios } from "../../lib/axios";
import { ExtractFnReturnType, QueryConfig } from "../../lib/react-query";
import { ProcessDescriptor } from "./types";
import { PROCESS_API_URL } from "./urlKeys";
import { QUERY_KEY_PROCESSES } from "./queryKeys";
export type GetProcessResponse = ProcessDescriptor;
export const getProcess = ({ processId }: { processId: string }): Promise<GetProcessResponse> => {
return axios.get(`${PROCESS_API_URL}/${processId}`);
};
type QueryFnType = typeof getProcess;
type UseProcessOptions = {
processId: string;
config?: QueryConfig<QueryFnType>;
};
export const useProcess = ({ processId, config }: UseProcessOptions) => {
return useQuery<ExtractFnReturnType<QueryFnType>>({
...config,
queryKey: [QUERY_KEY_PROCESSES, processId],
queryFn: async () => {
return await getProcess({ processId });
},
});
};

View File

@ -0,0 +1,34 @@
import { useQuery } from "@tanstack/react-query";
import { axios } from "../../lib/axios";
import { ExtractFnReturnType, QueryConfig } from "../../lib/react-query";
import { ScoreType, TextDescriptor } from "./types";
import { TEXT_API_URL, TEXT_PARAM } from "./urlKeys";
import { QUERY_KEY_TEXTS } from "./queryKeys";
export type GetTextResponse = TextDescriptor;
export const getText = ({ textId, type = "bert" }: { textId: number; type: ScoreType }): Promise<GetTextResponse> => {
return axios.get(TEXT_API_URL.replace(`:${TEXT_PARAM}`, String(textId)), {
params: {
type,
},
});
};
type QueryFnType = typeof getText;
type UseTextOptions = {
textId: number;
type: ScoreType;
config?: QueryConfig<QueryFnType>;
};
export const useText = ({ textId, type, config }: UseTextOptions) => {
return useQuery<ExtractFnReturnType<QueryFnType>>({
...config,
queryKey: [QUERY_KEY_TEXTS, textId, type],
queryFn: async () => {
return await getText({ textId, type });
},
});
};

View File

@ -0,0 +1,4 @@
export * from './types';
export * from './createProcess';
export * from './getProcess';
export * from './getText';

View File

@ -0,0 +1,2 @@
export const QUERY_KEY_PROCESSES = "processes";
export const QUERY_KEY_TEXTS = "texts";

View File

@ -0,0 +1,38 @@
export type DetailFeatures = [answer: string, metric: number, texts: string[]];
export type DetailDescriptor = {
text: string;
features: DetailFeatures;
};
export type ScoreType = "bert" | "f" | "nearest";
export type ScoreDescriptor = {
[key in ScoreType]: {
answer: string;
metric?: number;
};
};
export type TextDescriptor = {
id: number;
file_name: string;
description:
| {
[key in ScoreType]?: {
file?: string;
pdf?: string;
text: string | DetailDescriptor[];
};
}
| null;
text: string;
summary: string;
score: ScoreDescriptor;
};
export type ProcessDescriptor = {
texts: TextDescriptor[];
current: number;
total: number;
};

View File

@ -0,0 +1,5 @@
export const PROCESS_API_URL = "/process";
export const PROCESS_PARAM = "processId";
export const TEXT_PARAM = "textId";
export const TEXT_API_URL = `/process/describe/:${TEXT_PARAM}`;

View File

@ -0,0 +1,198 @@
import * as React from "react";
import { DefaultButton } from "@fluentui/react";
import Header from "./Header";
import { FC, PropsWithChildren, useCallback, useEffect, useRef } from "react";
import { ScoreType, useCreateProcess, useProcess, useText } from "../api/process";
import { useSingleTimeout } from "../hooks/useSingleTimeout";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
/* global Word, require */
const processFunction = async (
context: Word.RequestContext,
search_text: string,
comment_text: string,
score: number
) => {
search_text.replace("\u0005", "");
try {
const range = context.document.body
.search(search_text.slice(0, 255).split("\\").join(""), {
ignorePunct: true,
ignoreSpace: true,
})
.getFirstOrNullObject();
await context.sync();
if (!range.isNullObject) {
range.insertComment(comment_text + "\n" + "Точность: " + score.toFixed(2));
}
} catch (e) {
//
}
// return context.document.body
// .search(search_text.slice(0, 255).split("\\").join(""), {
// ignorePunct: true,
// ignoreSpace: true,
// })
// .getFirst()
// .insertComment(comment_text + "\n" + "Точность: " + score.toFixed(2));
};
const typeKey: ScoreType = "bert";
export const getEntriesFromDescription = (description: string = "") => {
const matches = Array.from(description.matchAll(/<span[^>]+>(.*?)<\/span>/gi));
const array = matches
.map((match) => {
const entry = match[0];
const text = match[1];
const value = Number(Array.from(entry.matchAll(/data-value=\\?"?([.\d]+)\\?"?/gi))[0]?.[1]) || 0;
return {
text,
value,
};
})
.filter((i) => i.value >= 0.01);
return [...Array.from(new Map(array.map((item) => [item["text"], item])).values())];
};
export interface AppProps {
title: string;
isOfficeInitialized: boolean;
}
export const PROCESS_POLLING_MS = 2000;
export const App: FC<PropsWithChildren<AppProps>> = () => {
const {
data: createProcessResponse,
mutateAsync: createProcess,
isLoading: createProcessLoading,
} = useCreateProcess();
const processId = createProcessResponse?.id;
const {
data: process,
isFetching: processFetching,
refetch: refetchProcess,
} = useProcess({
processId: processId || "",
config: {
enabled: !!processId,
},
});
const timeout = useSingleTimeout();
useEffect(() => {
if (processId) {
const startPolling = () => {
timeout.set(async () => {
const { data: process } = await refetchProcess();
if (process && process.current < process.total) {
startPolling();
}
}, PROCESS_POLLING_MS);
};
if (processId) {
startPolling();
}
}
}, [processId, refetchProcess, timeout]);
// const textId = process?.current === process?.total ? process?.texts[0].id : undefined;
const textId = 3184;
const {
data: textEntity,
isFetching: textFetching,
refetch: refetchText,
} = useText({
textId: textId || 0,
type: typeKey,
config: {
enabled: !!textId,
},
});
const answer = textEntity?.score?.[typeKey]?.answer;
const metric = textEntity?.score?.[typeKey]?.metric;
const summary = textEntity?.summary;
const initRef = useRef(false);
useEffect(() => {
if (!textEntity || initRef.current) {
return;
}
initRef.current = true;
Word.run(async (context) => {
const entries = getEntriesFromDescription((textEntity?.description?.[typeKey]?.text as string) || "");
for (const entry of entries) {
await processFunction(context, entry.text, "", entry.value);
}
});
}, [textEntity]);
const isLoading =
createProcessLoading ||
!!processId ||
processFetching ||
!!(process && process.current < process.total) ||
textFetching;
const onClick = useCallback(() => {
Word.run(function (context) {
// Insert your code here. For example:
const documentBody = context.document.body;
context.load(documentBody);
return context.sync().then(async () => {
await refetchText();
// const text = documentBody.text;
// await createProcess({
// text,
// });
});
});
}, []);
return (
<div className="ms-welcome">
<Header message="Анализ текстовых пресс-релизов" />
<main className="ms-welcome__main">
<p>
Позволяет оценить кредитный рейтинг компании на основе пресс-релиза с выделением в тексте ключевых фраз с
использованием различных методов.
</p>
<DefaultButton className="ms-welcome__action" iconProps={{ iconName: "ChevronRight" }} onClick={onClick}>
Отправить
</DefaultButton>
{isLoading && !textEntity && <p>Обработка...</p>}
{textEntity && (
<>
<h3>Результат оценки</h3>
<p>
Оценочный рейтинг: {answer} <br />
{metric && `Точность: ${metric.toFixed(2)}`}
</p>
<h4>Краткое содержание</h4>
<p>{summary}</p>
</>
)}
</main>
</div>
);
};

View File

@ -0,0 +1,17 @@
import * as React from "react";
export interface HeaderProps {
message: string;
}
export default class Header extends React.Component<HeaderProps> {
render() {
const { message } = this.props;
return (
<section className="ms-welcome__header ms-bgColor-neutralLighter ms-u-fadeIn500">
<h1 className="ms-fontSize-su ms-fontWeight-light ms-fontColor-neutralPrimary">{message}</h1>
</section>
);
}
}

View File

@ -0,0 +1,32 @@
import * as React from "react";
export interface HeroListItem {
icon: string;
primaryText: string;
}
export interface HeroListProps {
message: string;
items: HeroListItem[];
children: any;
}
export default class HeroList extends React.Component<HeroListProps> {
render() {
const { children, items, message } = this.props;
const listItems = items.map((item, index) => (
<li className="ms-ListItem" key={index}>
<i className={`ms-Icon ms-Icon--${item.icon}`}></i>
<span className="ms-font-m ms-fontColor-neutralPrimary">{item.primaryText}</span>
</li>
));
return (
<main className="ms-welcome__main">
<h2 className="ms-font-xl ms-fontWeight-semilight ms-fontColor-neutralPrimary ms-u-slideUpIn20">{message}</h2>
<ul className="ms-List ms-welcome__features ms-u-slideUpIn10">{listItems}</ul>
{children}
</main>
);
}
}

View File

@ -0,0 +1,22 @@
import * as React from "react";
import { Spinner, SpinnerSize } from "@fluentui/react";
export interface ProgressProps {
logo: string;
message: string;
title: string;
}
export default class Progress extends React.Component<ProgressProps> {
render() {
const { logo, message, title } = this.props;
return (
<section className="ms-welcome__progress ms-u-fadeIn500">
<img width="90" height="90" src={logo} alt={title} title={title} />
<h1 className="ms-fontSize-su ms-fontWeight-light ms-fontColor-neutralPrimary">{title}</h1>
<Spinner size={SpinnerSize.large} label={message} />
</section>
);
}
}

8
src/taskpane/config.ts Normal file
View File

@ -0,0 +1,8 @@
// export const BACKEND_URL = 'http://192.168.83.181:8000';
// export const BACKEND_URL = 'http://192.168.22.4:8000';
// export const BACKEND_URL = 'https://ed68-77-234-219-9.ngrok-free.app';
// export const BACKEND_URL = 'https://16c2-77-234-219-9.ngrok-free.app';
export const BACKEND_URL = "https://4810-176-59-122-187.ngrok-free.app";
export const BACKEND_MEDIA_PORT = "8000";
export const API_URL = BACKEND_URL + "/api";

View File

@ -0,0 +1,13 @@
import { useRef } from "react";
/**
* Единожды вызывает функцию и сохраняет ее значение в реф
* @param factory - функция, создающая значение рефа
*/
export function useFactoryRef<T>(factory: () => T): T {
const ref = useRef<T | null>(null);
if (!ref.current) {
ref.current = factory();
}
return ref.current;
}

View File

@ -0,0 +1,6 @@
import { SingleTimeoutManager } from "../utils/SingleTimeoutManager";
import { useFactoryRef } from "./useFactoryRef";
export const useSingleTimeout = () => {
return useFactoryRef(() => new SingleTimeoutManager());
};

41
src/taskpane/index.tsx Normal file
View File

@ -0,0 +1,41 @@
import { App } from "./components/App";
import { AppContainer } from "react-hot-loader";
import { initializeIcons } from "@fluentui/font-icons-mdl2";
import { ThemeProvider } from "@fluentui/react";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { ReactQueryProvider } from "./providers";
/* global document, Office, module, require */
initializeIcons();
let isOfficeInitialized = false;
const title = "Press-release analyzer";
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<ThemeProvider>
<ReactQueryProvider>
<Component title={title} isOfficeInitialized={isOfficeInitialized} />
</ReactQueryProvider>
</ThemeProvider>
</AppContainer>,
document.getElementById("container")
);
};
/* Render application after Office initializes */
Office.onReady(() => {
isOfficeInitialized = true;
render(App);
});
if ((module as any).hot) {
(module as any).hot.accept("./components/App", () => {
const NextApp = require("./components/App").default;
render(NextApp);
});
}

10
src/taskpane/lib/axios.ts Normal file
View File

@ -0,0 +1,10 @@
import Axios from "axios";
import { API_URL } from "../config";
export const axios = Axios.create({
baseURL: API_URL,
});
axios.interceptors.response.use((response) => {
return response.data;
});

View File

@ -0,0 +1,38 @@
import {
QueryClient,
UseQueryOptions,
UseMutationOptions,
DefaultOptions,
UseInfiniteQueryOptions,
} from "@tanstack/react-query";
import { AxiosError } from "axios";
import { ExtractFnReturnType } from "../utils/types";
const queryConfig: DefaultOptions = {
queries: {
useErrorBoundary: false,
refetchOnWindowFocus: false,
retry: false,
},
};
export const queryClient = new QueryClient({ defaultOptions: queryConfig });
export type QueryConfig<QueryFnType extends (...args: any) => any> = Omit<
UseQueryOptions<ExtractFnReturnType<QueryFnType>>,
"queryKey" | "queryFn"
>;
export type InfiniteQueryConfig<QueryFnType extends (...args: any) => any> = Omit<
UseInfiniteQueryOptions<ExtractFnReturnType<QueryFnType>>,
"queryKey" | "queryFn"
>;
export type MutationConfig<MutationFnType extends (...args: any) => any> = UseMutationOptions<
ExtractFnReturnType<MutationFnType>,
AxiosError,
Parameters<MutationFnType>[0],
any
>;
export type { ExtractFnReturnType };

View File

@ -0,0 +1 @@
export * from './react-query';

View File

@ -0,0 +1,9 @@
import React from "react";
import { QueryClientProvider } from "@tanstack/react-query";
import { ReactFCC } from "../utils/ReactFCC";
import { queryClient } from "../lib/react-query";
export const ReactQueryProvider: ReactFCC = (props) => {
// eslint-disable-next-line react/prop-types
return <QueryClientProvider client={queryClient}>{props.children}</QueryClientProvider>;
};

80
src/taskpane/taskpane.css Normal file
View File

@ -0,0 +1,80 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
* See LICENSE in the project root for license information.
*/
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
ul {
margin: 0;
padding: 0;
}
.ms-welcome__header {
padding: 20px;
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
align-items: center;
}
.ms-welcome__main {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-flex-wrap: nowrap;
flex-wrap: nowrap;
/*-webkit-align-items: center;*/
/*align-items: center;*/
-webkit-flex: 1 0 0;
flex: 1 0 0;
padding: 10px 20px;
}
/* */
/* .ms-welcome__main > h2 {*/
/* width: 100%;*/
/* text-align: center;*/
/* }*/
/* */
/* .ms-welcome__features {*/
/* list-style-type: none;*/
/* margin-top: 20px;*/
/* }*/
/* */
/* .ms-welcome__features.ms-List .ms-ListItem {*/
/* padding-bottom: 20px;*/
/* display: -webkit-flex;*/
/* display: flex;*/
/* }*/
/* */
/* .ms-welcome__features.ms-List .ms-ListItem > .ms-Icon {*/
/* margin-right: 10px;*/
/* }*/
/* */
/* .ms-welcome__action.ms-Button--hero {*/
/* margin-top: 30px;*/
/* }*/
/* */
/*.ms-Button.ms-Button--hero .ms-Button-label {*/
/* color: #0078d7;*/
/*}*/
/*.ms-Button.ms-Button--hero:hover .ms-Button-label,*/
/*.ms-Button.ms-Button--hero:focus .ms-Button-label{*/
/* color: #005a9e;*/
/* cursor: pointer;*/
/*}*/
/*b {*/
/* font-weight: bold;*/
/*}*/

View File

@ -0,0 +1,27 @@
<!-- Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -->
<!-- See LICENSE in the project root for license information -->
<!doctype html>
<html lang="en" data-framework="typescript">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Press-release analyzer</title>
<!-- Office JavaScript API -->
<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js"></script>
<!-- For more information on Fluent UI, visit https://developer.microsoft.com/fluentui#/. -->
<link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/11.0.0/css/fabric.min.css"/>
<!-- Template styles -->
<link href="taskpane.css" rel="stylesheet" type="text/css" />
</head>
<body class="ms-font-m ms-Fabric">
<div id="container"></div>
</body>
</html>

View File

@ -0,0 +1,3 @@
import React, { PropsWithChildren } from "react";
export type ReactFCC<T = unknown> = React.FC<PropsWithChildren<T>>;

View File

@ -0,0 +1,26 @@
export class SingleTimeoutManager {
timeout: NodeJS.Timeout | null = null;
public set(cb: null | (() => void), time?: number) {
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.timeout = null;
cb && cb();
}, time);
}
public setDelay(time: number) {
return this.set(null, time);
}
public clear() {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
}
public active() {
return this.timeout;
}
}

View File

@ -0,0 +1,45 @@
import React, { JSX } from "react";
import { PromiseValue } from "type-fest";
export type Optional<T> = T | null | undefined;
export type Extends<Self extends object, Base extends object> = Omit<Base, keyof Self> & Self;
export type IntrinsicPropsWithoutRef<E extends keyof JSX.IntrinsicElements> = React.PropsWithoutRef<
JSX.IntrinsicElements[E]
>;
export type ExtractArray<T> = T extends (infer U)[] ? U : T;
export type AnchorPropsWithoutRef = IntrinsicPropsWithoutRef<"a">;
export type DivPropsWithoutRef = IntrinsicPropsWithoutRef<"div">;
export type PPropsWithoutRef = IntrinsicPropsWithoutRef<"p">;
export type FooterPropsWithoutRef = IntrinsicPropsWithoutRef<"footer">;
export type ImgPropsWithoutRef = IntrinsicPropsWithoutRef<"img">;
export type ButtonPropsWithoutRef = IntrinsicPropsWithoutRef<"button">;
export type InputPropsWithoutRef = IntrinsicPropsWithoutRef<"input">;
export type SelectPropsWithoutRef = IntrinsicPropsWithoutRef<"select">;
export type UListPropsWithoutRef = IntrinsicPropsWithoutRef<"ul">;
export type LiPropsWithoutRef = IntrinsicPropsWithoutRef<"li">;
export type SvgPropsWithoutRef = IntrinsicPropsWithoutRef<"svg">;
export type PolyExtends<ComponentType extends React.ElementType, Self extends object, Base extends object> = {
/**
* Базовый компонент
*
* @type React.ElementType
*/
component?: ComponentType;
} & Extends<Self, Base>;
export type AnyObject = {
[key: number]: any;
[key: string]: any;
};
export type ExtractFnReturnType<FnType extends (...args: any) => any> = PromiseValue<ReturnType<FnType>>;
export type Pagination = {
offset?: number;
limit?: number;
};

33
tsconfig.json Normal file
View File

@ -0,0 +1,33 @@
{
"compilerOptions": {
"allowUnusedLabels": false,
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "CommonJS",
"moduleResolution": "node",
"noImplicitReturns": true,
"noUnusedParameters": true,
"outDir": "dist",
"removeComments": false,
"sourceMap": true,
"target": "es5",
"lib": [
"es7",
"dom"
],
"pretty": true,
"typeRoots": [
"node_modules/@types"
]
},
"exclude": [
"node_modules"
],
"compileOnSave": false,
"buildOnSave": false,
"ts-node": {
"files": true
}
}

111
webpack.config.js Normal file
View File

@ -0,0 +1,111 @@
/* eslint-disable no-undef */
const devCerts = require("office-addin-dev-certs");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");
const urlDev = "https://localhost:3000/";
const urlProd = "https://www.contoso.com/"; // CHANGE THIS TO YOUR PRODUCTION DEPLOYMENT LOCATION
async function getHttpsOptions() {
const httpsOptions = await devCerts.getHttpsServerOptions();
return { ca: httpsOptions.ca, key: httpsOptions.key, cert: httpsOptions.cert };
}
module.exports = async (env, options) => {
const dev = options.mode === "development";
const config = {
devtool: "source-map",
entry: {
polyfill: ["core-js/stable", "regenerator-runtime/runtime"],
vendor: ["react", "react-dom", "core-js", "@fluentui/react"],
taskpane: ["react-hot-loader/patch", "./src/taskpane/index.tsx", "./src/taskpane/taskpane.html"],
commands: "./src/commands/commands.ts",
},
output: {
clean: true,
},
resolve: {
extensions: [".ts", ".tsx", ".html", ".js"],
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-typescript"],
},
},
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: ["react-hot-loader/webpack", "ts-loader"],
},
{
test: /\.html$/,
exclude: /node_modules/,
use: "html-loader",
},
{
test: /\.(png|jpg|jpeg|gif|ico)$/,
type: "asset/resource",
generator: {
filename: "assets/[name][ext][query]",
},
},
],
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: "assets/*",
to: "assets/[name][ext][query]",
},
{
from: "manifest*.xml",
to: "[name]" + "[ext]",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
}
},
},
],
}),
new HtmlWebpackPlugin({
filename: "taskpane.html",
template: "./src/taskpane/taskpane.html",
chunks: ["taskpane", "vendor", "polyfills"],
}),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["commands"],
}),
new webpack.ProvidePlugin({
Promise: ["es6-promise", "Promise"],
}),
],
devServer: {
hot: true,
headers: {
"Access-Control-Allow-Origin": "*",
},
server: {
type: "https",
options: env.WEBPACK_BUILD || options.https !== undefined ? options.https : await getHttpsOptions(),
},
port: process.env.npm_package_config_dev_server_port || 3000,
},
};
return config;
};