1. Repo restructuring - updated code
This commit is contained in:
Родитель
c468d88812
Коммит
2f19be0926
|
@ -0,0 +1,24 @@
|
|||
# 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*
|
||||
.eslintcache
|
|
@ -0,0 +1,35 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
/dist
|
||||
|
||||
# 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*
|
||||
/.vs
|
||||
/public
|
||||
/src/Examples
|
||||
/src/App.css
|
||||
/src/App.tsx
|
||||
/src/index.tsx
|
||||
/src/index.css
|
||||
/src/App.test.tsx
|
||||
/.npmrc
|
||||
/package-lock.json
|
||||
/tsconfig.json
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
|
@ -0,0 +1,224 @@
|
|||
# FluidUI Editable DetailsList
|
||||
|
||||
## Overview
|
||||
FluentUI is a great UI library with some really cool controls, all adhering to Accessibility Standards.
|
||||
|
||||
DetailsList control of FluidUI is great when your requirement is a read-only grid. However, it does not offer any in-place editability functionality just yet.
|
||||
|
||||
This component(Editable DetailsList) is a wrapper over the existing DetailsList that makes in-place editability work like a dream(among many other new features).
|
||||
|
||||
Some of the features of the Editable Grid are:-
|
||||
>- Single Cell Edit (in-place)
|
||||
>- Single Row Edit (in-place)
|
||||
>- Single Column Edit
|
||||
>- Multi-Column, multi-row edit (Bulk Edit)
|
||||
>- Full Edit (Edit Mode)
|
||||
>- Deleting Rows
|
||||
>- Adding Rows
|
||||
>- Default Data Export (to Excel, CSV)
|
||||
>- Implement Custom Export functionality
|
||||
>- Callback hook to recieve grid data in the consuming component(for Save etc.)
|
||||
>- Support for various controls in grid in-place edit like TextField, Multiline TextField, DatePicker (Support for Dropdown will be released soon)
|
||||
>- Flexibility to implement onChange callback on any cell value change (For cases like calculating summation of a column etc)
|
||||
>- Length Validations during edit
|
||||
>- Type Validations during edit
|
||||
>- The component is completely Accessible
|
||||
|
||||
## Clone & Run
|
||||
- clone the repository on your local machine.
|
||||
- open the project
|
||||
- open terminal and change directory to your project path
|
||||
- type '***npm install***'
|
||||
- after the installation is complete, type '***npm start***'
|
||||
|
||||
This starts the project on port 8080 and you are ready to play around with the Editable DetailsList
|
||||
|
||||
## NPM Install
|
||||
npm i fluentui-editable-grid
|
||||
|
||||
## Usage
|
||||
import { DetailsListLayoutMode, SelectionMode } from '@fluentui/react';
|
||||
import { EditableGrid, EditControlType, IColumnConfig } from 'fluentui-editable-grid';
|
||||
import { Fabric } from 'office-ui-fabric-react';
|
||||
import * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
const Consumer = () => {
|
||||
const [items, setItems] = useState<any[]>([]);
|
||||
const columns: IColumnConfig[] = [
|
||||
{
|
||||
key: 'id',
|
||||
name: 'ID',
|
||||
text: 'ID',
|
||||
editable: false,
|
||||
dataType: 'number',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
name: 'Name',
|
||||
text: 'Name',
|
||||
editable: true,
|
||||
dataType: 'string',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'age',
|
||||
name: 'Age',
|
||||
text: 'Age',
|
||||
editable: true,
|
||||
dataType: 'number',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'designation',
|
||||
name: 'Designation',
|
||||
text: 'Designation',
|
||||
editable: true,
|
||||
dataType: 'string',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
inputType: EditControlType.MultilineTextField,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'salary',
|
||||
name: 'Salary',
|
||||
text: 'Salary',
|
||||
editable: true,
|
||||
dataType: 'number',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: false,
|
||||
includeColumnInSearch: true,
|
||||
maxLength:5,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'dateofjoining',
|
||||
name: 'Date of Joining',
|
||||
text: 'Date of Joining',
|
||||
editable: true,
|
||||
dataType: 'date',
|
||||
minWidth: 150,
|
||||
maxWidth: 150,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
inputType: EditControlType.Date
|
||||
}
|
||||
];
|
||||
|
||||
const SetDummyData = () : void => {
|
||||
const dummyData = [
|
||||
{
|
||||
id: "1",
|
||||
name: "Name1",
|
||||
age:32,
|
||||
designation:'Designation1',
|
||||
salary:75000,
|
||||
dateofjoining:'2010-04-01T14:57:10'
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
name: "Name2",
|
||||
age:32,
|
||||
designation:'Designation2',
|
||||
salary:75000,
|
||||
dateofjoining:'2014-06-09T14:57:10'
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
name: "Name3",
|
||||
age:32,
|
||||
designation:'Designation3',
|
||||
salary:75000,
|
||||
dateofjoining:'2005-07-02T14:57:10'
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
name: "Name4",
|
||||
age:32,
|
||||
designation:'Designation4',
|
||||
salary:75000,
|
||||
dateofjoining:'2019-04-01T14:57:10'
|
||||
}
|
||||
];
|
||||
setItems(dummyData);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
SetDummyData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Fabric>
|
||||
<EditableGrid
|
||||
id={1}
|
||||
columns={columns}
|
||||
items={items}
|
||||
enableCellEdit={true}
|
||||
enableExport={true}
|
||||
enableTextFieldEditMode={true}
|
||||
enableTextFieldEditModeCancel={true}
|
||||
enableGridRowsDelete={true}
|
||||
enableGridRowsAdd={true}
|
||||
height={'70vh'}
|
||||
width={'140vh'}
|
||||
position={'relative'}
|
||||
enableUnsavedEditIndicator={true}
|
||||
//onGridSave={onGridSave}
|
||||
enableGridReset={true}
|
||||
enableColumnFilters={true}
|
||||
enableColumnFilterRules={true}
|
||||
enableRowAddWithValues={{enable : true, enableRowsCounterInPanel : true}}
|
||||
layoutMode={DetailsListLayoutMode.justified}
|
||||
selectionMode={SelectionMode.multiple}
|
||||
enableRowEdit={true}
|
||||
enableRowEditCancel={true}
|
||||
enableBulkEdit={true}
|
||||
enableColumnEdit={true}
|
||||
enableSave={true}
|
||||
/>
|
||||
</Fabric>
|
||||
);
|
||||
};
|
||||
|
||||
export default Consumer;
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
---
|
||||
|
||||
_For more details please check out [Fluent UI Editable DetailsList Wiki](https://github.com/microsoft/FluentUIEditableDetailsList/wiki)._
|
|
@ -0,0 +1,41 @@
|
|||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.5 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
|
@ -0,0 +1,25 @@
|
|||
# TODO: The maintainer of this repo has not yet edited this file
|
||||
|
||||
**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
|
||||
|
||||
- **No CSS support:** Fill out this template with information about how to file issues and get help.
|
||||
- **Yes CSS support:** Fill out an intake form at [aka.ms/spot](https://aka.ms/spot). CSS will work with/help you to determine next steps. More details also available at [aka.ms/onboardsupport](https://aka.ms/onboardsupport).
|
||||
- **Not sure?** Fill out a SPOT intake as though the answer were "Yes". CSS will help you decide.
|
||||
|
||||
*Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
|
||||
|
||||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
|
||||
issues before filing new issues to avoid duplicates. For new issues, file your bug or
|
||||
feature request as a new Issue.
|
||||
|
||||
For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
|
||||
FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
|
||||
CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
|
||||
|
||||
## Microsoft Support Policy
|
||||
|
||||
Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"name": "fluentui-editable-grid",
|
||||
"version": "1.1.0",
|
||||
"license": "MIT",
|
||||
"description": "Wrapper over the existing DetailsList that makes in-place editability work like a dream(among many other new features)",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/FluentUIEditableDetailsList"
|
||||
},
|
||||
"keywords": [
|
||||
"editable",
|
||||
"grid",
|
||||
"detailslist",
|
||||
"fluentui"
|
||||
],
|
||||
"bugs": "https://github.com/microsoft/FluentUIEditableDetailsList/issues",
|
||||
"dependencies": {
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5",
|
||||
"@babel/cli": "7.12.1",
|
||||
"@babel/core": "^7.14.8",
|
||||
"@babel/preset-env": "^7.14.9",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@babel/preset-stage-0": "^7.8.3",
|
||||
"@fluentui/react": "^8.26.0",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^11.2.7",
|
||||
"@testing-library/user-event": "^12.8.3",
|
||||
"@types/file-saver": "^2.0.1",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/node": "^12.20.17",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"cpx": "^1.5.0",
|
||||
"file-saver": "^2.0.2",
|
||||
"office-ui-fabric-react": "^7.0.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-scripts": "^4.0.3",
|
||||
"typescript": "^4.3.5",
|
||||
"web-vitals": "^1.1.2",
|
||||
"webpack-cli": "^4.7.2",
|
||||
"xlsx": "^0.16.6",
|
||||
"y18n": "^3.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"just-scripts": "^0.27.0",
|
||||
"just-stack-react": "^1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build-site": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"clean": "if exist dist rd /s /q dist",
|
||||
"prepareBuild": "npm run clean && mkdir dist",
|
||||
"compile": "set NODE_ENV=production & babel src/libs --out-dir dist --extensions \".ts,.tsx\" --copy-files",
|
||||
"copy": "cpx \"{package.json,README.md}\" dist",
|
||||
"build": "npm run prepareBuild && npm run compile && tsc && npm run copy",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/env",
|
||||
"@babel/preset-react",
|
||||
"@babel/preset-typescript"
|
||||
],
|
||||
"ignore": [
|
||||
"**/*.test.js",
|
||||
"**/stories.js",
|
||||
"**/*.stories.js"
|
||||
]
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 3.8 KiB |
|
@ -0,0 +1,38 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { App } from './App';
|
||||
|
||||
it('renders "Welcome to Your Fluent UI App"', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/Welcome to Your Fluent UI App/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
|
@ -0,0 +1,24 @@
|
|||
import React from 'react';
|
||||
import { Stack, Text, Link, FontWeights, IStackTokens, IStackStyles, ITextStyles } from '@fluentui/react';
|
||||
import logo from './logo.svg';
|
||||
import './App.css';
|
||||
import Consumer from './Examples/gridconsumer/gridconsumer';
|
||||
|
||||
const boldStyle: Partial<ITextStyles> = { root: { fontWeight: FontWeights.semibold } };
|
||||
const stackTokens: IStackTokens = { childrenGap: 15 };
|
||||
const stackStyles: Partial<IStackStyles> = {
|
||||
root: {
|
||||
width: '960px',
|
||||
margin: '0 auto',
|
||||
textAlign: 'center',
|
||||
color: '#605e5c',
|
||||
},
|
||||
};
|
||||
|
||||
export const App: React.FunctionComponent = () => {
|
||||
return (
|
||||
<Stack horizontalAlign="center" verticalAlign="center" verticalFill styles={stackStyles} tokens={stackTokens}>
|
||||
<Consumer />
|
||||
</Stack>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { NumberAndDateOperators, StringOperators } from "../../libs/types/cellstyleruletype";
|
||||
import { IColumnConfig } from "../../libs/types/columnconfigtype";
|
||||
import { EditControlType } from "../../libs/types/editcontroltype";
|
||||
import { IGridItemsType } from "../../libs/types/griditemstype";
|
||||
|
||||
export const GridColumnConfig : IColumnConfig[] =
|
||||
[
|
||||
{
|
||||
key: 'id',
|
||||
name: 'ID',
|
||||
text: 'ID',
|
||||
editable: false,
|
||||
dataType: 'number',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
name: 'Name',
|
||||
text: 'Name',
|
||||
editable: true,
|
||||
dataType: 'string',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'age',
|
||||
name: 'Age',
|
||||
text: 'Age',
|
||||
editable: true,
|
||||
dataType: 'number',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'designation',
|
||||
name: 'Designation',
|
||||
text: 'Designation',
|
||||
editable: true,
|
||||
dataType: 'string',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
inputType: EditControlType.MultilineTextField,
|
||||
applyColumnFilter: true
|
||||
},
|
||||
{
|
||||
key: 'salary',
|
||||
name: 'Salary',
|
||||
text: 'Salary',
|
||||
editable: true,
|
||||
dataType: 'number',
|
||||
minWidth: 100,
|
||||
maxWidth: 100,
|
||||
isResizable: true,
|
||||
includeColumnInExport: false,
|
||||
includeColumnInSearch: true,
|
||||
maxLength:5,
|
||||
applyColumnFilter: true,
|
||||
cellStyleRule: {
|
||||
enable: true,
|
||||
rule: {
|
||||
operator : NumberAndDateOperators.LESSTHAN,
|
||||
value: 50000
|
||||
},
|
||||
whenTrue: { textColor: '#EF5350', fontWeight: 'bold' },
|
||||
whenFalse: { textColor: '#9CCC65' }
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'dateofjoining',
|
||||
name: 'Date of Joining',
|
||||
text: 'Date of Joining',
|
||||
editable: true,
|
||||
dataType: 'date',
|
||||
minWidth: 150,
|
||||
maxWidth: 150,
|
||||
isResizable: true,
|
||||
includeColumnInExport: true,
|
||||
includeColumnInSearch: true,
|
||||
inputType: EditControlType.Date
|
||||
}
|
||||
];
|
||||
|
||||
export interface GridItemsType {
|
||||
id: number;
|
||||
name: string;
|
||||
age: number;
|
||||
designation: string;
|
||||
salary: number;
|
||||
dateofjoining: string;
|
||||
};
|
|
@ -0,0 +1,111 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { DefaultButton, DetailsList, DetailsListLayoutMode, Fabric, mergeStyles, mergeStyleSets, SelectionMode, TextField } from 'office-ui-fabric-react';
|
||||
import * as React from 'react';
|
||||
import { useState } from 'react';
|
||||
import EditableGrid from '../../libs/editablegrid/editablegrid';
|
||||
import { ICallBackParams, ICallBackRequestParams } from '../../libs/types/callbackparams';
|
||||
import { IColumnConfig } from '../../libs/types/columnconfigtype';
|
||||
import { GridColumnConfig, GridItemsType } from './gridconfig';
|
||||
import { EventEmitter, EventType } from '../../libs/eventemitter/EventEmitter.js';
|
||||
|
||||
const Consumer = () => {
|
||||
|
||||
const [items, setItems] = useState<GridItemsType[]>([]);
|
||||
|
||||
const classNames = mergeStyleSets({
|
||||
controlWrapper: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
}
|
||||
});
|
||||
|
||||
const GetRandomDate = (start : Date, end : Date) : Date => {
|
||||
var diff = end.getTime() - start.getTime();
|
||||
var new_diff = diff * Math.random();
|
||||
var date = new Date(start.getTime() + new_diff);
|
||||
return date;
|
||||
}
|
||||
|
||||
const GetRandomInt = (min : number, max : number) : number => {
|
||||
min = Math.ceil(min);
|
||||
max = Math.floor(max);
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
};
|
||||
|
||||
const SetDummyData = () : void => {
|
||||
var dummyData : GridItemsType[] = []
|
||||
for(var i = 1; i <= 100; i++){
|
||||
dummyData.push({
|
||||
id: i,
|
||||
name: 'Name'+ GetRandomInt(1, 10),
|
||||
age: GetRandomInt(20,40),
|
||||
designation: 'Designation' + GetRandomInt(1, 15),
|
||||
salary: GetRandomInt(35000, 75000),
|
||||
dateofjoining: '2010-10-10T14:57:10'
|
||||
});
|
||||
}
|
||||
|
||||
setItems(dummyData);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
SetDummyData();
|
||||
}, []);
|
||||
|
||||
const onGridSave = (data: any[]): void => {
|
||||
alert('Grid Data Saved');
|
||||
setItems([...data]);
|
||||
};
|
||||
|
||||
const onDesignationChanged = (callbackRequestParamObj : ICallBackParams): any[] => {
|
||||
callbackRequestParamObj.rowindex.forEach((index) => {
|
||||
callbackRequestParamObj.data.filter((item) => item._grid_row_id_ == index).map((item) => item.salary = 30000);
|
||||
});
|
||||
|
||||
return callbackRequestParamObj.data;
|
||||
}
|
||||
|
||||
const attachGridValueChangeCallbacks = (columnConfig : IColumnConfig[]) : IColumnConfig[] => {
|
||||
columnConfig.filter((item) => item.key == 'designation').map((item) => item.onChange = onDesignationChanged);
|
||||
return columnConfig;
|
||||
};
|
||||
|
||||
return (
|
||||
<Fabric>
|
||||
<div className={classNames.controlWrapper}>
|
||||
<TextField placeholder='Search Grid' className={mergeStyles({ width: '60vh', paddingBottom:'10px' })} onChange={(event) => EventEmitter.dispatch(EventType.onSearch, event)}/>
|
||||
</div>
|
||||
<EditableGrid
|
||||
id={1}
|
||||
enableColumnEdit={true}
|
||||
enableSave={true}
|
||||
columns={attachGridValueChangeCallbacks(GridColumnConfig)}
|
||||
layoutMode={DetailsListLayoutMode.justified}
|
||||
selectionMode={SelectionMode.multiple}
|
||||
enableRowEdit={true}
|
||||
enableRowEditCancel={true}
|
||||
enableBulkEdit={true}
|
||||
items={items}
|
||||
enableCellEdit={true}
|
||||
enableExport={true}
|
||||
enableTextFieldEditMode={true}
|
||||
enableTextFieldEditModeCancel={true}
|
||||
enableGridRowsDelete={true}
|
||||
enableGridRowsAdd={true}
|
||||
height={'70vh'}
|
||||
width={'140vh'}
|
||||
position={'relative'}
|
||||
enableUnsavedEditIndicator={true}
|
||||
onGridSave={onGridSave}
|
||||
enableGridReset={true}
|
||||
enableColumnFilters={true}
|
||||
enableColumnFilterRules={true}
|
||||
enableRowAddWithValues={{enable : true, enableRowsCounterInPanel : true}}
|
||||
/>
|
||||
</Fabric>
|
||||
);
|
||||
};
|
||||
|
||||
export default Consumer;
|
|
@ -0,0 +1,11 @@
|
|||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans',
|
||||
'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { App } from './App';
|
||||
import { mergeStyles } from '@fluentui/react';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
// Inject some global styles
|
||||
mergeStyles({
|
||||
':global(body,html,#root)': {
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
height: '100vh',
|
||||
},
|
||||
});
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
|
@ -0,0 +1,98 @@
|
|||
import { ConstrainMode, DatePicker, IStackStyles, IStackTokens, ITextFieldStyles, mergeStyleSets, Position, PrimaryButton, SpinButton, Stack, TextField } from "office-ui-fabric-react";
|
||||
import React, { useState } from "react";
|
||||
import { IColumnConfig } from "../types/columnconfigtype";
|
||||
import { EditControlType } from "../types/editcontroltype";
|
||||
import { DayPickerStrings } from "./datepickerconfig";
|
||||
import { controlClass, horizontalGapStackTokens, stackStyles, textFieldStyles, verticalGapStackTokens } from "./editablegridstyles";
|
||||
|
||||
interface Props {
|
||||
onChange: any;
|
||||
columnConfigurationData: IColumnConfig[];
|
||||
enableRowsCounterField?: boolean;
|
||||
}
|
||||
|
||||
const AddRowPanel = (props: Props) => {
|
||||
let AddSpinRef: any = React.createRef();
|
||||
|
||||
const updateObj : any = {};
|
||||
|
||||
const onTextUpdate = (ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, text: string): void => {
|
||||
updateObj[(ev.target as Element).id] = text;
|
||||
//console.log(updateObj);
|
||||
};
|
||||
|
||||
const onPanelSubmit = (): void => {
|
||||
props.onChange(updateObj, props.enableRowsCounterField ? AddSpinRef.current.value : 1);
|
||||
};
|
||||
|
||||
const onCellDateChange = (date: Date | null | undefined, item : any): void => {
|
||||
updateObj[item.key] = date;
|
||||
};
|
||||
|
||||
const createTextFields = () : any[] => {
|
||||
let tmpRenderObj : any[] = [];
|
||||
props.columnConfigurationData.forEach((item, index) => {
|
||||
switch(item.inputType){
|
||||
case EditControlType.Date:
|
||||
tmpRenderObj.push(<DatePicker
|
||||
label={item.text}
|
||||
strings={DayPickerStrings}
|
||||
placeholder="Select a date..."
|
||||
ariaLabel="Select a date"
|
||||
onSelectDate={(date) => onCellDateChange(date, item)}
|
||||
//value={props != null && props.panelValues != null ? new Date(props.panelValues[item.key]) : new Date()}
|
||||
value={new Date()}
|
||||
/>);
|
||||
break;
|
||||
default:
|
||||
tmpRenderObj.push(<TextField
|
||||
name={item.text}
|
||||
id={item.key}
|
||||
label={item.text}
|
||||
styles={textFieldStyles}
|
||||
onChange={(ev, text) => onTextUpdate(ev, text!)}
|
||||
defaultValue = { '' }
|
||||
/>);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if(props.enableRowsCounterField){
|
||||
tmpRenderObj.push(
|
||||
<SpinButton
|
||||
componentRef = {AddSpinRef}
|
||||
label="# of Rows to Add"
|
||||
labelPosition={Position.top}
|
||||
defaultValue="0"
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
incrementButtonAriaLabel="Increase value by 1"
|
||||
decrementButtonAriaLabel="Decrease value by 1"
|
||||
styles={{ spinButtonWrapper: { width: 75 } }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
console.log(tmpRenderObj);
|
||||
return tmpRenderObj;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Stack tokens={verticalGapStackTokens}>
|
||||
{createTextFields()}
|
||||
</Stack>
|
||||
<Stack horizontal disableShrink styles={stackStyles} tokens={horizontalGapStackTokens}>
|
||||
<PrimaryButton
|
||||
text="Save To Grid"
|
||||
className={controlClass.submitStylesEditpanel}
|
||||
onClick={onPanelSubmit}
|
||||
allowDisabledFocus
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddRowPanel;
|
|
@ -0,0 +1,35 @@
|
|||
import { Callout, DirectionalHint } from "office-ui-fabric-react";
|
||||
import React from "react";
|
||||
import { useId } from '@uifabric/react-hooks';
|
||||
import { styles } from "./filtercalloutstyles";
|
||||
import FilterList from "./filterlist";
|
||||
import { IFilterCalloutProps } from "../../types/columnfilterstype";
|
||||
|
||||
interface Props extends IFilterCalloutProps {
|
||||
onApply: any;
|
||||
onCancel: any;
|
||||
}
|
||||
|
||||
const FilterCallout = (props : Props) => {
|
||||
const labelId: string = useId('callout-label');
|
||||
const descriptionId: string = useId('callout-description');
|
||||
console.log(props.columnClass);
|
||||
return(
|
||||
<>
|
||||
<Callout
|
||||
className={styles.callout}
|
||||
ariaLabelledBy={labelId}
|
||||
ariaDescribedBy={descriptionId}
|
||||
role="filtercallout"
|
||||
gapSpace={5}
|
||||
target={`.${props.columnClass}`}
|
||||
isBeakVisible={true}
|
||||
directionalHint={DirectionalHint.topCenter}
|
||||
>
|
||||
<FilterList onCancel={props.onCancel} onApply={props.onApply} columnKey={props.columnKey} columnName={props.columnName} filterList={props.filterList} />
|
||||
</Callout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default FilterCallout;
|
|
@ -0,0 +1,8 @@
|
|||
import { mergeStyleSets } from "office-ui-fabric-react";
|
||||
|
||||
export const styles = mergeStyleSets({
|
||||
callout: {
|
||||
maxWidth: 500,
|
||||
padding: 30
|
||||
}
|
||||
});
|
|
@ -0,0 +1,189 @@
|
|||
import { ActionButton, Checkbox, DefaultButton, Dropdown, mergeStyles, PrimaryButton, ScrollablePane, ScrollbarVisibility, Stack, TextField } from "office-ui-fabric-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { IFilterCalloutProps, IFilterItem, IFilterListItem, IFilterListProps } from "../../types/columnfilterstype";
|
||||
import { styles, stackTokens } from "./filterliststyles";
|
||||
|
||||
interface Props extends IFilterListProps {
|
||||
onApply: any;
|
||||
onCancel: any;
|
||||
}
|
||||
|
||||
const FilterList = (props : Props) => {
|
||||
const [filterItemsList, setFilterItemsList] = React.useState<IFilterListItem[]>([]);
|
||||
const [filterListContent, setFilterListContent] = React.useState<JSX.Element[] | undefined>([]);
|
||||
const [appliedFilters, setAppliedFilters] = React.useState<IFilterItem[]>([]);
|
||||
|
||||
const [isSelectAllIndeterminate, setIsSelectAllIndeterminate] = React.useState(true);
|
||||
const [isSelectAllChecked, setIsSelectAllChecked] = React.useState(true);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
debugger;
|
||||
if(props && props.filterList && props.filterList.length > 0){
|
||||
setFilterItemsList(props.filterList.map((item, index) => {
|
||||
return {key: index, text : item.text, isFilteredIn : true, isChecked : item.isChecked};
|
||||
}))
|
||||
setAppliedFilters(props.filterList.map((item, index) => {
|
||||
return {text : item.text, isChecked : item.isChecked};
|
||||
}));
|
||||
}
|
||||
else{
|
||||
setFilterItemsList([]);
|
||||
}
|
||||
},[props.filterList])
|
||||
|
||||
useEffect(() => {
|
||||
}, [appliedFilters]);
|
||||
|
||||
useEffect(() => {
|
||||
debugger;
|
||||
SetIndeterminate(filterItemsList);
|
||||
if(filterItemsList && filterItemsList.length > 0){
|
||||
let tmpRenderObj : any[] = [];
|
||||
filterItemsList.filter((item) => item.isFilteredIn == true).forEach((item, index) => {
|
||||
tmpRenderObj.push(<Checkbox
|
||||
label={item.text}
|
||||
key={item.key}
|
||||
onChange={(ev, checked) => onCheckChanged(ev!, checked!, item.key!, item.text)}
|
||||
//defaultChecked={item.isChecked}
|
||||
className={styles.checkbox}
|
||||
checked={item.isChecked}
|
||||
/>);
|
||||
});
|
||||
setFilterListContent(tmpRenderObj);
|
||||
}
|
||||
else{
|
||||
setFilterListContent(undefined);
|
||||
}
|
||||
},[filterItemsList])
|
||||
|
||||
const SetIndeterminate = (filterItemsList : IFilterListItem[]) : void => {
|
||||
var checkedCount = filterItemsList.filter((item) => item.isChecked == true).length;
|
||||
var totalCount = filterItemsList.length;
|
||||
var uncheckedCount = totalCount - checkedCount;
|
||||
|
||||
if(checkedCount == totalCount){
|
||||
setIsSelectAllIndeterminate(false);
|
||||
setIsSelectAllChecked(true);
|
||||
}
|
||||
else if(uncheckedCount == totalCount){
|
||||
setIsSelectAllIndeterminate(false);
|
||||
setIsSelectAllChecked(false);
|
||||
}
|
||||
else{
|
||||
setIsSelectAllIndeterminate(true);
|
||||
setIsSelectAllChecked(false);
|
||||
}
|
||||
}
|
||||
|
||||
function onCheckChanged(ev: React.FormEvent<HTMLElement>, isChecked: boolean, key : number, text: string) {
|
||||
debugger;
|
||||
|
||||
var filterItemsListTmp : IFilterListItem[] = [...filterItemsList];
|
||||
filterItemsListTmp.filter((item) => item.key == key).map((item) => item.isChecked = isChecked);
|
||||
setFilterItemsList(filterItemsListTmp);
|
||||
|
||||
var appliedFiltersTmp : IFilterItem[] = [...appliedFilters];
|
||||
appliedFiltersTmp.filter((item) => item.text == text).map((item) => item.isChecked = isChecked);
|
||||
setAppliedFilters(appliedFiltersTmp);
|
||||
}
|
||||
|
||||
const onSelectAllCheckChanged = (ev: React.FormEvent<HTMLElement>, isChecked: boolean) : void => {
|
||||
var filterItemsListTmp : IFilterListItem[] = [...filterItemsList];
|
||||
filterItemsListTmp.map((item) => item.isChecked = isChecked);
|
||||
setFilterItemsList(filterItemsListTmp);
|
||||
|
||||
var appliedFiltersTmp : IFilterItem[] = [...appliedFilters];
|
||||
appliedFiltersTmp.map((item) => item.isChecked = isChecked);
|
||||
setAppliedFilters(appliedFiltersTmp);
|
||||
}
|
||||
|
||||
const onReset = (): void => {
|
||||
var filterItemsListTmp : IFilterListItem[] = [...filterItemsList];
|
||||
filterItemsListTmp.map((item) => item.isChecked = false);
|
||||
setFilterItemsList(filterItemsListTmp);
|
||||
|
||||
var appliedFiltersTmp : IFilterItem[] = [...appliedFilters];
|
||||
appliedFiltersTmp.map((item) => item.isChecked = false);
|
||||
setAppliedFilters(appliedFiltersTmp);
|
||||
};
|
||||
|
||||
const onApply = (): void => {
|
||||
if(props.onApply){
|
||||
var onApplyParams : IFilterListProps = { columnKey: props.columnKey, columnName: props.columnName, filterList: appliedFilters }
|
||||
props.onApply(onApplyParams);
|
||||
}
|
||||
};
|
||||
|
||||
const onFilterTextUpdate = (ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, text: string | undefined): void => {
|
||||
if(text){
|
||||
let searchResult : IFilterListItem[] = [...filterItemsList];
|
||||
searchResult.filter(
|
||||
(_data, index) => {
|
||||
var BreakException = {};
|
||||
try{
|
||||
if(_data.text.toString().toLowerCase().includes(text.trim().toLowerCase())){
|
||||
_data.isFilteredIn = true;
|
||||
throw BreakException;
|
||||
}
|
||||
else{
|
||||
_data.isFilteredIn = false;
|
||||
}
|
||||
} catch (e) {
|
||||
// if (e !== BreakException) throw e;
|
||||
}
|
||||
}
|
||||
);
|
||||
setFilterItemsList(searchResult);
|
||||
}
|
||||
else{
|
||||
var filterItemsListTmp : IFilterListItem[] = [...filterItemsList];
|
||||
filterItemsListTmp.map((item) => item.isFilteredIn = true);
|
||||
setFilterItemsList(filterItemsListTmp);
|
||||
}
|
||||
};
|
||||
|
||||
return(
|
||||
<>
|
||||
<Stack verticalAlign="start" tokens={stackTokens}>
|
||||
<TextField
|
||||
placeholder={`Filter ${props.columnName}`}
|
||||
onChange={(ev, text) => onFilterTextUpdate(ev, text)}
|
||||
/>
|
||||
<div className={mergeStyles({ height: '25vh', width: '30vh', position: 'relative', backgroundColor: 'white' })}>
|
||||
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto}>
|
||||
<Checkbox
|
||||
label="(Select All)"
|
||||
key={'SelectAll'}
|
||||
indeterminate={isSelectAllIndeterminate}
|
||||
checked={isSelectAllChecked}
|
||||
className={styles.selectAllCheckbox}
|
||||
onChange={(ev, checked) => onSelectAllCheckChanged(ev!, checked!)}
|
||||
/>
|
||||
{filterListContent}
|
||||
</ScrollablePane>
|
||||
</div>
|
||||
|
||||
<Stack horizontal horizontalAlign="start">
|
||||
<ActionButton
|
||||
className={styles.button}
|
||||
onClick={onApply}
|
||||
text="Apply" />
|
||||
|
||||
<ActionButton
|
||||
text="Clear All"
|
||||
className={styles.button}
|
||||
onClick={onReset}
|
||||
disabled={appliedFilters.filter((item) => item.isChecked == true).length == 0} />
|
||||
|
||||
<ActionButton
|
||||
text="Cancel"
|
||||
className={styles.button}
|
||||
onClick={props.onCancel} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilterList;
|
|
@ -0,0 +1,15 @@
|
|||
import { IStackTokens, mergeStyleSets } from "office-ui-fabric-react";
|
||||
|
||||
export const stackTokens: IStackTokens = { childrenGap: 20, maxWidth:1000 };
|
||||
|
||||
export const styles = mergeStyleSets({
|
||||
checkbox: {
|
||||
padding: 5,
|
||||
},
|
||||
selectAllCheckbox:{
|
||||
padding: 5
|
||||
},
|
||||
button: {
|
||||
margin: 10
|
||||
}
|
||||
});
|
|
@ -0,0 +1,221 @@
|
|||
import { DefaultButton, Dialog, DialogFooter, Dropdown, IDialogStyleProps, IDialogStyles, IDropdownOption, IDropdownStyles, IStackTokens, ITextFieldStyles, mergeStyleSets, PrimaryButton, Stack, TextField } from "office-ui-fabric-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { IColumnConfig } from "../../types/columnconfigtype";
|
||||
import { IFilter, IOperators, operatorsArr } from "../../types/filterstype";
|
||||
import { controlClass, dropdownStyles, modelProps, stackTokens, textFieldStyles } from "./columnfilterdialogStyles";
|
||||
|
||||
interface Props {
|
||||
columnConfigurationData: IColumnConfig[];
|
||||
gridData: any[];
|
||||
onDialogCancel?: any;
|
||||
onDialogSave?: any;
|
||||
}
|
||||
|
||||
const ColumnFilterDialog = (props : Props) => {
|
||||
//const [gridColumn, setGridColumn] = useState('');
|
||||
const [gridColumn, setGridColumn] = useState<IColumnConfig>();
|
||||
const [operator, setOperator] = useState('');
|
||||
const [value, setValue] = useState('');
|
||||
//const [filter, setFilter] = useState<IFilter>({ column:'', operator:'', value: '' });
|
||||
|
||||
const onSelectGridColumn = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined, index: number | undefined): void => {
|
||||
console.log(item)
|
||||
//setGridColumn(item!.key.toString());
|
||||
setGridColumn(props.columnConfigurationData.filter((val) => val.key == item!.key)[0]);
|
||||
// var filterTmp : IFilter = {...filter};
|
||||
// filterTmp.column = item!.key.toString();
|
||||
// setFilter(filterTmp);
|
||||
};
|
||||
|
||||
const onSelectOperator = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined, index: number | undefined): void => {
|
||||
debugger;
|
||||
console.log(item)
|
||||
setOperator(item!.text.toString());
|
||||
//var filterTmp : IFilter = {...filter};
|
||||
//filterTmp.operator = item!.text.toString();
|
||||
//setFilter(filterTmp);
|
||||
};
|
||||
|
||||
const onSelectValue = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined, index: number | undefined): void => {
|
||||
console.log(item)
|
||||
setValue(item!.key.toString());
|
||||
// var filterTmp : IFilter = {...filter};
|
||||
// filterTmp.value = item!.key.toString();
|
||||
// setFilter(filterTmp);
|
||||
};
|
||||
|
||||
const onTextUpdate = (ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, text: string): void => {
|
||||
console.log('Text Changed: ' + text);
|
||||
setValue(text);
|
||||
// var filterTmp : IFilter = {...filter};
|
||||
// filterTmp.value = text;
|
||||
// setFilter(filterTmp);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if(gridColumn && gridColumn.key && gridColumn.key.length > 0){
|
||||
var column = props.columnConfigurationData.filter(x => x.key == gridColumn!.key);
|
||||
if(column.length > 0){
|
||||
var valueOptions = createValueOptions(column[0]);
|
||||
switch(column[0].dataType){
|
||||
case 'number':
|
||||
setInputFieldContent(
|
||||
<TextField
|
||||
className={controlClass.textFieldClass}
|
||||
placeholder="Value"
|
||||
onChange={(ev, text) => onTextUpdate(ev, text!)}
|
||||
styles={textFieldStyles}
|
||||
/>
|
||||
);
|
||||
setOperatorDropDownContent(<Dropdown
|
||||
placeholder="Select the Column"
|
||||
options={createCompareOptions()}
|
||||
styles={dropdownStyles}
|
||||
onChange={onSelectOperator}
|
||||
/>);
|
||||
break;
|
||||
case 'string':
|
||||
setInputFieldContent(
|
||||
<TextField
|
||||
className={controlClass.textFieldClass}
|
||||
placeholder="Value"
|
||||
onChange={(ev, text) => onTextUpdate(ev, text!)}
|
||||
styles={textFieldStyles}
|
||||
/>
|
||||
);
|
||||
setOperatorDropDownContent(<Dropdown
|
||||
placeholder="Select the Column"
|
||||
options={createCompareOptions()}
|
||||
styles={dropdownStyles}
|
||||
onChange={onSelectOperator}
|
||||
/>);
|
||||
break;
|
||||
case 'date':
|
||||
setInputFieldContent(<Dropdown
|
||||
placeholder="Select the Column"
|
||||
options={valueOptions}
|
||||
styles={dropdownStyles}
|
||||
onChange={onSelectValue}
|
||||
/>)
|
||||
setOperatorDropDownContent(<Dropdown
|
||||
placeholder="Select the Column"
|
||||
options={createCompareOptions()}
|
||||
styles={dropdownStyles}
|
||||
onChange={onSelectOperator}
|
||||
/>);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}, [gridColumn]);
|
||||
|
||||
const createDropDownOptions = () : IDropdownOption[] => {
|
||||
let dropdownOptions: IDropdownOption[] = [];
|
||||
props.columnConfigurationData.forEach((item, index) => {
|
||||
dropdownOptions.push({ key: item.key, text: item.text});
|
||||
});
|
||||
|
||||
return dropdownOptions;
|
||||
}
|
||||
|
||||
const options = createDropDownOptions();
|
||||
|
||||
const createCompareOptions = () : IDropdownOption[] => {
|
||||
debugger;
|
||||
if(!(gridColumn && gridColumn.key && gridColumn.key.length > 0)){
|
||||
return [];
|
||||
}
|
||||
let dataType = props.columnConfigurationData.filter(x => x.key == gridColumn.key)[0].dataType;
|
||||
let dropdownOptions: IDropdownOption[] = [];
|
||||
let operatorsOptions : any[] = [];
|
||||
switch(dataType){
|
||||
case 'string':
|
||||
operatorsOptions = operatorsArr.filter((item) => item.type == 'string')[0].value;
|
||||
break;
|
||||
case 'number':
|
||||
operatorsOptions = operatorsArr.filter((item) => item.type == 'number')[0].value;
|
||||
break;
|
||||
}
|
||||
operatorsOptions.forEach((item, index) => {
|
||||
dropdownOptions.push({ key: item+index, text: item});
|
||||
});
|
||||
|
||||
return dropdownOptions;
|
||||
}
|
||||
|
||||
const createValueOptions = (column : IColumnConfig) : IDropdownOption[] => {
|
||||
var columnData = props.gridData.map((item) => item[column.key]);
|
||||
let dropdownOptions: IDropdownOption[] = [];
|
||||
columnData.forEach((item, index) => {
|
||||
dropdownOptions.push({ key: item+index, text: item});
|
||||
});
|
||||
|
||||
return dropdownOptions;
|
||||
};
|
||||
|
||||
//const compareOptions = createCompareOptions();
|
||||
|
||||
const [inputFieldContent, setInputFieldContent] = React.useState<JSX.Element | undefined>(
|
||||
<Dropdown
|
||||
placeholder="Select the Column"
|
||||
options={options}
|
||||
styles={dropdownStyles}
|
||||
onChange={onSelectValue}
|
||||
/>
|
||||
);
|
||||
|
||||
const [operatorDropDownContent, setOperatorDropDownContent] = React.useState<JSX.Element | undefined>(
|
||||
<Dropdown
|
||||
placeholder="Select the Column"
|
||||
options={createCompareOptions()}
|
||||
styles={dropdownStyles}
|
||||
onChange={onSelectValue}
|
||||
/>
|
||||
);
|
||||
|
||||
const closeDialog = React.useCallback((): void => {
|
||||
if(props.onDialogCancel){
|
||||
props.onDialogCancel();
|
||||
}
|
||||
|
||||
setInputFieldContent(undefined)
|
||||
}, []);
|
||||
|
||||
const saveDialog = (): void => {
|
||||
debugger;
|
||||
var filterObj : IFilter = { column: gridColumn!, operator: operator, value: value }
|
||||
if(props.onDialogSave){
|
||||
props.onDialogSave(filterObj);
|
||||
}
|
||||
|
||||
setInputFieldContent(undefined);
|
||||
};
|
||||
|
||||
return(
|
||||
<Dialog modalProps={modelProps} hidden={!inputFieldContent} onDismiss={closeDialog} closeButtonAriaLabel="Close">
|
||||
<Stack verticalAlign="start" tokens={stackTokens}>
|
||||
<Dropdown
|
||||
placeholder="Select the Column"
|
||||
options={options}
|
||||
styles={dropdownStyles}
|
||||
onChange={onSelectGridColumn}
|
||||
/>
|
||||
{operatorDropDownContent}
|
||||
{inputFieldContent}
|
||||
</Stack>
|
||||
<DialogFooter>
|
||||
<PrimaryButton
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={saveDialog}
|
||||
text="Save"
|
||||
/>
|
||||
<DefaultButton
|
||||
//onClick={closeDialog}
|
||||
text="Cancel" />
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default ColumnFilterDialog;
|
|
@ -0,0 +1,25 @@
|
|||
import { IDropdownStyles, IStackTokens, ITextFieldStyles, mergeStyleSets } from "office-ui-fabric-react";
|
||||
|
||||
export const dropdownStyles: Partial<IDropdownStyles> = {
|
||||
dropdown: { width: '90%', margin:10 },
|
||||
};
|
||||
|
||||
export const controlClass = mergeStyleSets({
|
||||
textFieldClass:{
|
||||
display: 'block',
|
||||
margin: 10,
|
||||
width: '90%'
|
||||
},
|
||||
datePickerClass:{
|
||||
display: 'block',
|
||||
margin: 10,
|
||||
width: '90%'
|
||||
}
|
||||
});
|
||||
|
||||
export const stackTokens: IStackTokens = { childrenGap: 20, maxWidth:1000 };
|
||||
export const textFieldStyles: Partial<ITextFieldStyles> = { fieldGroup: {} };
|
||||
export const modelProps = {
|
||||
isBlocking: false,
|
||||
styles: { main: { maxWidth: '100vh' }},
|
||||
};
|
|
@ -0,0 +1,161 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { DatePicker, DefaultButton, Dialog, DialogFooter, Dropdown, IDropdownOption, IDropdownStyles, IStackTokens, ITextFieldStyles, mergeStyleSets, PrimaryButton, Stack, TextField } from "office-ui-fabric-react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { IColumnConfig } from "../types/columnconfigtype";
|
||||
import { EditControlType } from "../types/editcontroltype";
|
||||
import { DayPickerStrings } from "./datepickerconfig";
|
||||
|
||||
interface Props {
|
||||
columnConfigurationData: IColumnConfig[];
|
||||
onDialogCancel?: any;
|
||||
onDialogSave?: any;
|
||||
}
|
||||
|
||||
const ColumnUpdateDialog = (props : Props) => {
|
||||
const controlClass = mergeStyleSets({
|
||||
textFieldClass:{
|
||||
display: 'block',
|
||||
margin: 10,
|
||||
width: '90%'
|
||||
},
|
||||
datePickerClass:{
|
||||
display: 'block',
|
||||
margin: 10,
|
||||
width: '90%'
|
||||
}
|
||||
});
|
||||
|
||||
const textFieldStyles: Partial<ITextFieldStyles> = { fieldGroup: {} };
|
||||
|
||||
|
||||
const [gridColumn, setGridColumn] = useState('');
|
||||
const [columnDialogValues, setColumnDialogValues] = useState({
|
||||
});
|
||||
|
||||
const stackTokens: IStackTokens = { childrenGap: 10 };
|
||||
const dropdownStyles: Partial<IDropdownStyles> = {
|
||||
dropdown: { width: '90%', margin:10 },
|
||||
};
|
||||
|
||||
const onTextUpdate = (ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, text: string): void => {
|
||||
console.log('Text Changed: ' + text);
|
||||
setColumnDialogValues({[gridColumn]: text});
|
||||
};
|
||||
|
||||
const [inputFieldContent, setInputFieldContent] = React.useState<JSX.Element | undefined>(
|
||||
<TextField
|
||||
className={controlClass.textFieldClass}
|
||||
placeholder="Value"
|
||||
onChange={(ev, text) => onTextUpdate(ev, text!)}
|
||||
styles={textFieldStyles}
|
||||
/>
|
||||
);
|
||||
|
||||
const onSelectDate = (date: Date | null | undefined): void => {
|
||||
setColumnDialogValues({[gridColumn] : date!.toDateString()});
|
||||
};
|
||||
|
||||
const onSelectGridColumn = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption | undefined): void => {
|
||||
console.log(item)
|
||||
setGridColumn(item!.key.toString());
|
||||
};
|
||||
|
||||
const closeDialog = React.useCallback((): void => {
|
||||
if(props.onDialogCancel){
|
||||
props.onDialogCancel();
|
||||
}
|
||||
|
||||
setInputFieldContent(undefined)
|
||||
}, []);
|
||||
|
||||
const saveDialog = (): void => {
|
||||
debugger;
|
||||
if(props.onDialogSave){
|
||||
props.onDialogSave(columnDialogValues);
|
||||
}
|
||||
|
||||
setInputFieldContent(undefined);
|
||||
};
|
||||
|
||||
const createDropDownOptions = () : IDropdownOption[] => {
|
||||
let dropdownOptions: IDropdownOption[] = [];
|
||||
props.columnConfigurationData.forEach((item, index) => {
|
||||
if(item.editable == true){
|
||||
dropdownOptions.push({ key: item.key, text: item.text});
|
||||
}
|
||||
});
|
||||
|
||||
return dropdownOptions;
|
||||
}
|
||||
|
||||
const options = createDropDownOptions();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
},[columnDialogValues]);
|
||||
|
||||
useEffect(() => {
|
||||
//debugger;
|
||||
setColumnDialogValues({[gridColumn]:''});
|
||||
var column = props.columnConfigurationData.filter(x => x.key == gridColumn);
|
||||
if(column.length > 0){
|
||||
switch(column[0].inputType){
|
||||
case EditControlType.TextField:
|
||||
setInputFieldContent(
|
||||
<TextField
|
||||
className={controlClass.textFieldClass}
|
||||
placeholder="Value"
|
||||
onChange={(ev, text) => onTextUpdate(ev, text!)}
|
||||
styles={textFieldStyles}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
case EditControlType.Date:
|
||||
setInputFieldContent(<DatePicker
|
||||
strings={DayPickerStrings}
|
||||
placeholder="Select a date..."
|
||||
ariaLabel="Select a date"
|
||||
className={controlClass.datePickerClass}
|
||||
onSelectDate={onSelectDate}
|
||||
/>);
|
||||
break;
|
||||
default:
|
||||
setInputFieldContent(
|
||||
<TextField
|
||||
className={controlClass.textFieldClass}
|
||||
placeholder="Value"
|
||||
onChange={(ev, text) => onTextUpdate(ev, text!)}
|
||||
styles={textFieldStyles}
|
||||
/>
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [gridColumn]);
|
||||
|
||||
return(
|
||||
<Dialog hidden={!inputFieldContent} onDismiss={closeDialog} closeButtonAriaLabel="Close">
|
||||
<Stack verticalAlign="start" tokens={stackTokens}>
|
||||
<Dropdown
|
||||
placeholder="Select the Column"
|
||||
options={options}
|
||||
styles={dropdownStyles}
|
||||
onChange={onSelectGridColumn}
|
||||
/>
|
||||
{inputFieldContent}
|
||||
</Stack>
|
||||
<DialogFooter>
|
||||
<PrimaryButton
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onClick={saveDialog}
|
||||
text="Save"
|
||||
/>
|
||||
<DefaultButton onClick={closeDialog} text="Cancel" />
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default ColumnUpdateDialog;
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IDatePickerStrings } from "office-ui-fabric-react";
|
||||
|
||||
export const DayPickerStrings: IDatePickerStrings = {
|
||||
months: [
|
||||
'January',
|
||||
'February',
|
||||
'March',
|
||||
'April',
|
||||
'May',
|
||||
'June',
|
||||
'July',
|
||||
'August',
|
||||
'September',
|
||||
'October',
|
||||
'November',
|
||||
'December',
|
||||
],
|
||||
shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
||||
|
||||
days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
||||
|
||||
shortDays: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
|
||||
|
||||
goToToday: 'Go to today',
|
||||
prevMonthAriaLabel: 'Go to previous month',
|
||||
nextMonthAriaLabel: 'Go to next month',
|
||||
prevYearAriaLabel: 'Go to previous year',
|
||||
nextYearAriaLabel: 'Go to next year',
|
||||
closeButtonAriaLabel: 'Close date picker',
|
||||
|
||||
isRequiredErrorMessage: 'Field is required.',
|
||||
|
||||
invalidInputErrorMessage: 'Invalid date format.',
|
||||
};
|
||||
|
||||
export function dateToISOLikeButLocal(date: any) {
|
||||
const offsetMs = date.getTimezoneOffset() * 60 * 1000;
|
||||
const msLocal = date.getTime() - offsetMs;
|
||||
const dateLocal = new Date(msLocal);
|
||||
const iso = dateLocal.toISOString();
|
||||
const isoLocal = iso.slice(0, 10);
|
||||
return isoLocal;
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,81 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { IColumn, ICommandBarItemProps, IconButton, TextField } from "office-ui-fabric-react";
|
||||
import React from "react";
|
||||
import { IColumnConfig } from "../types/columnconfigtype";
|
||||
import { Operation } from "../types/operation";
|
||||
import { controlClass, textFieldStyles } from "./editablegridstyles";
|
||||
import { initializeIcons } from 'office-ui-fabric-react';
|
||||
import { EditControlType } from "../types/editcontroltype";
|
||||
|
||||
initializeIcons(/* optional base url */);
|
||||
|
||||
export const InitializeInternalGrid = (items : any[]) : any[] => {
|
||||
return items.map((obj, index) => {
|
||||
if(Object.keys(obj).indexOf('_grid_row_id_') == -1 && Object.keys(obj).indexOf('_grid_row_operation_') == -1)
|
||||
{
|
||||
obj._grid_row_id_ = index;
|
||||
obj._grid_row_operation_ = Operation.None;
|
||||
obj._is_filtered_in_ = true;
|
||||
obj._is_filtered_in_grid_search_ = true;
|
||||
obj._is_filtered_in_column_filter_ = true;
|
||||
}
|
||||
return obj;
|
||||
})
|
||||
};
|
||||
|
||||
export const ResetGridRowID = (items : any[]) : any[] => {
|
||||
return items.map((obj, index) => {
|
||||
obj._grid_row_id_ = index;
|
||||
|
||||
return obj;
|
||||
});
|
||||
};
|
||||
|
||||
export const InitializeInternalGridEditStructure = (items : any[]) : any[] => {
|
||||
let activateCellEditTmp : any[] = [];
|
||||
items.forEach((item, index) => {
|
||||
let activateCellEditRowTmp : any = {'isActivated' : false, properties : {}};
|
||||
var objectKeys = Object.keys(item);
|
||||
objectKeys.forEach((objKey) => {
|
||||
activateCellEditRowTmp.properties[objKey] = {'activated' : false, 'value' : item[objKey]};
|
||||
})
|
||||
|
||||
activateCellEditTmp.push(activateCellEditRowTmp);
|
||||
});
|
||||
console.log(activateCellEditTmp);
|
||||
return activateCellEditTmp;
|
||||
};
|
||||
|
||||
export const ShallowCopyDefaultGridToEditGrid = (defaultGrid : any[], editGrid : any[]) : any[] => {
|
||||
debugger;
|
||||
defaultGrid.forEach((item, index) => {
|
||||
var objectKeys = Object.keys(item);
|
||||
objectKeys.forEach((objKey) => {
|
||||
editGrid[index].properties[objKey]['value'] = item[objKey];
|
||||
})
|
||||
});
|
||||
|
||||
return editGrid;
|
||||
};
|
||||
|
||||
export const ShallowCopyEditGridToDefaultGrid = (defaultGrid : any[], editGrid : any[]) : any[] => {
|
||||
editGrid.forEach((item) => {
|
||||
var index = defaultGrid.findIndex((row) => row._grid_row_id_ == item.properties._grid_row_id_.value);
|
||||
if(index >= 0){
|
||||
var objectKeys = Object.keys(item.properties);
|
||||
objectKeys.forEach((objKey) => {
|
||||
if(defaultGrid[index][objKey] != item.properties[objKey].value){
|
||||
defaultGrid[index][objKey] = item.properties[objKey].value;
|
||||
|
||||
if(defaultGrid[index]['_grid_row_operation_'] != Operation.Add && defaultGrid[index]['_grid_row_operation_'] != Operation.Update){
|
||||
defaultGrid[index]['_grid_row_operation_'] = Operation.Update;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
return defaultGrid;
|
||||
};
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { getTheme, IDetailsColumnStyles, IStackStyles, IStackTokens, ITextFieldStyles, mergeStyleSets } from "office-ui-fabric-react";
|
||||
import { ICellStyleRulesType } from "../types/cellstyleruletype";
|
||||
import { IColumnConfig } from "../types/columnconfigtype";
|
||||
import { EvaluateRule } from "./helper";
|
||||
|
||||
export const stackStyles: Partial<IStackStyles> = { root: { width: 500 } };
|
||||
|
||||
export const controlClass = mergeStyleSets({
|
||||
control: {
|
||||
marginBottom: '10px',
|
||||
marginRight: '30px',
|
||||
maxWidth: '300px',
|
||||
},
|
||||
searchStyles: {
|
||||
marginTop: '5px',
|
||||
},
|
||||
submitStyles: {
|
||||
marginTop: '20px',
|
||||
marginLeft: '10px',
|
||||
},
|
||||
buttonStyles: {
|
||||
margin: 5
|
||||
},
|
||||
textFieldClass:{
|
||||
display: 'block',
|
||||
margin: 10
|
||||
},
|
||||
spanStyles:{
|
||||
display:'inline-block',
|
||||
width:'100%',
|
||||
height:'100%',
|
||||
//lineHeight:'250%'
|
||||
},
|
||||
dialogSubMessageStyles : {
|
||||
margin: 10,
|
||||
},
|
||||
dialogHeaderStyles : {
|
||||
margin: 10,
|
||||
},
|
||||
submitStylesEditpanel: {
|
||||
marginTop: '20px',
|
||||
marginLeft: '10px',
|
||||
marginRight: '10px',
|
||||
maxWidth: '300px',
|
||||
},
|
||||
labelValue: {
|
||||
fontWeight: 'bold',
|
||||
}
|
||||
});
|
||||
|
||||
export const GetDynamicSpanStyles = (column : IColumnConfig, cellValue : number | string | undefined) : string => {
|
||||
|
||||
var styleRule = column.cellStyleRule ?? undefined;
|
||||
var isRuleTrue : boolean = EvaluateRule(column.dataType ?? 'string', cellValue, styleRule);
|
||||
var styles = mergeStyleSets({
|
||||
dynamicSpanStyle: {
|
||||
display:'inline-block',
|
||||
width:'100%',
|
||||
height:'100%',
|
||||
//textAlign:'center',
|
||||
color:(!column.cellStyleRule || !column.cellStyleRule.enable) ? undefined : (isRuleTrue ? styleRule?.whenTrue?.textColor : styleRule?.whenFalse?.textColor),
|
||||
//backgroundColor: (!column.cellStyleRule || !column.cellStyleRule.enable) ? undefined : (isRuleTrue ? styleRule?.whenTrue?.backgroundColor : styleRule?.whenFalse?.backgroundColor),
|
||||
//lineHeight:'250%',
|
||||
fontWeight:(!column.cellStyleRule || !column.cellStyleRule.enable) ? undefined : (isRuleTrue ? styleRule?.whenTrue?.fontWeight : styleRule?.whenFalse?.fontWeight)
|
||||
}
|
||||
});
|
||||
return styles.dynamicSpanStyle;
|
||||
}
|
||||
|
||||
export const verticalGapStackTokens: IStackTokens = {
|
||||
childrenGap: 15,
|
||||
padding: 10,
|
||||
};
|
||||
|
||||
export const horizontalGapStackTokens: IStackTokens = {
|
||||
childrenGap: 10,
|
||||
padding: 10,
|
||||
};
|
||||
|
||||
export const textFieldStyles: Partial<ITextFieldStyles> = { fieldGroup: {} };
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { DatePicker, IStackStyles, IStackTokens, ITextFieldStyles, mergeStyleSets, PrimaryButton, Stack, TextField } from "office-ui-fabric-react";
|
||||
import React, { useState } from "react";
|
||||
import { IColumnConfig } from "../types/columnconfigtype";
|
||||
import { EditControlType } from "../types/editcontroltype";
|
||||
import { DayPickerStrings } from "./datepickerconfig";
|
||||
import { controlClass, horizontalGapStackTokens, stackStyles, textFieldStyles, verticalGapStackTokens } from "./editablegridstyles";
|
||||
import { IsValidDataType } from "./helper";
|
||||
|
||||
interface Props {
|
||||
onChange: any;
|
||||
columnConfigurationData: IColumnConfig[];
|
||||
}
|
||||
|
||||
const EditPanel = (props: Props) => {
|
||||
const updateObj : any = {};
|
||||
|
||||
const onTextUpdate = (ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, text: string, column : IColumnConfig): void => {
|
||||
debugger;
|
||||
if(!IsValidDataType(column.dataType, text) || text.trim() == ''){
|
||||
return;
|
||||
}
|
||||
|
||||
updateObj[(ev.target as Element).id] = text;
|
||||
};
|
||||
|
||||
const onPanelSubmit = (): void => {
|
||||
console.log(updateObj);
|
||||
props.onChange(updateObj);
|
||||
};
|
||||
|
||||
const onCellDateChange = (date: Date | null | undefined, item : any): void => {
|
||||
updateObj[item.key] = date;
|
||||
};
|
||||
|
||||
const createTextFields = () : any[] => {
|
||||
let tmpRenderObj : any[] = [];
|
||||
props.columnConfigurationData.forEach((item, index) => {
|
||||
if(item.editable == true){
|
||||
switch(item.inputType){
|
||||
case EditControlType.Date:
|
||||
tmpRenderObj.push(<DatePicker
|
||||
label={item.text}
|
||||
strings={DayPickerStrings}
|
||||
placeholder="Select a date..."
|
||||
ariaLabel="Select a date"
|
||||
onSelectDate={(date) => onCellDateChange(date, item)}
|
||||
//value={props != null && props.panelValues != null ? new Date(props.panelValues[item.key]) : new Date()}
|
||||
value={new Date()}
|
||||
/>);
|
||||
break;
|
||||
default:
|
||||
tmpRenderObj.push(<TextField
|
||||
name={item.text}
|
||||
id={item.key}
|
||||
label={item.text}
|
||||
styles={textFieldStyles}
|
||||
onChange={(ev, text) => onTextUpdate(ev, text!, item)}
|
||||
defaultValue = { '' }
|
||||
/>);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
console.log(tmpRenderObj);
|
||||
return tmpRenderObj;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Stack tokens={verticalGapStackTokens}>
|
||||
{createTextFields()}
|
||||
</Stack>
|
||||
<Stack horizontal disableShrink styles={stackStyles} tokens={horizontalGapStackTokens}>
|
||||
<PrimaryButton
|
||||
text="Save To Grid"
|
||||
className={controlClass.submitStylesEditpanel}
|
||||
onClick={onPanelSubmit}
|
||||
allowDisabledFocus
|
||||
/>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default EditPanel;
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { ExportType } from "../types/exporttype";
|
||||
import * as XLSX from 'xlsx';
|
||||
import * as FileSaver from 'file-saver';
|
||||
|
||||
export const ExportToExcelUtil = (exportData : any[], fileName : string): void =>
|
||||
{
|
||||
let fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
|
||||
|
||||
const ws = XLSX.utils.json_to_sheet(exportData);
|
||||
const wb = { Sheets: { 'data': ws }, SheetNames: ['data'] };
|
||||
const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
||||
const data = new Blob([excelBuffer], {type: fileType});
|
||||
FileSaver.saveAs(data, fileName);
|
||||
}
|
||||
|
||||
export const ExportToCSVUtil = (exportData : any[], fileName : string) : void => {
|
||||
if (!exportData || !exportData.length) {
|
||||
return;
|
||||
}
|
||||
const separator = ',';
|
||||
const keys = Object.keys(exportData[0]);
|
||||
const csvContent =
|
||||
keys.join(separator) +
|
||||
'\n' +
|
||||
exportData.map(row => {
|
||||
return keys.map(k => {
|
||||
let cell = row[k] === null || row[k] === undefined ? '' : row[k];
|
||||
cell = cell instanceof Date
|
||||
? cell.toLocaleString()
|
||||
: cell.toString().replace(/"/g, '""');
|
||||
if (cell.search(/("|,|\n)/g) >= 0) {
|
||||
cell = `"${cell}"`;
|
||||
}
|
||||
return cell;
|
||||
}).join(separator);
|
||||
}).join('\n');
|
||||
|
||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||
if (navigator.msSaveBlob) { // IE 10+
|
||||
navigator.msSaveBlob(blob, fileName);
|
||||
} else {
|
||||
const link = document.createElement('a');
|
||||
if (link.download !== undefined) {
|
||||
// Browsers that support HTML5 download attribute
|
||||
const url = URL.createObjectURL(blob);
|
||||
link.setAttribute('href', url);
|
||||
link.setAttribute('download', fileName);
|
||||
link.style.visibility = 'hidden';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
import { ICellStyleRulesType } from "../types/cellstyleruletype";
|
||||
import { IGridColumnFilter } from "../types/columnfilterstype";
|
||||
import { dateOperatorEval, IFilter, numberOperatorEval, stringOperatorEval } from "../types/filterstype";
|
||||
|
||||
export const filterGridData = (data : any[], filters : IFilter[]) : any[] => {
|
||||
debugger;
|
||||
var dataTmp : any[] = [...data];
|
||||
dataTmp.forEach((row) => {
|
||||
var isRowIncluded : boolean = true;
|
||||
filters.forEach((item) => {
|
||||
if(isRowIncluded){
|
||||
var columnType = item.column.dataType;
|
||||
switch(columnType){
|
||||
case 'number':
|
||||
isRowIncluded = isRowIncluded && numberOperatorEval(row[item.column.key], item.value, item.operator);
|
||||
break;
|
||||
case 'string':
|
||||
isRowIncluded = isRowIncluded && stringOperatorEval(row[item.column.key], item.value, item.operator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(isRowIncluded){
|
||||
row._is_filtered_in_ = true;
|
||||
}
|
||||
else{
|
||||
row._is_filtered_in_ = false;
|
||||
}
|
||||
});
|
||||
|
||||
return dataTmp;
|
||||
}
|
||||
|
||||
export const applyGridColumnFilter = (data : any[], gridColumnFilterArr : IGridColumnFilter[]) : any[] => {
|
||||
debugger;
|
||||
var dataTmp : any[] = [...data];
|
||||
if(gridColumnFilterArr.filter((item) => item.isApplied == true).length > 0){
|
||||
dataTmp.map((row) => row._is_filtered_in_column_filter_ = true);
|
||||
}
|
||||
|
||||
gridColumnFilterArr.filter((gridColumnFilter) => gridColumnFilter.isApplied == true).forEach((gridColumnFilter, index) => {
|
||||
dataTmp.filter((row) => row._is_filtered_in_column_filter_ == true).forEach((row, i) => {
|
||||
row._is_filtered_in_column_filter_ = gridColumnFilter.filterCalloutProps!.filterList.filter(a => a.isChecked == true).map(a => a.text).includes(row[gridColumnFilter.column.key]);
|
||||
});
|
||||
});
|
||||
|
||||
return dataTmp;
|
||||
}
|
||||
|
||||
export const isColumnDataTypeSupportedForFilter = (datatype : string | undefined) : boolean => {
|
||||
switch(datatype){
|
||||
case 'number':
|
||||
return true;
|
||||
case 'string':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const IsValidDataType = (type : string | undefined, text : string) : boolean => {
|
||||
var isValid = true;
|
||||
switch(type){
|
||||
case 'number':
|
||||
isValid = !isNaN(Number(text));
|
||||
break;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
};
|
||||
|
||||
export const EvaluateRule = (datatType : string, cellValue: string | number | undefined, styleRule: ICellStyleRulesType | undefined): boolean => {
|
||||
if(!styleRule){
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(datatType){
|
||||
case 'number':
|
||||
return numberOperatorEval(Number(cellValue), styleRule?.rule!.value as number, styleRule?.rule!.operator);
|
||||
case 'string':
|
||||
return stringOperatorEval(String(cellValue), styleRule?.rule!.value as string, styleRule?.rule!.operator)
|
||||
case 'date':
|
||||
return dateOperatorEval(new Date(String(cellValue)), new Date(styleRule?.rule!.value), styleRule?.rule!.operator);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { DefaultButton, Dialog, DialogFooter, mergeStyleSets } from "office-ui-fabric-react";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
interface Props {
|
||||
message?: string;
|
||||
subMessage?: string;
|
||||
onDialogClose?: any;
|
||||
}
|
||||
|
||||
const MessageDialog = (props : Props) => {
|
||||
const [messageDialogContent, setMessageDialogContent] = React.useState<JSX.Element | undefined>(undefined);
|
||||
const closeDialog = React.useCallback((): void => {
|
||||
if(props.onDialogClose){
|
||||
props.onDialogClose();
|
||||
}
|
||||
setMessageDialogContent(undefined);
|
||||
}, []);
|
||||
|
||||
const controlClass = mergeStyleSets({
|
||||
dialogSubMessageStyles : {
|
||||
margin: 10,
|
||||
},
|
||||
dialogHeaderStyles : {
|
||||
margin: 10,
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setMessageDialogContent(
|
||||
<>
|
||||
<div>
|
||||
<h3 className={controlClass.dialogHeaderStyles}>{props && props.message ? props.message : ''}</h3>
|
||||
<div className={controlClass.dialogSubMessageStyles}>
|
||||
{props && props.subMessage ? props.subMessage : ''}
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DefaultButton onClick={() => closeDialog()} text="Close" />
|
||||
</DialogFooter>
|
||||
</>,
|
||||
);
|
||||
}, [props]);
|
||||
|
||||
return(
|
||||
<Dialog hidden={!messageDialogContent} onDismiss={closeDialog} closeButtonAriaLabel="Close">
|
||||
{messageDialogContent}
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default MessageDialog;
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
export const EventType = {
|
||||
onSearch: 'onSearch',
|
||||
onClick: 'onClick'
|
||||
};
|
||||
|
||||
export const EventEmitter = {
|
||||
events: {},
|
||||
|
||||
subscribe: function(event, callback) {
|
||||
if (!this.events[event]) this.events[event] = [];
|
||||
if (this.events[event].some(c => c === callback)) {
|
||||
console.warn(event + ' Already subscribed by ');
|
||||
console.log(callback);
|
||||
return;
|
||||
}
|
||||
this.events[event].push(callback);
|
||||
},
|
||||
|
||||
unsubscribe: function(event, callback) {
|
||||
this.events[event] = this.events[event].filter(c => c !== callback);
|
||||
},
|
||||
|
||||
dispatch: function(event, data) {
|
||||
if (!this.events[event]) return;
|
||||
this.events[event].forEach(callback => callback(data));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
export { default as EditableGrid } from "./editablegrid/editablegrid";
|
||||
export type { ICallBackParams, ICallBackRequestParams } from "./types/callbackparams";
|
||||
export type { IColumnConfig } from "./types/columnconfigtype";
|
||||
export { EditControlType } from "./types/editcontroltype";
|
||||
export type { IGridItemsType } from "./types/griditemstype";
|
||||
export { EventEmitter, EventType } from "./eventemitter/EventEmitter";
|
||||
export { NumberAndDateOperators, StringOperators } from './types/cellstyleruletype';
|
||||
export type { ICellStyleRulesType } from './types/cellstyleruletype';
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
export enum CalculationType {
|
||||
Addition,
|
||||
Subtraction,
|
||||
Multiplication,
|
||||
Division
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
export interface ICallBackRequestParams extends ICallBackParams {
|
||||
callbackhook : any;
|
||||
}
|
||||
|
||||
export interface ICallBackParams {
|
||||
data : any[];
|
||||
rowindex: Number[];
|
||||
triggerkey: string;
|
||||
activatetriggercell: boolean;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
export interface ICellStyleRulesType {
|
||||
enable?: boolean;
|
||||
rule?: IStringCellValueRule | INumberCellValueRule;
|
||||
whenTrue?: ICellStyle;
|
||||
whenFalse?: ICellStyle;
|
||||
}
|
||||
|
||||
export interface IStringCellValueRule {
|
||||
operator: StringOperators;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface INumberCellValueRule {
|
||||
operator: NumberAndDateOperators;
|
||||
value: number | Date;
|
||||
}
|
||||
|
||||
export enum StringOperators {
|
||||
EQUALS = 'equals',
|
||||
CONTAINS = 'contains',
|
||||
STARTSWITH = 'starts with',
|
||||
ENDSWITH = 'ends with',
|
||||
NOTEQUALTO = 'not equal to'
|
||||
}
|
||||
|
||||
export enum NumberAndDateOperators {
|
||||
GREATERTHAN = '>',
|
||||
LESSTHAN = '<',
|
||||
GREATERTHANOREQUALTO = '>=',
|
||||
LESSTHANOREQUALTO = '<=',
|
||||
EQUALTO = '=',
|
||||
NOTEQUALTO = '!='
|
||||
}
|
||||
|
||||
export interface ICellStyle {
|
||||
textColor?: string;
|
||||
//backgroundColor: string;
|
||||
fontWeight?: string;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { ConstrainMode, IColumn, IDetailsHeaderProps } from 'office-ui-fabric-react/lib/components/DetailsList/DetailsList.types';
|
||||
import { CalculationType } from "./calculationtype";
|
||||
import { ICellStyleRulesType } from './cellstyleruletype';
|
||||
import { EditControlType } from "./editcontroltype";
|
||||
|
||||
export interface IColumnConfig extends IColumn {
|
||||
key: string;
|
||||
text: string;
|
||||
editable?: boolean;
|
||||
dataType?: string;
|
||||
isResizable?: boolean;
|
||||
includeColumnInExport?: boolean;
|
||||
includeColumnInSearch?: boolean;
|
||||
inputType?: EditControlType;
|
||||
calculatedColumn?: { type: CalculationType, fields: any[] };
|
||||
onChange?: any;
|
||||
maxLength?: number;
|
||||
applyColumnFilter?: boolean;
|
||||
cellStyleRule?: ICellStyleRulesType;
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
import { IColumnConfig } from "./columnconfigtype";
|
||||
|
||||
export interface IFilterItem {
|
||||
text: any;
|
||||
isChecked: boolean;
|
||||
}
|
||||
|
||||
export interface IFilterListItem extends IFilterItem {
|
||||
key : number;
|
||||
isFilteredIn : boolean;
|
||||
}
|
||||
|
||||
export interface IFilterListProps {
|
||||
columnKey: string;
|
||||
columnName: string;
|
||||
filterList : IFilterItem[];
|
||||
}
|
||||
|
||||
export interface IFilterCalloutProps extends IFilterListProps {
|
||||
columnClass: string;
|
||||
}
|
||||
|
||||
export interface IGridColumnFilter {
|
||||
index: number;
|
||||
column: IColumnConfig;
|
||||
isApplied: boolean;
|
||||
isHidden: boolean;
|
||||
filterCalloutProps?: IFilterCalloutProps;
|
||||
}
|
||||
|
||||
export interface IColumnFilterValues{
|
||||
column: IColumnConfig;
|
||||
value: any[];
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
import { ConstrainMode } from "office-ui-fabric-react/lib/components/DetailsList";
|
||||
import { IDetailsListProps } from "office-ui-fabric-react/lib/components/DetailsList/DetailsList";
|
||||
import { IColumnConfig } from "./columnconfigtype";
|
||||
import { IRowAddWithValues } from "./rowaddtype";
|
||||
|
||||
export interface Props extends IDetailsListProps {
|
||||
id: number;
|
||||
items: any[];
|
||||
columns: IColumnConfig[];
|
||||
enableExport?: boolean;
|
||||
exportFileName?: string;
|
||||
enableSave?: boolean;
|
||||
enableRowEdit?: boolean;
|
||||
enableRowEditCancel?: boolean;
|
||||
enableColumnEdit?: boolean;
|
||||
enableBulkEdit?: boolean;
|
||||
enableCellEdit?: boolean;
|
||||
onGridSelectionChange?: any;
|
||||
onGridUpdate?:any;
|
||||
onGridSave?:any
|
||||
enableGridRowsDelete? : boolean;
|
||||
enableGridRowsAdd?: boolean;
|
||||
enableRowAddWithValues?: IRowAddWithValues;
|
||||
enableTextFieldEditMode?: boolean;
|
||||
enableTextFieldEditModeCancel?: boolean;
|
||||
enablePagination?: boolean;
|
||||
pageSize?: number;
|
||||
onExcelExport?: any;
|
||||
height?: string;
|
||||
width? : string;
|
||||
position?: string;
|
||||
constrainMode?:ConstrainMode;
|
||||
enableUnsavedEditIndicator?: boolean;
|
||||
enableGridReset?: boolean;
|
||||
enableColumnFilterRules?: boolean;
|
||||
enableColumnFilters?: boolean;
|
||||
enableCommandBar?: boolean;
|
||||
enableSingleClickCellEdit?: boolean;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
export enum EditControlType {
|
||||
None,
|
||||
TextField,
|
||||
DropDown,
|
||||
Date,
|
||||
MultilineTextField,
|
||||
DateTime
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
export enum EditType {
|
||||
None,
|
||||
ColumnEdit,
|
||||
BulkEdit,
|
||||
RowEdit,
|
||||
DeleteRow,
|
||||
AddRow,
|
||||
ColumnFilter,
|
||||
AddRowWithData
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
export enum ExportType {
|
||||
XLSX,
|
||||
CSV,
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
import { IColumnConfig } from "./columnconfigtype";
|
||||
|
||||
export interface IOperators{
|
||||
type: string;
|
||||
value: string[];
|
||||
}
|
||||
|
||||
export interface IFilter{
|
||||
column: IColumnConfig;
|
||||
operator: string;
|
||||
value: any;
|
||||
}
|
||||
|
||||
export const operatorsArr : IOperators[] = [
|
||||
{
|
||||
type:'string',
|
||||
value:['equals', 'contains', 'starts with', 'ends with', 'not equal to']
|
||||
},
|
||||
{
|
||||
type:'number',
|
||||
value:['>', '<', '>=', '<=', '=', '!=']
|
||||
}
|
||||
]
|
||||
|
||||
export const operatorEval1 = {
|
||||
'equals': (a : string, b : string) : boolean => { return a == b },
|
||||
'contains': (a : string, b : string) : boolean => { return a.indexOf(b) >= 0 },
|
||||
'starts with': (a : string, b : string) : boolean => { return a.startsWith(b) },
|
||||
'ends with': (a : string, b : string) : boolean => { return a.endsWith(b) },
|
||||
'not equal to': (a : string, b : string) : boolean => { return a != b },
|
||||
'>': (a : number, b : number) : boolean => { return a > b },
|
||||
'<': (a : number, b : number) : boolean => { return a < b },
|
||||
'>=': (a : number, b : number) : boolean => { return a >= b },
|
||||
'<=': (a : number, b : number) : boolean => { return a <= b },
|
||||
'=': (a : number, b : number) : boolean => { return a == b },
|
||||
'!=': (a : number, b : number) : boolean => { return a != b },
|
||||
}
|
||||
|
||||
export const numberOperatorEval = (var1 : number, var2 : number, operator : string) : boolean => {
|
||||
switch(operator){
|
||||
case '>':
|
||||
return var1 > var2;
|
||||
case '<':
|
||||
return var1 < var2;
|
||||
case '>=':
|
||||
return var1 >= var2;
|
||||
case '<=':
|
||||
return var1 <= var2;
|
||||
case '=':
|
||||
return var1 == var2;
|
||||
case '!=':
|
||||
return var1 != var2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const dateOperatorEval = (var1 : Date, var2 : Date, operator : string) : boolean => {
|
||||
switch(operator){
|
||||
case '>':
|
||||
return var1 > var2;
|
||||
case '<':
|
||||
return var1 < var2;
|
||||
case '>=':
|
||||
return var1 >= var2;
|
||||
case '<=':
|
||||
return var1 <= var2;
|
||||
case '=':
|
||||
return var1 == var2;
|
||||
case '!=':
|
||||
return var1 != var2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const stringOperatorEval = (var1 : string, var2 : string, operator : string) : boolean => {
|
||||
switch(operator){
|
||||
case 'equals':
|
||||
return var1 == var2;
|
||||
case 'contains':
|
||||
return var1.indexOf(var2) >= 0;
|
||||
case 'starts with':
|
||||
return var1.startsWith(var2);
|
||||
case 'ends with':
|
||||
return var1.endsWith(var2);
|
||||
case 'not equal to':
|
||||
return var1 != var2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import { Operation } from "./operation";
|
||||
|
||||
export interface IGridItemsType {
|
||||
_grid_row_id_ : number;
|
||||
_grid_row_operation_ : Operation;
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
export enum Operation{
|
||||
None = 1,
|
||||
Add,
|
||||
Update,
|
||||
Delete
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export interface IRowAddWithValues {
|
||||
enable? : boolean;
|
||||
enableRowsCounterInPanel? : boolean;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
|
||||
<g fill="#61DAFB">
|
||||
<path
|
||||
d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z" />
|
||||
<circle cx="420.9" cy="296.5" r="45.7" />
|
||||
<path d="M520.5 78.1z" />
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 2.6 KiB |
|
@ -0,0 +1 @@
|
|||
/// <reference types="react-scripts" />
|
|
@ -0,0 +1,15 @@
|
|||
import { ReportHandler } from 'web-vitals';
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
|
@ -0,0 +1,5 @@
|
|||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"downlevelIteration": true,
|
||||
"declaration": true,
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [
|
||||
"src/libs"
|
||||
]
|
||||
}
|
Загрузка…
Ссылка в новой задаче