нагенерено

This commit is contained in:
gorbenko.pavel
2026-07-28 17:53:59 +05:00
parent 67a732f7b7
commit b0280281fb
30 changed files with 21097 additions and 0 deletions
+321
View File
@@ -0,0 +1,321 @@
require('@rushstack/eslint-config/patch/modern-module-resolution');
module.exports = {
extends: ['@microsoft/eslint-config-spfx/lib/profiles/react'],
parserOptions: { tsconfigRootDir: __dirname },
overrides: [
{
files: ['*.ts', '*.tsx'],
parser: '@typescript-eslint/parser',
'parserOptions': {
'project': './tsconfig.json',
'ecmaVersion': 2018,
'sourceType': 'module'
},
rules: {
// Prevent usage of the JavaScript null value, while allowing code to access existing APIs that may require null. https://www.npmjs.com/package/@rushstack/eslint-plugin
'@rushstack/no-new-null': 1,
// Require Jest module mocking APIs to be called before any other statements in their code block. https://www.npmjs.com/package/@rushstack/eslint-plugin
'@rushstack/hoist-jest-mock': 1,
// Require chunk names for dynamic imports in SPFx projects. https://www.npmjs.com/package/@rushstack/eslint-plugin
'@rushstack/import-requires-chunk-name': 1,
// Ensure that React components rendered with ReactDOM.render() are unmounted with ReactDOM.unmountComponentAtNode(). https://www.npmjs.com/package/@rushstack/eslint-plugin
'@rushstack/pair-react-dom-render-unmount': 1,
// Require regular expressions to be constructed from string constants rather than dynamically building strings at runtime. https://www.npmjs.com/package/@rushstack/eslint-plugin-security
'@rushstack/security/no-unsafe-regexp': 1,
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/adjacent-overload-signatures': 1,
// RATIONALE: Code is more readable when the type of every variable is immediately obvious.
// Even if the compiler may be able to infer a type, this inference will be unavailable
// to a person who is reviewing a GitHub diff. This rule makes writing code harder,
// but writing code is a much less important activity than reading it.
//
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/explicit-function-return-type': [
1,
{
'allowExpressions': true,
'allowTypedFunctionExpressions': true,
'allowHigherOrderFunctions': false
}
],
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
// Rationale to disable: although this is a recommended rule, it is up to dev to select coding style.
// Set to 1 (warning) or 2 (error) to enable.
'@typescript-eslint/explicit-member-accessibility': 0,
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/no-array-constructor': 1,
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
//
// RATIONALE: The "any" keyword disables static type checking, the main benefit of using TypeScript.
// This rule should be suppressed only in very special cases such as JSON.stringify()
// where the type really can be anything. Even if the type is flexible, another type
// may be more appropriate such as "unknown", "{}", or "Record<k,V>".
'@typescript-eslint/no-explicit-any': 1,
// RATIONALE: The #1 rule of promises is that every promise chain must be terminated by a catch()
// handler. Thus wherever a Promise arises, the code must either append a catch handler,
// or else return the object to a caller (who assumes this responsibility). Unterminated
// promise chains are a serious issue. Besides causing errors to be silently ignored,
// they can also cause a NodeJS process to terminate unexpectedly.
'@typescript-eslint/no-floating-promises': 2,
// RATIONALE: Catches a common coding mistake.
'@typescript-eslint/no-for-in-array': 2,
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/no-misused-new': 2,
// RATIONALE: The "namespace" keyword is not recommended for organizing code because JavaScript lacks
// a "using" statement to traverse namespaces. Nested namespaces prevent certain bundler
// optimizations. If you are declaring loose functions/variables, it's better to make them
// static members of a class, since classes support property getters and their private
// members are accessible by unit tests. Also, the exercise of choosing a meaningful
// class name tends to produce more discoverable APIs: for example, search+replacing
// the function "reverse()" is likely to return many false matches, whereas if we always
// write "Text.reverse()" is more unique. For large scale organization, it's recommended
// to decompose your code into separate NPM packages, which ensures that component
// dependencies are tracked more conscientiously.
//
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/no-namespace': [
1,
{
'allowDeclarations': false,
'allowDefinitionFiles': false
}
],
// RATIONALE: Parameter properties provide a shorthand such as "constructor(public title: string)"
// that avoids the effort of declaring "title" as a field. This TypeScript feature makes
// code easier to write, but arguably sacrifices readability: In the notes for
// "@typescript-eslint/member-ordering" we pointed out that fields are central to
// a class's design, so we wouldn't want to bury them in a constructor signature
// just to save some typing.
//
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
// Set to 1 (warning) or 2 (error) to enable the rule
'@typescript-eslint/parameter-properties': 0,
// RATIONALE: When left in shipping code, unused variables often indicate a mistake. Dead code
// may impact performance.
//
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/no-unused-vars': [
1,
{
'vars': 'all',
// Unused function arguments often indicate a mistake in JavaScript code. However in TypeScript code,
// the compiler catches most of those mistakes, and unused arguments are fairly common for type signatures
// that are overriding a base class method or implementing an interface.
'args': 'none'
}
],
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/no-use-before-define': [
2,
{
'functions': false,
'classes': true,
'variables': true,
'enums': true,
'typedefs': true
}
],
// Disallows require statements except in import statements.
// In other words, the use of forms such as var foo = require("foo") are banned. Instead use ES6 style imports or import foo = require("foo") imports.
'@typescript-eslint/no-var-requires': 'error',
// RATIONALE: The "module" keyword is deprecated except when describing legacy libraries.
//
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'@typescript-eslint/prefer-namespace-keyword': 1,
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
// Rationale to disable: it's up to developer to decide if he wants to add type annotations
// Set to 1 (warning) or 2 (error) to enable the rule
'@typescript-eslint/no-inferrable-types': 0,
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
// Rationale to disable: declaration of empty interfaces may be helpful for generic types scenarios
'@typescript-eslint/no-empty-interface': 0,
// RATIONALE: This rule warns if setters are defined without getters, which is probably a mistake.
'accessor-pairs': 1,
// RATIONALE: In TypeScript, if you write x["y"] instead of x.y, it disables type checking.
'dot-notation': [
1,
{
'allowPattern': '^_'
}
],
// RATIONALE: Catches code that is likely to be incorrect
'eqeqeq': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'for-direction': 1,
// RATIONALE: Catches a common coding mistake.
'guard-for-in': 2,
// RATIONALE: If you have more than 2,000 lines in a single source file, it's probably time
// to split up your code.
'max-lines': ['warn', { max: 2000 }],
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-async-promise-executor': 2,
// RATIONALE: Deprecated language feature.
'no-caller': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-compare-neg-zero': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-cond-assign': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-constant-condition': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-control-regex': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-debugger': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-delete-var': 2,
// RATIONALE: Catches code that is likely to be incorrect
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-duplicate-case': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-empty': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-empty-character-class': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-empty-pattern': 1,
// RATIONALE: Eval is a security concern and a performance concern.
'no-eval': 1,
// RATIONALE: Catches code that is likely to be incorrect
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-ex-assign': 2,
// RATIONALE: System types are global and should not be tampered with in a scalable code base.
// If two different libraries (or two versions of the same library) both try to modify
// a type, only one of them can win. Polyfills are acceptable because they implement
// a standardized interoperable contract, but polyfills are generally coded in plain
// JavaScript.
'no-extend-native': 1,
// Disallow unnecessary labels
'no-extra-label': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-fallthrough': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-func-assign': 1,
// RATIONALE: Catches a common coding mistake.
'no-implied-eval': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-invalid-regexp': 2,
// RATIONALE: Catches a common coding mistake.
'no-label-var': 2,
// RATIONALE: Eliminates redundant code.
'no-lone-blocks': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-misleading-character-class': 2,
// RATIONALE: Catches a common coding mistake.
'no-multi-str': 2,
// RATIONALE: It's generally a bad practice to call "new Thing()" without assigning the result to
// a variable. Either it's part of an awkward expression like "(new Thing()).doSomething()",
// or else implies that the constructor is doing nontrivial computations, which is often
// a poor class design.
'no-new': 1,
// RATIONALE: Obsolete language feature that is deprecated.
'no-new-func': 2,
// RATIONALE: Obsolete language feature that is deprecated.
'no-new-object': 2,
// RATIONALE: Obsolete notation.
'no-new-wrappers': 1,
// RATIONALE: Catches code that is likely to be incorrect
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-octal': 2,
// RATIONALE: Catches code that is likely to be incorrect
'no-octal-escape': 2,
// RATIONALE: Catches code that is likely to be incorrect
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-regex-spaces': 2,
// RATIONALE: Catches a common coding mistake.
'no-return-assign': 2,
// RATIONALE: Security risk.
'no-script-url': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-self-assign': 2,
// RATIONALE: Catches a common coding mistake.
'no-self-compare': 2,
// RATIONALE: This avoids statements such as "while (a = next(), a && a.length);" that use
// commas to create compound expressions. In general code is more readable if each
// step is split onto a separate line. This also makes it easier to set breakpoints
// in the debugger.
'no-sequences': 1,
// RATIONALE: Catches code that is likely to be incorrect
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-shadow-restricted-names': 2,
// RATIONALE: Obsolete language feature that is deprecated.
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-sparse-arrays': 2,
// RATIONALE: Although in theory JavaScript allows any possible data type to be thrown as an exception,
// such flexibility adds pointless complexity, by requiring every catch block to test
// the type of the object that it receives. Whereas if catch blocks can always assume
// that their object implements the "Error" contract, then the code is simpler, and
// we generally get useful additional information like a call stack.
'no-throw-literal': 2,
// RATIONALE: Catches a common coding mistake.
'no-unmodified-loop-condition': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-unsafe-finally': 2,
// RATIONALE: Catches a common coding mistake.
'no-unused-expressions': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-unused-labels': 1,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-useless-catch': 1,
// RATIONALE: Avoids a potential performance problem.
'no-useless-concat': 1,
// RATIONALE: The "var" keyword is deprecated because of its confusing "hoisting" behavior.
// Always use "let" or "const" instead.
//
// STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json
'no-var': 2,
// RATIONALE: Generally not needed in modern code.
'no-void': 1,
// RATIONALE: Obsolete language feature that is deprecated.
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'no-with': 2,
// RATIONALE: Makes logic easier to understand, since constants always have a known value
// @typescript-eslint\eslint-plugin\dist\configs\eslint-recommended.js
'prefer-const': 1,
// RATIONALE: Catches a common coding mistake where "resolve" and "reject" are confused.
'promise/param-names': 2,
// RATIONALE: Catches code that is likely to be incorrect
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'require-atomic-updates': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'require-yield': 1,
// "Use strict" is redundant when using the TypeScript compiler.
'strict': [
2,
'never'
],
// RATIONALE: Catches code that is likely to be incorrect
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
'use-isnan': 2,
// STANDARDIZED BY: eslint\conf\eslint-recommended.js
// Set to 1 (warning) or 2 (error) to enable.
// Rationale to disable: !!{}
'no-extra-boolean-cast': 0,
// ====================================================================
// @microsoft/eslint-plugin-spfx
// ====================================================================
'@microsoft/spfx/no-require-ensure': 2,
}
},
{
// For unit tests, we can be a little bit less strict. The settings below revise the
// defaults specified in the extended configurations, as well as above.
files: [
// Test files
'*.test.ts',
'*.test.tsx',
'*.spec.ts',
'*.spec.tsx',
// Facebook convention
'**/__mocks__/*.ts',
'**/__mocks__/*.tsx',
'**/__tests__/*.ts',
'**/__tests__/*.tsx',
// Microsoft convention
'**/test/*.ts',
'**/test/*.tsx'
],
rules: {}
}
]
};
+7
View File
@@ -0,0 +1,7 @@
node_modules/
lib/
dist/
temp/
*.sppkg
.heft/
sharepoint/solution/
+80
View File
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="d95a388c-277d-4d79-9d16-2aa5741f7e12" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$/.." value="main" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." />
</component>
<component name="ProjectColorInfo">{
&quot;associatedIndex&quot;: 8
}</component>
<component name="ProjectId" id="3H7sXhlmo3hJbwt19x7HPeUySi5" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"ModuleVcsDetector.initialDetectionPerformed": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
"codeWithMe.voiceChat.enabledByDefault": "false",
"git-widget-placeholder": "trynode22",
"ignore.virus.scanning.warn.message": "true",
"javascript.preferred.runtime.type.id": "node",
"node.js.detected.package.eslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"ts.external.directory.path": "C:\\work\\git\\tnsu-approval-route\\frontend\\node_modules\\typescript\\lib"
}
}]]></component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-js-predefined-d6986cc7102b-4abd2a77f808-JavaScript-WS-262.8665.259" />
</set>
</attachedChunks>
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="d95a388c-277d-4d79-9d16-2aa5741f7e12" name="Changes" comment="" />
<created>1785230487130</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1785230487130</updated>
<workItem from="1785230488187" duration="3692000" />
<workItem from="1785238689901" duration="1057000" />
</task>
<task id="LOCAL-00001" summary="поправлены все ошибки">
<option name="closed" value="true" />
<created>1785236629458</created>
<option name="number" value="00001" />
<option name="presentableId" value="LOCAL-00001" />
<option name="project" value="LOCAL" />
<updated>1785236629459</updated>
</task>
<option name="localTasksCounter" value="2" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="3" />
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="поправлены все ошибки" />
<option name="LAST_COMMIT_MESSAGE" value="поправлены все ошибки" />
</component>
</project>
+22
View File
@@ -0,0 +1,22 @@
# Ignore everything by default
**
# Use negative patterns to bring back the specific things we want to publish
!/bin/**
!/dist/**
!/EULA/**
!/lib/**
!ThirdPartyNotice.txt
# Ignore certain files in the above folders
/dist/*.stats.*
/dist/**/*.js.map
/lib/**/*.js.map
/lib/**/test/**
# NOTE: These don't need to be specified, because NPM includes them automatically.
#
# package.json
# README (and its variants)
# CHANGELOG (and its variants)
# LICENSE / LICENCE
+23
View File
@@ -0,0 +1,23 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Hosted workbench",
"type": "msedge",
"request": "launch",
"url": "https://{tenantDomain}/_layouts/workbench.aspx",
"webRoot": "${workspaceRoot}",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///.././src/*": "${webRoot}/src/*",
"webpack:///../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../src/*": "${webRoot}/src/*",
"webpack:///../../../../../src/*": "${webRoot}/src/*"
},
"runtimeArgs": [
"--remote-debugging-port=9222",
"-incognito"
]
}
]
}
+14
View File
@@ -0,0 +1,14 @@
// Place your settings in this file to overwrite default and user settings.
{
// Configure glob patterns for excluding files and folders in the file explorer.
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"**/bower_components": true,
"**/coverage": true,
"**/jest-output": true,
"**/lib-amd": true,
"src/**/*.scss.ts": true
},
"typescript.tsdk": ".\\node_modules\\typescript\\lib"
}
+19
View File
@@ -0,0 +1,19 @@
{
"@microsoft/generator-sharepoint": {
"useGulp": false,
"plusBeta": false,
"isCreatingSolution": true,
"nodeVersion": "22.23.1",
"sdksVersions": {},
"version": "1.22.1",
"libraryName": "approval-route-admin",
"libraryId": "ce823ddf-e35c-460f-a92d-ddb4ef5fc494",
"environment": "spo",
"packageManager": "npm",
"solutionName": "approval-route-admin",
"solutionShortDescription": "approval-route-admin description",
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"componentType": "webpart"
}
}
+77
View File
@@ -0,0 +1,77 @@
# approval-route-admin
## Summary
Short summary on functionality and used technologies.
[picture of the solution in action, if possible]
## Used SharePoint Framework Version
![version](https://img.shields.io/badge/version-1.22.1-green.svg)
## Applies to
- [SharePoint Framework](https://aka.ms/spfx)
- [Microsoft 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant)
> Get your own free development tenant by subscribing to [Microsoft 365 developer program](http://aka.ms/o365devprogram)
## Prerequisites
> Any special pre-requisites?
## Solution
| Solution | Author(s) |
| ----------- | ------------------------------------------------------- |
| folder name | Author details (name, company, twitter alias with link) |
## Version history
| Version | Date | Comments |
| ------- | ---------------- | --------------- |
| 1.1 | March 10, 2021 | Update comment |
| 1.0 | January 29, 2021 | Initial release |
## Disclaimer
**THIS CODE IS PROVIDED _AS IS_ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
---
## Minimal Path to Awesome
- Clone this repository
- Ensure that you are at the solution folder
- in the command-line run:
- `npm install -g @rushstack/heft`
- `npm install`
- `heft start`
> Include any additional steps as needed.
Other build commands can be listed using `heft --help`.
## Features
Description of the extension that expands upon high-level summary above.
This extension illustrates the following concepts:
- topic 1
- topic 2
- topic 3
> Notice that better pictures and documentation will increase the sample usage and the value you are providing for others. Thanks for your submissions advance.
> Share your web part with others through Microsoft 365 Patterns and Practices program to get visibility and exposure. More details on the community, open-source projects and other activities from http://aka.ms/m365pnp.
## References
- [Getting started with SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-developer-tenant)
- [Building for Microsoft teams](https://docs.microsoft.com/sharepoint/dev/spfx/build-for-teams-overview)
- [Use Microsoft Graph in your solution](https://docs.microsoft.com/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis)
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/sharepoint/dev/spfx/publish-to-marketplace-overview)
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
- [Heft Documentation](https://heft.rushstack.io/)
+18
View File
@@ -0,0 +1,18 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"approval-admin-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/approvalAdmin/ApprovalAdminWebPart.js",
"manifest": "./src/webparts/approvalAdmin/ApprovalAdminWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"ApprovalAdminWebPartStrings": "lib/webparts/approvalAdmin/loc/{locale}.js"
}
}
@@ -0,0 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./release/assets/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "approval-route-admin",
"accessKey": "<!-- ACCESS KEY -->"
}
+40
View File
@@ -0,0 +1,40 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "approval-route-admin-client-side-solution",
"id": "ce823ddf-e35c-460f-a92d-ddb4ef5fc494",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"developer": {
"name": "",
"websiteUrl": "",
"privacyUrl": "",
"termsOfUseUrl": "",
"mpnId": "Undefined-1.22.1"
},
"metadata": {
"shortDescription": {
"default": "approval-route-admin description"
},
"longDescription": {
"default": "approval-route-admin description"
},
"screenshotPaths": [],
"videoUrl": "",
"categories": []
},
"features": [
{
"title": "approval-route-admin Feature",
"description": "The feature that activates elements of the approval-route-admin solution.",
"id": "be919a96-acbc-43a8-9a43-2dba926e6cd2",
"version": "1.0.0.0"
}
]
},
"paths": {
"zippedPackage": "solution/approval-route-admin.sppkg"
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
"rigPackageName": "@microsoft/spfx-web-build-rig"
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json",
"extends": "@microsoft/spfx-web-build-rig/profiles/default/config/sass.json"
}
+6
View File
@@ -0,0 +1,6 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
"port": 4321,
"https": true,
"initialPage": "https://{tenantDomain}/_layouts/workbench.aspx"
}
+7
View File
@@ -0,0 +1,7 @@
{
"extends": "@microsoft/spfx-web-build-rig/profiles/default/config/typescript.json",
"staticAssetsToCopy": {
"fileExtensions": [".resx", ".jpg", ".png", ".woff", ".eot", ".ttf", ".svg", ".gif"],
"includeGlobs": ["webparts/*/loc/*.js"]
}
}
+4
View File
@@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
"cdnBasePath": "<!-- PATH TO CDN -->"
}
+20123
View File
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
{
"name": "approval-route-admin",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=22.14.0 < 23.0.0"
},
"scripts": {
"build": "heft test --clean --production && heft package-solution --production",
"start": "heft start --clean",
"clean": "heft clean",
"eject-webpack": "heft eject-webpack"
},
"dependencies": {
"@fluentui/react": "^8.106.4",
"@microsoft/sp-component-base": "1.22.1",
"@microsoft/sp-core-library": "1.22.1",
"@microsoft/sp-lodash-subset": "1.22.1",
"@microsoft/sp-office-ui-fabric-core": "1.22.1",
"@microsoft/sp-property-pane": "1.22.1",
"@microsoft/sp-webpart-base": "1.22.1",
"react": "17.0.1",
"react-dom": "17.0.1",
"tslib": "2.3.1"
},
"devDependencies": {
"@microsoft/eslint-config-spfx": "1.22.1",
"@microsoft/eslint-plugin-spfx": "1.22.1",
"@microsoft/sp-module-interfaces": "1.22.1",
"@microsoft/spfx-heft-plugins": "1.22.1",
"@microsoft/spfx-web-build-rig": "1.22.1",
"@rushstack/eslint-config": "4.5.2",
"@rushstack/heft": "1.1.2",
"@types/heft-jest": "1.0.2",
"@types/react": "17.0.45",
"@types/react-dom": "17.0.17",
"@types/webpack-env": "~1.15.2",
"@typescript-eslint/parser": "8.46.2",
"css-loader": "~7.1.2",
"eslint": "8.57.1",
"eslint-plugin-react-hooks": "4.3.0",
"typescript": "~5.8.0"
},
"overrides": {
"@rushstack/heft": "1.1.2"
},
"resolutions": {
"@types/react": "17.0.45"
}
}
@@ -0,0 +1,28 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "4825e72c-4ff3-479e-917e-f6b04e003a82",
"alias": "ApprovalAdminWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"supportedHosts": ["SharePointWebPart", "TeamsPersonalApp", "TeamsTab", "SharePointFullPage"],
"supportsThemeVariants": true,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Advanced
"group": { "default": "Advanced" },
"title": { "default": "approval-admin" },
"description": { "default": "approval-admin description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "approval-admin"
}
}]
}
@@ -0,0 +1,121 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
type IPropertyPaneConfiguration,
PropertyPaneTextField
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { IReadonlyTheme } from '@microsoft/sp-component-base';
import * as strings from 'ApprovalAdminWebPartStrings';
import ApprovalAdmin from './components/ApprovalAdmin';
import { IApprovalAdminProps } from './components/IApprovalAdminProps';
export interface IApprovalAdminWebPartProps {
description: string;
}
export default class ApprovalAdminWebPart extends BaseClientSideWebPart<IApprovalAdminWebPartProps> {
private _isDarkTheme: boolean = false;
private _environmentMessage: string = '';
public render(): void {
const element: React.ReactElement<IApprovalAdminProps> = React.createElement(
ApprovalAdmin,
{
description: this.properties.description,
isDarkTheme: this._isDarkTheme,
environmentMessage: this._environmentMessage,
hasTeamsContext: !!this.context.sdks.microsoftTeams,
userDisplayName: this.context.pageContext.user.displayName
}
);
ReactDom.render(element, this.domElement);
}
protected onInit(): Promise<void> {
return this._getEnvironmentMessage().then(message => {
this._environmentMessage = message;
});
}
private _getEnvironmentMessage(): Promise<string> {
if (!!this.context.sdks.microsoftTeams) { // running in Teams, office.com or Outlook
return this.context.sdks.microsoftTeams.teamsJs.app.getContext()
.then(context => {
let environmentMessage: string = '';
switch (context.app.host.name) {
case 'Office': // running in Office
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOffice : strings.AppOfficeEnvironment;
break;
case 'Outlook': // running in Outlook
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOutlook : strings.AppOutlookEnvironment;
break;
case 'Teams': // running in Teams
case 'TeamsModern':
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentTeams : strings.AppTeamsTabEnvironment;
break;
default:
environmentMessage = strings.UnknownEnvironment;
}
return environmentMessage;
});
}
return Promise.resolve(this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentSharePoint : strings.AppSharePointEnvironment);
}
protected onThemeChanged(currentTheme: IReadonlyTheme | undefined): void {
if (!currentTheme) {
return;
}
this._isDarkTheme = !!currentTheme.isInverted;
const {
semanticColors
} = currentTheme;
if (semanticColors) {
this.domElement.style.setProperty('--bodyText', semanticColors.bodyText || null);
this.domElement.style.setProperty('--link', semanticColors.link || null);
this.domElement.style.setProperty('--linkHovered', semanticColors.linkHovered || null);
}
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,34 @@
@import '~@fluentui/react/dist/sass/References.scss';
.approvalAdmin {
overflow: hidden;
padding: 1em;
color: "[theme:bodyText, default: #323130]";
color: var(--bodyText);
&.teams {
font-family: $ms-font-family-fallbacks;
}
}
.welcome {
text-align: center;
}
.welcomeImage {
width: 100%;
max-width: 420px;
}
.links {
a {
text-decoration: none;
color: "[theme:link, default:#03787c]";
color: var(--link); // note: CSS Custom Properties support is limited to modern browsers only
&:hover {
text-decoration: underline;
color: "[theme:linkHovered, default: #014446]";
color: var(--linkHovered); // note: CSS Custom Properties support is limited to modern browsers only
}
}
}
@@ -0,0 +1,43 @@
import * as React from 'react';
import styles from './ApprovalAdmin.module.scss';
import type { IApprovalAdminProps } from './IApprovalAdminProps';
import { escape } from '@microsoft/sp-lodash-subset';
export default class ApprovalAdmin extends React.Component<IApprovalAdminProps> {
public render(): React.ReactElement<IApprovalAdminProps> {
const {
description,
isDarkTheme,
environmentMessage,
hasTeamsContext,
userDisplayName
} = this.props;
return (
<section className={`${styles.approvalAdmin} ${hasTeamsContext ? styles.teams : ''}`}>
<div className={styles.welcome}>
<img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} />
<h2>Well done, {escape(userDisplayName)}!</h2>
<div>{environmentMessage}</div>
<div>Web part property value: <strong>{escape(description)}</strong></div>
</div>
<div>
<h3>Welcome to SharePoint Framework!</h3>
<p>
The SharePoint Framework (SPFx) is a extensibility model for Microsoft Viva, Microsoft Teams and SharePoint. It&#39;s the easiest way to extend Microsoft 365 with automatic Single Sign On, automatic hosting and industry standard tooling.
</p>
<h4>Learn more about SPFx development:</h4>
<ul className={styles.links}>
<li><a href="https://aka.ms/spfx" target="_blank" rel="noreferrer">SharePoint Framework Overview</a></li>
<li><a href="https://aka.ms/spfx-yeoman-graph" target="_blank" rel="noreferrer">Use Microsoft Graph in your solution</a></li>
<li><a href="https://aka.ms/spfx-yeoman-teams" target="_blank" rel="noreferrer">Build for Microsoft Teams using SharePoint Framework</a></li>
<li><a href="https://aka.ms/spfx-yeoman-viva" target="_blank" rel="noreferrer">Build for Microsoft Viva Connections using SharePoint Framework</a></li>
<li><a href="https://aka.ms/spfx-yeoman-store" target="_blank" rel="noreferrer">Publish SharePoint Framework applications to the marketplace</a></li>
<li><a href="https://aka.ms/spfx-yeoman-api" target="_blank" rel="noreferrer">SharePoint Framework API reference</a></li>
<li><a href="https://aka.ms/m365pnp" target="_blank" rel="noreferrer">Microsoft 365 Developer Community</a></li>
</ul>
</div>
</section>
);
}
}
@@ -0,0 +1,7 @@
export interface IApprovalAdminProps {
description: string;
isDarkTheme: boolean;
environmentMessage: string;
hasTeamsContext: boolean;
userDisplayName: string;
}
@@ -0,0 +1,16 @@
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field",
"AppLocalEnvironmentSharePoint": "The app is running on your local environment as SharePoint web part",
"AppLocalEnvironmentTeams": "The app is running on your local environment as Microsoft Teams app",
"AppLocalEnvironmentOffice": "The app is running on your local environment in office.com",
"AppLocalEnvironmentOutlook": "The app is running on your local environment in Outlook",
"AppSharePointEnvironment": "The app is running on SharePoint page",
"AppTeamsTabEnvironment": "The app is running in Microsoft Teams",
"AppOfficeEnvironment": "The app is running in office.com",
"AppOutlookEnvironment": "The app is running in Outlook",
"UnknownEnvironment": "The app is running in an unknown environment"
}
});
+19
View File
@@ -0,0 +1,19 @@
declare interface IApprovalAdminWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
DescriptionFieldLabel: string;
AppLocalEnvironmentSharePoint: string;
AppLocalEnvironmentTeams: string;
AppLocalEnvironmentOffice: string;
AppLocalEnvironmentOutlook: string;
AppSharePointEnvironment: string;
AppTeamsTabEnvironment: string;
AppOfficeEnvironment: string;
AppOutlookEnvironment: string;
UnknownEnvironment: string;
}
declare module 'ApprovalAdminWebPartStrings' {
const strings: IApprovalAdminWebPartStrings;
export = strings;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

+3
View File
@@ -0,0 +1,3 @@
{
"extends": "./node_modules/@microsoft/spfx-web-build-rig/profiles/default/tsconfig-base.json"
}