1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GROWI CSV/XLSXプレビュープラグインの紹介

Posted at

オープンソースのWikiであるGROWIにはプラグイン機能が用意されています。自社のデータを表示したり、表示をカスタマイズするのに利用できます。

前回紹介したCSVプレビュープラグインを、XLSXファイルにも対応させました。今回はその使い方と、コードを紹介します。

FireShot Capture 066 - プラグイン開発 - GROWI - localhost.jpg

プラグインを追加する

利用する際には、GROWIの管理画面の プラグイン にて追加してください。URLは https://github.com/goofmint/growi-plugin-csv-preview です。

Admin

使い方

利用する際には、編集画面でCSVファイル、またはXLSXファイルをアップロードします。そうすると、右側のプレビューにてテーブル表示されます。

FireShot Capture 066 - プラグイン開発 - GROWI - localhost.jpg

これは編集中のプレビュー、ページ表示時の両方に対応しています。なお、ヘッダー行をスティッキーするようにしましたが、プレビュー時には高さの計算がずれるので注意してください。

FireShot Capture 064 - プラグイン開発 - GROWI - localhost.jpg

コードについて

今回は添付ファイルを利用しているので、プラグインコンポーネントで 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をカスタマイズしましょう。

OSS開発wikiツールのGROWI | 快適な情報共有を、全ての人へ

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?