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でSSSAPIのデータを表示するプラグインを作りました

Posted at

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

今回は、GROWIプラグインとしてGoogleスプレッドシートをAPI化するSSSAPIのデータを表示するプラグインを作成しました。業務システムでGoogleスプレッドシートを利用している企業は多いので、そのデータをGROWI内で表示できます。

プラグインの動作

Remark Directiveとして、以下のように記述します。 [] 内には、SSSAPIのURLを記述します。

::sssapi[https://api.sssapi.app/ID]

オプションとして、 show を使って一覧表示に利用するカラムを指定できます。カラム名は、SSSAPIのデータに合わせてください。

::sssapi[https://api.sssapi.app/ID]{show=id,title,date}

FireShot Capture 618 - SSSAPI - GROWI - localhost.jpg

各行をクリックすると、テーブルの下に詳細データを表示します。ここではすべてのフィールドが表示対象になります。

FireShot Capture 619 - SSSAPI - GROWI - localhost.jpg

プラグインを追加する

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

Admin

コードについて

コードはgoofmint/growi-plugin-sssapi: GROWI plugin integrated with SSSAPIにて公開しています。ライセンスはMIT Licenseになります。

最初に ::sssapi というRemark Directiveを処理します。この記述があれば、 a タグに変換します。また、 sssapi = true を追加して、他の a タグとの区別をつけています。

vist メソッドで、RemarkのAST leafDirective を処理します。2つ目の引数を指定すると、そのディレクティブの場合のみ呼び出されるので便利です。 leafDirective は、行頭で :: から始まるディレクティブです。

export const remarkPlugin: Plugin = () => {
  return (tree: Node) => {
    // ::plugin[xxx]{hello=growi} -> leafDirective
    visit(tree, 'leafDirective', (node: Node) => {
      const n = node as unknown as GrowiNode;
      if (n.name !== 'sssapi') return;
      const data = n.data || (n.data = {});
      // Render your component
      const { url } = n.children[0] || { url: '' };
      data.hName = 'a'; // Tag name
      data.hChildren = []; // Children
      // Set properties
      data.hProperties = {
        href: url,
        title: JSON.stringify({ ...n.attributes, ...{ sssapi: true } }), // Pass to attributes to the component
      };
    });
  };
};

外部データを取得して表示

GROWI 7.2から、React Hooksに対応しました。今回のプラグインではそれを使ってSSSAPIからデータを取得し、表示に反映しています。

export const helloGROWI = (Tag: React.FunctionComponent<any>): React.FunctionComponent<any> => {
  return ({ children, ...props }) => {
    try {
      const { react } = growiFacade;
      const { useEffect, useState } = react;
      // 外部データを取得して適用するためのstate
      const [rows, setRows] = useState<{[key: string]: string}[]>([]);
      // ヘッダー情報
      const [headers, setHeaders] = useState<string[]>([]);
      // 行をクリックした際に表示する詳細情報
      const [detail, setDetail] = useState<{[key: string]: string} | null>(null);
      // SSSAPIからデータを取得する
      const getData = async(url: string) => {
        const response = await fetch(url);
        const json = await response.json();
        setRows(json);
        setHeaders(Object.keys(json[0] || {}));
      };
      const { sssapi, show } = JSON.parse(props.title);
      // sssapiがtrueの場合のみ処理を行う
      if (sssapi) {
        const { href } = props;
        // データの取得
        useEffect(() => {
          getData(href);
        }, [href]);
        // 表示するフィールド(オプション)
        const displayFields = show ? show.split(',') : [];
        return (
          { /* 表示処理 */}
        );
      }
    }
    catch (err) {
      // console.error(err);
    }
    // Return the original component if an error occurs
    return (
      <Tag {...props}>{children}</Tag>
    );
  };
};

表示処理

表示についてはReactで表示し、行のクリックで detail にデータを入れているだけです。

return (
  <>
    <table className='table'>
      <thead>
        <tr>
          {headers.map(header => (
            (displayFields.length > 0 && !displayFields.includes(header)) ? null
              : <th key={header}>{header}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {rows.map((row, rowIndex) => (
          <tr
            key={rowIndex}
            onClick={() => setDetail(row)}
          >
            {headers.map(header => (
              (displayFields.length > 0 && !displayFields.includes(header)) ? null
                : <td key={header}>{row[header]}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
    {detail && (
      <div>
        <ul>
          {Object.entries(detail).map(([key, value]) => (
            <li key={key}>{key}:<br />
              {value}
            </li>
          ))}
        </ul>
      </div>
    )}
  </>
);

GROWIコミュニティについて

プラグインの使い方や要望などがあれば、ぜひGROWIコミュニティにお寄せください。実現できそうなものがあれば、なるべく対応します。他にもヘルプチャンネルなどもありますので、ぜひ参加してください!

GROWI Slackへの参加はこちらから

まとめ

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?