オープンソースのWikiであるGROWIにはプラグイン機能が用意されています。自社のデータを表示したり、表示をカスタマイズするのに利用できます。
前回紹介したCSVプレビュープラグインを、XLSXファイルにも対応させました。今回はその使い方と、コードを紹介します。
プラグインを追加する
利用する際には、GROWIの管理画面の プラグイン
にて追加してください。URLは https://github.com/goofmint/growi-plugin-csv-preview
です。
使い方
利用する際には、編集画面でCSVファイル、またはXLSXファイルをアップロードします。そうすると、右側のプレビューにてテーブル表示されます。
これは編集中のプレビュー、ページ表示時の両方に対応しています。なお、ヘッダー行をスティッキーするようにしましたが、プレビュー時には高さの計算がずれるので注意してください。
コードについて
今回は添付ファイルを利用しているので、プラグインコンポーネントで attachment
の処理を上書きしています。 CSVPreview
がCSVプレビュー用のコンポーネントです。
const activate = (): void => {
if (growiFacade == null || growiFacade.markdownRenderer == null) {
return;
}
const { optionsGenerators } = growiFacade.markdownRenderer;
// For page view
optionsGenerators.customGenerateViewOptions = (...args) => {
const options = optionsGenerators.generateViewOptions(...args);
const { attachment } = options.components;
options.components.attachment = CSVPreview(attachment); // Wrap the default component
return options;
};
// For preview
optionsGenerators.customGeneratePreviewOptions = (...args) => {
const preview = optionsGenerators.generatePreviewOptions(...args);
const { attachment } = preview.components;
preview.components.attachment = CSVPreview(attachment); // Wrap the default component
return preview;
};
};
そして、添付ファイル名が .csv
で終わっていれば、プレビュー表示処理に入ります。
export const CSVPreview = (Tag: React.FunctionComponent<any>): React.FunctionComponent<any> => {
return ({ children, ...props }) => {
const { attachmentName, url }: {attachmentName: string, url: string} = props;
if (!attachmentName.endsWith('.csv') && !attachmentName.endsWith('.xlsx')) {
// 拡張子が.csv、または.xlsxでない場合は、通常の処理を行う
return (<Tag {...props}>
{children}
</Tag>);
}
try {
return (<>
{/* プレビュー表示用の処理 */}
</>
);
}
catch (err) {
// console.error(err);
}
// Return the original component if an error occurs
return (
<Tag {...props}>{children}</Tag>
);
};
};
プレビュー表示について
プレビュー表示はファイルを読み込む(非同期処理)なので、 react-async
を使います。拡張子ごとに関数を分けています。
return (<>
<strong>Preview: {attachmentName}</strong>
<Async promiseFn={loadFile} filePath={url}>
{({ data, error, isPending }) => {
if (isPending) return 'Loading...';
if (error) return `Something went wrong: ${error.message}`;
if (data) {
return (<>
{TableView(data)}
<Tag {...props}>
{children}
</Tag>
</>
);
}
return null;
}}
</Async>
</>
);
loadFile
は以下のようになります。ファイルの拡張子部分によって処理を分けています。
const loadFile = ({ filePath }: any, { signal }: any) => {
if (filePath.endsWith('.csv')) {
return loadCSV(filePath, { signal });
}
return loadXLSX(filePath, { signal });
};
loadCSV
は以下のようになります。ファイルパスを受け取り、それをテキストとして読み込みます。また、 vanillaes/csv を使ってCSVをパースします。
const loadCSV = async({ filePath }: any, { signal }: any) => {
const res = await fetch(filePath, { signal });
const text = await res.text();
return parse(text);
};
loadXLSX
は以下のようになります。ファイルパスを受け取り、それをバイナリとして読み込みます。XLSXファイルのパースは xlsx を使っています。
const loadXLSX = async(filePath: string, { signal }: any) => {
const file = await (await fetch(filePath, { signal })).arrayBuffer();
const workbook = XLSX.read(file);
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
const text = XLSX.utils.sheet_to_csv(worksheet, { forceQuotes: true });
const res = parse(text);
return res;
};
そして、受け取った配列をテーブル表示します。ヘッダーを固定した際に背景の情報が見えてしまわないように、背景色を取得しています。
const bgColor = typeof document !== 'undefined'
? window.getComputedStyle(document.querySelector('body')!, null).getPropertyValue('background-color')
: 'rgb(255, 255, 255)';
return (
<table className='table sticky-header'>
<thead>
{data[0].map((row: string) => (
<th
style={{ backgroundColor: bgColor }}
>{row}</th>
))}
</thead>
<tbody>
{data.slice(1).map((row: string[]) => (
<tr>
{row.map(str => (
<td>{str}</td>
))}
</tr>
))}
</tbody>
</table>
);
注意点
表示されるXLSXファイルについて
表示されるのは1つ目のシートになります。シート切り替えには対応していません。
プレビュー表示させたくない場合
プレビュー表示させたくない場合は、ファイル名を .csv
や .xlsx
で終わらない形(末尾にスペースを入れるなど)に変更してください。
まとめ
GROWIプラグインを使うと、表示を自由に拡張できます。足りない機能があれば、どんどん追加できます。ぜひ、自分のWikiをカスタマイズしましょう。