我可以在 ReactAdmin 应用栏中显示过滤器设置吗?

Can I display filter settings in the ReactAdmin app bar?

是否可以在 ReactAdmin 应用栏中显示我当前过滤器的元素?

例如我有一个团队过滤器,用于显示公司中给定团队的销售结果。这一点都在工作。过滤器最终作为团队 ID 而不是名称出现在路由中。我不确定是否有可能改变它,而且我可能也不想这样做;但我还是想在应用栏的过滤器中显示所选团队 name

我已经设置了自定义应用栏,但我需要的信息似乎无法作为应用栏的道具提供。

我可以在 Redux Tools 中看到,在 admin\resources 下,已按 id 预加载了团队;但我不确定这些预加载项目的布局是否得到官方支持?也没有关于何时加载它们的官方时间? (These must be there because they were loaded for the filter, so logically I guess(??) that the one I need must be there when a filter value has been selected....)

然后,据我所知,要获得当前的过滤器设置,我还必须从状态的 router 部分提取内容。

我可以尝试将我的自定义应用程序栏连接到 Redux 并提取上述项目。我想我可以让它工作 - 但它有强烈的代码味道。 'will break with any ReactAdmin updates'的味道,或许还夹杂着'accessing state from the wrong place, at the wrong time'!

的味道

是否有更简洁、更正式的方式来解决这个问题?

我已经实施了我在自己的问题中建议的 'not officially supported' 方法。它工作正常,但是 - 公平警告 - 据我所知它可能会在更新 ReactAdmin 后停止工作。

如果我想出了一个更受官方支持的方法,或者如果我设法将此中的任何内容提交回 ReactAdmin 项目,我将更新此答案。

所以,这是一个自定义布局:

// CustomLayout.js
import React from 'react';
import { connect } from 'react-redux';
import { Layout, AppBar } from 'react-admin';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import getFilterValue from './getFilterValue';

const useStyles = makeStyles(
  theme => ({
    title: {
      flex: 1,
      textOverflow: 'ellipsis',
      whiteSpace: 'nowrap',
      overflow: 'hidden',
    },
  }),
  { name: 'RaAppBar' }
);

const CustomAppBarUnconnected = (props) => {
  const classes = useStyles(props);
  const { title } = props;
  return (
    <AppBar
      {...props}
    >
      <Typography
        variant="h6"
        color="inherit"
        className={classes.title}
      >
        { title }
      </Typography>
    </AppBar>
  );
}

const mapStateToProps = (state, props) => {
  let team = getFilterValue(state, 'teamId', 'teams'); //, 'name');
  let previousMonth = getFilterValue(state, 'previousMonth');
  let title = `${team ? team.name : 'Company'} Sales. ${previousMonth ? `Previous month = ${previousMonth}` : 'Nothing to see here'}.`;
  return {
    ...props,
    title
  };
};

const CustomAppBar = connect(
  mapStateToProps,
)(CustomAppBarUnconnected);

export const CustomLayout = (props) =>
  <Layout
    {...props}
    appBar={ CustomAppBar }
  />;

使用 <Admin layout={CustomLayout}> 在您的 ReactAdmin 应用程序中应用它。这是一些示例输出:

大多数自定义布局只是获得自定义应用栏所需的样板,它看起来像默认应用栏:它将 children 传递给标准 AppBar,应用所需的格式使标题看起来像标准标题。

If you want the default title to appear along with your custom title, add <span id="react-admin-title" /> where you want it to appear (presumably, somewhere next to { title }).

If you also want to more thoroughly re-arrange the app bar then (following the ReactAdmin documentation), you would need to make a new custom AppBar class from scratch, starting from the original ReactAdmin AppBar class. Then just link it to Redux as I have done above.

此自定义布局的关键变化是 AppBar 现在连接到 Redux,这意味着在 mapStateToProps 中我们可以调用新功能 getFilterValue:

// getFilterValue.js
const getFilterValue = (state, source, resource, field) => {
  let value = undefined;

  if (!state || !source) return value;
  
  const filterJSON =
    state.router &&
    state.router.location &&
    state.router.location.query &&
    state.router.location.query.filter;

  if (filterJSON) {
    let filter = JSON.parse(decodeURIComponent(filterJSON));

    let id = filter && filter[source];

    if (id !== undefined) {
      if (!resource) {
        value = id;
      } else {
        const data =
          state.admin &&
          state.admin.resources &&
          state.admin.resources[resource] &&
          state.admin.resources[resource].data;

        if (data) {
          value = data[id];
          if (field) {
            value = value[field];
          }
        }
      }
    }
  }

  return value;
};

export default getFilterValue;

根据您传递给 getFilterValue 的参数,您可以:

  • 从过滤器中获取原始项目:(state, source)
  • 将过滤器中的原始项目 ID 映射到已从 API 中获取的 object:(state, source, resource)
  • 将过滤器中的 id 映射到一个项目,然后从该项目中提取一个命名字段:(state, source, resource, field)

undefined 如果要求的值不存在,总是返回;例如如果您不在包含所请求过滤器的页面上,或者如果用户尚未应用该过滤器,或者如果您在任何参数中输入错误。