How to customize default export option in material-table - reactjs

I am using material-table and I want to remove the default CSV & PDF export option.
I would like to have only an excel option.
How can I change the menu ?
Thank you

For custom CSV and PDF, you should define options
options={{
exportButton: {
csv: true,
pdf: true,
}
}}
and for the handlers should be defined more options
options={{
exportButton: {
csv: true,
pdf: true,
},
exportCsv: (data, columns) => console.log(data, columns, '<== CSV'),
exportPdf: (data, columns) => console.log(data, columns, '<== PDF'),
}}
in the handler function for the CSV you can use filefy package
import { CsvBuilder } from 'filefy';
and for PDF you can use jspdf and jspdf-autotable packages
import jsPDF from 'jspdf';
import 'jspdf-autotable';
also handler examples
exportCsv: (data, columns) => {
const columnTitles = columns
.map(columnDef => columnDef.title);
const csvData = data.map(rowData =>
columns.map(columnDef => rowData[columnDef.field]),
);
const builder = new CsvBuilder(`data.csv`)
.setColumns(columnTitles)
.addRows(csvData)
.exportFile();
return builder;
}
exportPdf: (data, columns) => {
const doc = new jsPDF();
const columnTitles = columns
.map(columnDef => columnDef.title);
const pdfData = data.map(rowData =>
columns.map(columnDef => rowData[columnDef.field]),
);
doc.autoTable({
head: [columnTitles],
body: pdfData,
});
doc.save(`data.pdf`);
}

Defining options on the MT component like this will allow you to show/hide each option:
options={{
// ..other options
exportButton: {
csv: true,
pdf: false
}
}}
Also, you could use localization settings to rename the label of each option like this:
localization={{
toolbar: {
exportCSVName: "Export some Excel format",
exportPDFName: "Export as pdf!!"
}
}}
It looks like the official docs are a bit outdated, so I found the answer to what you were looking for on these threads in GitHub:
exportButton
localization
Working sandbox here. Good luck!

Related

TradingView widget, advanced chart, not showing in React

I am trying to implement the Advanced chart widget of TradingView in my web application, that is created in React/Javascript, using primereact. I have tried several options before, and the only thing that worked so far was by importing the TradingViewEmbed from "react-tradingview-embed". Unfortunately it only worked with the old version "1.0.2", that has the old advertisement bar in it and also the banner below.
In order to remove those and implement it the way TradingView states I have done the below:
import React, { useEffect } from "react";
import './market-data.css';
const MarketData = () => {
const useScript = url => {
useEffect(() => {
const script = document.createElement('script');
script.src = url;
script.async = true;
document.body.appendChild(script);
return () => {
document.body.removeChild(script);
}
}, [url]);
};
return (
<div className="tradingview-widget-container">
{useScript('https://s3.tradingview.com/tv.js')}
<div id="tradingview_dc023"></div>
<div className="tradingview-widget-copyright"></div>
<script type="text/javascript" nonce>
{
new window.TradingView.widget(
{
autosize: true,
symbol: "FX_IDC:EURUSD",
timezone: "Europe/Amsterdam",
theme: "dark",
style: "2",
enable_publishing: false,
hide_top_toolbar: false,
hide_legend: false,
withdateranges: true,
range: "1D",
hide_side_toolbar: true,
allow_symbol_change: true,
save_image: false,
watchlist: [
"FX_IDC:EURUSD",
"FX_IDC:EURGBP",
"FX_IDC:EURJPY"
],
details: true,
hotlist: false,
calendar: true,
studies: [],
height: "100%",
width: "100%",
container_id: "tradingview_dc023"
})
}
</script>
</div>
)
}
export default MarketData;
Looking at the inspect of the web application it looks fine to me, but the chart/widget is just not showing.
tv.js is loaded:
tv.js
script is loaded and shows the way TradingView states on its website:
script
Could anybody please help and direct me in the right way of fixing this?

CK Editor 5 custom build onChange not working

I am using ck editor 5 online build tool to build a custom build of CK Editor 5. Successfully added it as a dependency of react project.
Included Mention plugin and other default plugins
import Editor from "ckeditor5-custom-build/build/ckeditor";
<CKEditor
disabled={props.readOnly}
editor={Editor}
data={props.value ? props.value : ""}
config={{
readOnly: props.readOnly,
mention: {
feeds: [
{
marker: "#",
feed: getPersonByName,
minimumCharacters: 1,
},
],
},
toolbar: [],
}}
onChange={(_event: any, editor: { getData: () => any }) => {
const data = editor.getData();
handleChange(editor);
}}
onBlur={(_event: any, _editor: any) => {}}
onFocus={(_event: any, _editor: any) => {}}
/>
mention plugin work as expected. but editors onChange event not firing.so I could not get the editor value.
ckeditor.js:5
CKEditorError: editor-isreadonly-has-no-setter
Updating the React version to the latest version (18.0.0) would be fixed the issue

Fetch data for ag-grid in Remix

I'm learning Remix.run and trying to figure out how to face some requirements
in advance. According to the documentation there is something called Resource Routes. But seems that a Resource Route need to be linked from a Link component:
<Link to="pdf" reloadDocument>
View as PDF
</Link>
I can't found any example showing how to create a simple route that can return data for a grid component, for example ag-grid.
There is any way to do this inside Remix or I will need to implement an external endpoint?
AG Grid wrote a blog post about this not too long ago. Here is the article: https://blog.ag-grid.com/using-ag-grid-react-ui-with-remix-run/.
First, set up a resource route using Remix's conventions outlined here: https://remix.run/docs/en/v1/guides/resource-routes#creating-resource-routes
The resource route should export only a loader function that retrieves the data you want to load into the table.
Note: This example also uses logic for infinite scrolling
app/routes/posts/$id/postsGridData.ts
import type { LoaderFunction } from 'remix';
import { db } from '~/utils/db.server'; // Prisma ORM being used
export const loader: LoaderFunction = ({ request }) => {
const from = Number(new URL(request.url).searchParams.get("from"));
const to = Number(new URL(request.url).searchParams.get("to"));
if (from >= 0 && to > 0) {
const posts = await db.post.findMany({
skip: from,
take: to - from,
select: {
id: true,
title: true,
updatedAt: true,
author: {
select: {
email: true,
name: true,
},
},
},
});
return posts;
}
return [];
}
Next, in the route with your AGGridReact component, you'll add the following:
A Remix Fetcher to get the data from your resource route without a route change
An onGridReady function that loads the next batch of data
Some local state to manage the fetching logic
A datasource to plug into AG Grid
A useEffect function to trigger when the fetcher has loaded
AgGridReact component with added parameters rowModelType and onGridReady
app/routes/posts.tsx
import { useFetcher } from 'remix';
import { useCallback, useEffect, useState } from 'react';
import { AgGridReact } from "ag-grid-react";
import AgGridStyles from "ag-grid-community/dist/styles/ag-grid.css";
import AgThemeAlpineStyles from "ag-grid-community/dist/styles/ag-theme-alpine.css";
export default function PostsRoute() {
const [isFetching, setIsFetching] = useState(false);
const [getRowParams, setGetRowParams] = useState(null);
const posts = useFetcher();
const onGridReady = useCallback((params) => {
const datasource = {
getRows(params) {
if (!isFetching) {
posts.load(`/posts?from=${params.startRow}&to=${params.endRow}`);
setGetRowParams(params);
setIsFetching(true);
}
},
};
params.api.setDatasource(datasource);
}, []);
useEffect(() => {
// The useEffect hook in this code will trigger when the fetcher has
// loaded new data. If a successCallback is available, it’ll call it,
// passing the loaded data and the last row to load
if (getRowParams) {
const data = posts.data || [];
getRowParams.successCallback(
data,
data.length < getRowParams.endRow - getRowParams.startRow
? getRowParams.startRow
: -1
);
}
setIsFetching(false);
setGetRowParams(null);
}, [posts.data, getRowParams]);
const columnDefs = [/* Your columnDefs */];
return (
<div className="ag-theme-alpine" style={{ width: "100%", height: "100%" }}>
<AgGridReact
columnDefs={columnDefs}
rowModelType="infinite"
onGridReady={onGridReady}
/>
</div>
);
}

Gatsby fetching Wordpress Custom Post Types and create pages

I read the documentation and tried several tutorials, but I am stuck on fetching custom post types with GatsbyJS.
I tried several approaches, but none of them are working as expected. I always receive a 404.
This is a part of the snippet I am using, which works fine with pages and posts, but not with a custom post type.
The projects pages should be created under a project subfolder/path. Like: example.com/project/my-first-project
The part of the gatsby-node.js looks like that:
const createSinglePages = async ({ posts, gatsbyUtilities }) =>
Promise.all(
posts.map(({ previous, post, next }) =>
// createPage is an action passed to createPages
// See https://www.gatsbyjs.com/docs/actions#createPage for more info
gatsbyUtilities.actions.createPage({
// Use the WordPress uri as the Gatsby page path
// This is a good idea so that internal links and menus work 👍
path: post.uri,
// use the blog post template as the page component
component: path.resolve(
`./src/templates/${post.__typename.replace(`Wp`, ``)}.js`
),
// `context` is available in the template as a prop and
// as a variable in GraphQL.
context: {
// we need to add the post id here
// so our blog post template knows which blog post
// the current page is (when you open it in a browser)
id: post.id,
// We also use the next and previous id's to query them and add links!
previousPostId: previous ? previous.id : null,
nextPostId: next ? next.id : null,
},
})
)
);
The src/template/project.js file looks like this:
import React from "react";
import { Link, graphql } from "gatsby";
import Image from "gatsby-image";
import parse from "html-react-parser";
import Layout from "../components/Layout";
import Seo from "../components/Seo";
const ProjectTemplate = ({ data: { post } }) => {
const featuredImage = {
fluid: post.featuredImage?.node?.localFile?.childImageSharp?.fluid,
alt: post.featuredImage?.node?.alt || ``,
};
return (
<Layout>
<Seo title={post.title} description={post.excerpt} />
<article
className="blog-post"
itemScope
itemType="http://schema.org/Article"
>
<header>
<h1 itemProp="headline">{parse(post.title)}</h1>
<p>{post.date}</p>
{/* if we have a featured image for this post let's display it */}
{featuredImage?.fluid && (
<Image
fluid={featuredImage.fluid}
alt={featuredImage.alt}
style={{ marginBottom: 50 }}
/>
)}
</header>
{!!post.content && (
<section itemProp="articleBody">{parse(post.content)}</section>
)}
</article>
</Layout>
);
};
export default ProjectTemplate;
export const pageQuery = graphql`
query ProjectById(
# these variables are passed in via createPage.pageContext in gatsby-node.js
$id: String!
) {
# selecting the current post by id
post: wpProject(id: { eq: $id }) {
id
content
title
date(formatString: "MMMM DD, YYYY")
featuredImage {
node {
altText
localFile {
childImageSharp {
fluid(maxWidth: 1000, quality: 100) {
...GatsbyImageSharpFluid_tracedSVG
}
}
}
}
}
}
}
`;
Is the Gatsby API creating a subfolder automatically, or do I need to define that somewhere for each post type?
Any help appreciated!
You define the "subfolder" under the path field in:
gatsbyUtilities.actions.createPage({
path: post.uri,
component: path.resolve(
`./src/templates/${post.__typename.replace(`Wp`, ``)}.js`
),
context: {
id: post.id,
previousPostId: previous ? previous.id : null,
nextPostId: next ? next.id : null,
},
})
You just need to do something like:
path: `projects/${post.id}`
Check the slashes and trailing slashes here.
You cna replace projects for your dynamic project type if you fetch that information for a more automatic approach (assuming it's post.__typename).
In order to use Custom Post Types with WPGraphQL, you must configure the Post Type to show_in_graphql using the following field:
show_in_graphql : true
While Registering a new Custom Post Type
This is an example of registering a new "docs" post_type and enabling GraphQL Support.
add_action( 'init', function() {
register_post_type( 'docs', [
'show_ui' => true,
'labels' => [
//#see https://developer.wordpress.org/themes/functionality/internationalization/
'menu_name' => __( 'Docs', 'your-textdomain' ),
],
'show_in_graphql' => true,
'hierarchical' => true,
'graphql_single_name' => 'document',
'graphql_plural_name' => 'documents',
] );
} );

Monaco editor intellisense font sizing wrong making it unusable

I have the Monaco editor embedded in a React component. For some reason the intellisense font sizes are all hosed up. Anyone have any ideas? I have changed a bunch of settings to try and fix things but nothing I have tried is having any impact.
import { useRef } from 'react'
import MonacoEditor from '#monaco-editor/react'
import codeShift from 'jscodeshift'
import Highlighter from 'monaco-jsx-highlighter'
import './jsx-syntax.css'
const CodeEditor = ({ height, initialValue, language, onChange, readOnly }) => {
const editorRef = useRef()
const onEditorDidMount = (getValue, editor) => {
editorRef.current = editor
editor.onDidChangeModelContent(() => (onChange) ? onChange(getValue()) : {})
editor.getModel()?.updateOptions({ tabSize: 4 })
const highlighter = new Highlighter(window.monaco, codeShift, editor);
highlighter.highLightOnDidChangeModelContent(
() => {}, () => {}, undefined, () => {}
);
}
const options = {
minimap: {enabled: false},
//showUnused: false,
lineNumbersMinChars: 3,
//fontSize: 13,
scrollBeyondLastLine: false,
automaticLayout: true,
readOnly
}
return (
<div className="editor-wrapper">
<MonacoEditor theme="dark" language={language ?? 'javascript'} height={(height ?? 400) + 'px'} value={initialValue ?? ''}
editorDidMount={onEditorDidMount} options={options}
/>
</div>
);
};
export default CodeEditor;
After much playing around I can confirm that the reason for the distortions is that my project is using the Bulma css framework. It looks like Monaco does not properly namespace its CSS and that Bulma is able to change things that completely mess up the toolbars and intellisense popups from the editor. To fix it I am manually going through and figuring out which styles need to be loacally applied to the wrapper around Monaco to get it working again.
It turned out to be the padding added to the tabs style in Bulma since the Monaco intellisense apparently uses a embedded tab on each line:
.tabs a {
...
padding: 0.5em 1em;
...
}
There's a FAQ somewhere, which says that if Monaco has measured its fonts before you set new ones, values are computed wrongly.
That's why I call:
public componentDidMount(): void {
Monaco.remeasureFonts();
}

Resources