filter-button 0.2.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -46
- package/dist/admin/ButtonComponent-BtVaVTMf.js +25 -0
- package/dist/admin/ButtonComponent-ggy5X7sG.mjs +25 -0
- package/dist/admin/en-B4KWt_jN.js +4 -0
- package/dist/admin/en-Byx4XI2L.mjs +4 -0
- package/dist/admin/fr-C8Qw4iPZ.js +4 -0
- package/dist/admin/fr-hkSxFuzl.mjs +4 -0
- package/dist/admin/index.js +117 -0
- package/dist/admin/index.mjs +117 -0
- package/dist/server/index.js +16 -0
- package/dist/server/index.mjs +16 -0
- package/package.json +81 -38
- package/admin/src/components/ButtonComponent/ButtonComponent.js +0 -37
- package/admin/src/components/Initializer/index.js +0 -26
- package/admin/src/components/PluginIcon/index.js +0 -26
- package/admin/src/index.js +0 -64
- package/admin/src/pages/App/index.js +0 -25
- package/admin/src/pages/HomePage/index.js +0 -20
- package/admin/src/pluginId.js +0 -5
- package/admin/src/translations/en.json +0 -1
- package/admin/src/translations/fr.json +0 -1
- package/admin/src/utils/axiosInstance.js +0 -42
- package/admin/src/utils/getTrad.js +0 -5
- package/assets/demo.gif +0 -0
- package/server/bootstrap.js +0 -5
- package/server/index.js +0 -7
- package/server/register.js +0 -9
- package/strapi-admin.js +0 -3
- package/strapi-server.js +0 -3
package/README.md
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
## About
|
|
4
4
|
|
|
5
|
-

|
|
5
|
+
<!--  -->
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+

|
|
8
8
|
|
|
9
9
|
This package provides a custom field for Strapi that lets you add a filter button in no time.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
> **Strapi 5** compatible. (For Strapi 4 use `filter-button@0.2.1`.)
|
|
12
|
+
|
|
13
|
+
Custom fields offer a powerful API to create highly customizable fields.
|
|
12
14
|
|
|
13
15
|
This plugin lets you view filtered data according to your configurations.
|
|
14
16
|
|
|
@@ -28,61 +30,95 @@ npm i filter-button
|
|
|
28
30
|
yarn add filter-button
|
|
29
31
|
```
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
#### Using a local build (unpublished / linked)
|
|
34
|
+
|
|
35
|
+
If you have the plugin checked out locally (e.g. as a sibling folder next to your Strapi app) instead of installing from NPM, first build it, then reference it with a `file:` dependency:
|
|
32
36
|
|
|
33
37
|
```bash
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
# in the plugin folder
|
|
39
|
+
npm install
|
|
40
|
+
npm run build
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```jsonc
|
|
44
|
+
// in your Strapi app's package.json
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"filter-button": "file:../Filter-Button"
|
|
38
47
|
}
|
|
39
48
|
```
|
|
40
49
|
|
|
50
|
+
```bash
|
|
51
|
+
# in your Strapi app
|
|
52
|
+
npm install
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`npm install` symlinks the plugin into `node_modules/filter-button`. Note the `file:` path is machine-specific, so this is best for local development rather than committing to a shared repo.
|
|
56
|
+
|
|
57
|
+
### Registering the plugin (optional)
|
|
58
|
+
|
|
59
|
+
Because `filter-button` is a package dependency in your `package.json`, Strapi 5 auto-discovers and enables it — **no `config/plugins` entry is required** just to turn it on.
|
|
60
|
+
|
|
61
|
+
You only need an entry in `./config/plugins.js` (or `./config/plugins.ts`) if you want to be explicit about it (recommended for discoverability), or to disable it (`enabled: false`):
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
module.exports = {
|
|
65
|
+
'filter-button': {
|
|
66
|
+
enabled: true,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If you use a TypeScript config that already exports other plugin settings, add `'filter-button'` **inside** the exported config object rather than a separate `module.exports` — a trailing `module.exports` will override `export default` and silently drop your other settings:
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
export default ({ env }) => ({
|
|
75
|
+
// ...other plugins...
|
|
76
|
+
'filter-button': {
|
|
77
|
+
enabled: true,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
41
82
|
## Configuration
|
|
42
83
|
|
|
43
84
|
#### create relations first for filter button to work
|
|
44
85
|
|
|
45
86
|
if relation is many to many then add boolean `manyToMany:true` in configuration
|
|
46
87
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
),
|
|
81
|
-
})
|
|
82
|
-
)
|
|
83
|
-
return config;
|
|
88
|
+
Strapi 5 uses **Vite** for the admin panel (webpack has been removed). Create (or edit) `src/admin/vite.config.js` in your Strapi app and expose your configuration through Vite's `define` option:
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
const { mergeConfig } = require('vite');
|
|
92
|
+
|
|
93
|
+
module.exports = (config) => {
|
|
94
|
+
return mergeConfig(config, {
|
|
95
|
+
define: {
|
|
96
|
+
CONTENT_TYPES: JSON.stringify([
|
|
97
|
+
{
|
|
98
|
+
from: 'api::topic.topic', // collection where button will be added
|
|
99
|
+
to: 'api::card.card', // which collection you want to filter
|
|
100
|
+
filterBy: 'title', // field name by which you want to filter
|
|
101
|
+
attributeName: 'viewCards', // attribute name added while adding button
|
|
102
|
+
buttonTitle: 'View Cards', // title of button
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
from: 'api::category.category',
|
|
106
|
+
to: 'api::topic.topic',
|
|
107
|
+
filterBy: 'title',
|
|
108
|
+
attributeName: 'viewTopics',
|
|
109
|
+
buttonTitle: 'View Topics',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
from: 'api::category.category', // adding multiple buttons for same collection
|
|
113
|
+
to: 'api::card.card',
|
|
114
|
+
filterBy: 'title',
|
|
115
|
+
attributeName: 'viewCards',
|
|
116
|
+
buttonTitle: 'View Cards',
|
|
117
|
+
},
|
|
118
|
+
]),
|
|
119
|
+
},
|
|
120
|
+
});
|
|
84
121
|
};
|
|
85
|
-
|
|
86
122
|
```
|
|
87
123
|
|
|
88
124
|
#### Then run build:
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const designSystem = require("@strapi/design-system");
|
|
6
|
+
const reactRouterDom = require("react-router-dom");
|
|
7
|
+
const admin = require("@strapi/strapi/admin");
|
|
8
|
+
const ButtonComponent = react.forwardRef(({ name }, ref) => {
|
|
9
|
+
const navigate = reactRouterDom.useNavigate();
|
|
10
|
+
const { contentType, form } = admin.unstable_useContentManagerContext();
|
|
11
|
+
const values = form?.values ?? {};
|
|
12
|
+
const uid = contentType?.uid;
|
|
13
|
+
const currentCollection = CONTENT_TYPES?.filter(
|
|
14
|
+
(data) => data?.from === uid && data?.attributeName === name
|
|
15
|
+
)[0];
|
|
16
|
+
const filterCards = () => {
|
|
17
|
+
if (!currentCollection) return;
|
|
18
|
+
const relationField = currentCollection?.manyToMany ? `${currentCollection?.from?.split(".")[1]}s` : currentCollection?.from?.split(".")[1];
|
|
19
|
+
navigate(
|
|
20
|
+
`/content-manager/collection-types/${currentCollection?.to}?page=1&pageSize=10&sort=${currentCollection?.filterBy}:ASC&filters[$and][0][${relationField}][${currentCollection?.filterBy}][$eq]=${values?.title}`
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { ref, paddingTop: 5, style: { width: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { style: { margin: "auto" }, size: "L", variant: "default", onClick: filterCards, children: currentCollection?.buttonTitle || "View" }) });
|
|
24
|
+
});
|
|
25
|
+
exports.default = ButtonComponent;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { Box, Button } from "@strapi/design-system";
|
|
4
|
+
import { useNavigate } from "react-router-dom";
|
|
5
|
+
import { unstable_useContentManagerContext } from "@strapi/strapi/admin";
|
|
6
|
+
const ButtonComponent = forwardRef(({ name }, ref) => {
|
|
7
|
+
const navigate = useNavigate();
|
|
8
|
+
const { contentType, form } = unstable_useContentManagerContext();
|
|
9
|
+
const values = form?.values ?? {};
|
|
10
|
+
const uid = contentType?.uid;
|
|
11
|
+
const currentCollection = CONTENT_TYPES?.filter(
|
|
12
|
+
(data) => data?.from === uid && data?.attributeName === name
|
|
13
|
+
)[0];
|
|
14
|
+
const filterCards = () => {
|
|
15
|
+
if (!currentCollection) return;
|
|
16
|
+
const relationField = currentCollection?.manyToMany ? `${currentCollection?.from?.split(".")[1]}s` : currentCollection?.from?.split(".")[1];
|
|
17
|
+
navigate(
|
|
18
|
+
`/content-manager/collection-types/${currentCollection?.to}?page=1&pageSize=10&sort=${currentCollection?.filterBy}:ASC&filters[$and][0][${relationField}][${currentCollection?.filterBy}][$eq]=${values?.title}`
|
|
19
|
+
);
|
|
20
|
+
};
|
|
21
|
+
return /* @__PURE__ */ jsx(Box, { ref, paddingTop: 5, style: { width: "100%" }, children: /* @__PURE__ */ jsx(Button, { style: { margin: "auto" }, size: "L", variant: "default", onClick: filterCards, children: currentCollection?.buttonTitle || "View" }) });
|
|
22
|
+
});
|
|
23
|
+
export {
|
|
24
|
+
ButtonComponent as default
|
|
25
|
+
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const react = require("react");
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
const styledComponents = require("styled-components");
|
|
6
|
+
const designSystem = require("@strapi/design-system");
|
|
7
|
+
const icons = require("@strapi/icons");
|
|
8
|
+
const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
|
9
|
+
const v = glob[path];
|
|
10
|
+
if (v) {
|
|
11
|
+
return typeof v === "function" ? v() : Promise.resolve(v);
|
|
12
|
+
}
|
|
13
|
+
return new Promise((_, reject) => {
|
|
14
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
|
15
|
+
reject.bind(
|
|
16
|
+
null,
|
|
17
|
+
new Error(
|
|
18
|
+
"Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const prefixPluginTranslations = (trad, pluginId2) => {
|
|
25
|
+
if (!pluginId2) {
|
|
26
|
+
throw new TypeError("pluginId can't be empty");
|
|
27
|
+
}
|
|
28
|
+
return Object.keys(trad).reduce((acc, current) => {
|
|
29
|
+
acc[`${pluginId2}.${current}`] = trad[current];
|
|
30
|
+
return acc;
|
|
31
|
+
}, {});
|
|
32
|
+
};
|
|
33
|
+
const name$1 = "filter-button";
|
|
34
|
+
const strapi = { "name": "filter-button" };
|
|
35
|
+
const pluginPkg = {
|
|
36
|
+
name: name$1,
|
|
37
|
+
strapi
|
|
38
|
+
};
|
|
39
|
+
const pluginId = pluginPkg.name.replace(/^(@[^-,.][\w,-]+\/|strapi-)plugin-/i, "");
|
|
40
|
+
const Initializer = ({ setPlugin }) => {
|
|
41
|
+
const ref = react.useRef();
|
|
42
|
+
ref.current = setPlugin;
|
|
43
|
+
react.useEffect(() => {
|
|
44
|
+
ref.current(pluginId);
|
|
45
|
+
}, []);
|
|
46
|
+
return null;
|
|
47
|
+
};
|
|
48
|
+
const IconBox = styledComponents.styled(designSystem.Flex)`
|
|
49
|
+
/* Hard code color values */
|
|
50
|
+
/* to stay consistent between themes */
|
|
51
|
+
background-color: #f0f0ff; /* primary100 */
|
|
52
|
+
border: 1px solid #d9d8ff; /* primary200 */
|
|
53
|
+
|
|
54
|
+
svg > path {
|
|
55
|
+
fill: #4945ff; /* primary600 */
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
const PluginIcon = () => {
|
|
59
|
+
return /* @__PURE__ */ jsxRuntime.jsx(IconBox, { justifyContent: "center", alignItems: "center", width: 7, height: 6, hasRadius: true, "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Filter, {}) });
|
|
60
|
+
};
|
|
61
|
+
const name = pluginPkg.strapi.name;
|
|
62
|
+
const index = {
|
|
63
|
+
register(app) {
|
|
64
|
+
app.customFields.register({
|
|
65
|
+
name: "filterButton",
|
|
66
|
+
pluginId,
|
|
67
|
+
// the custom field is provided by this plugin
|
|
68
|
+
type: "string",
|
|
69
|
+
// the value is stored as a string
|
|
70
|
+
intlLabel: {
|
|
71
|
+
id: "filter-button-button-label",
|
|
72
|
+
defaultMessage: "Filter Button"
|
|
73
|
+
},
|
|
74
|
+
intlDescription: {
|
|
75
|
+
id: "filter-button-button-description",
|
|
76
|
+
defaultMessage: "Filter Data"
|
|
77
|
+
},
|
|
78
|
+
icon: PluginIcon,
|
|
79
|
+
// don't forget to create/import your icon component
|
|
80
|
+
components: {
|
|
81
|
+
Input: async () => Promise.resolve().then(() => require("./ButtonComponent-BtVaVTMf.js")).then((module2) => ({
|
|
82
|
+
default: module2.default
|
|
83
|
+
}))
|
|
84
|
+
},
|
|
85
|
+
options: {
|
|
86
|
+
// declare options here
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
app.registerPlugin({
|
|
90
|
+
id: pluginId,
|
|
91
|
+
initializer: Initializer,
|
|
92
|
+
isReady: false,
|
|
93
|
+
name
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
bootstrap(app) {
|
|
97
|
+
},
|
|
98
|
+
async registerTrads({ locales }) {
|
|
99
|
+
const importedTrads = await Promise.all(
|
|
100
|
+
locales.map((locale) => {
|
|
101
|
+
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => Promise.resolve().then(() => require("./en-B4KWt_jN.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-C8Qw4iPZ.js")) }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
|
|
102
|
+
return {
|
|
103
|
+
data: prefixPluginTranslations(data, pluginId),
|
|
104
|
+
locale
|
|
105
|
+
};
|
|
106
|
+
}).catch(() => {
|
|
107
|
+
return {
|
|
108
|
+
data: {},
|
|
109
|
+
locale
|
|
110
|
+
};
|
|
111
|
+
});
|
|
112
|
+
})
|
|
113
|
+
);
|
|
114
|
+
return Promise.resolve(importedTrads);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
exports.default = index;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { useRef, useEffect } from "react";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { styled } from "styled-components";
|
|
4
|
+
import { Flex } from "@strapi/design-system";
|
|
5
|
+
import { Filter } from "@strapi/icons";
|
|
6
|
+
const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
|
7
|
+
const v = glob[path];
|
|
8
|
+
if (v) {
|
|
9
|
+
return typeof v === "function" ? v() : Promise.resolve(v);
|
|
10
|
+
}
|
|
11
|
+
return new Promise((_, reject) => {
|
|
12
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
|
13
|
+
reject.bind(
|
|
14
|
+
null,
|
|
15
|
+
new Error(
|
|
16
|
+
"Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
|
|
17
|
+
)
|
|
18
|
+
)
|
|
19
|
+
);
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
const prefixPluginTranslations = (trad, pluginId2) => {
|
|
23
|
+
if (!pluginId2) {
|
|
24
|
+
throw new TypeError("pluginId can't be empty");
|
|
25
|
+
}
|
|
26
|
+
return Object.keys(trad).reduce((acc, current) => {
|
|
27
|
+
acc[`${pluginId2}.${current}`] = trad[current];
|
|
28
|
+
return acc;
|
|
29
|
+
}, {});
|
|
30
|
+
};
|
|
31
|
+
const name$1 = "filter-button";
|
|
32
|
+
const strapi = { "name": "filter-button" };
|
|
33
|
+
const pluginPkg = {
|
|
34
|
+
name: name$1,
|
|
35
|
+
strapi
|
|
36
|
+
};
|
|
37
|
+
const pluginId = pluginPkg.name.replace(/^(@[^-,.][\w,-]+\/|strapi-)plugin-/i, "");
|
|
38
|
+
const Initializer = ({ setPlugin }) => {
|
|
39
|
+
const ref = useRef();
|
|
40
|
+
ref.current = setPlugin;
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
ref.current(pluginId);
|
|
43
|
+
}, []);
|
|
44
|
+
return null;
|
|
45
|
+
};
|
|
46
|
+
const IconBox = styled(Flex)`
|
|
47
|
+
/* Hard code color values */
|
|
48
|
+
/* to stay consistent between themes */
|
|
49
|
+
background-color: #f0f0ff; /* primary100 */
|
|
50
|
+
border: 1px solid #d9d8ff; /* primary200 */
|
|
51
|
+
|
|
52
|
+
svg > path {
|
|
53
|
+
fill: #4945ff; /* primary600 */
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
56
|
+
const PluginIcon = () => {
|
|
57
|
+
return /* @__PURE__ */ jsx(IconBox, { justifyContent: "center", alignItems: "center", width: 7, height: 6, hasRadius: true, "aria-hidden": true, children: /* @__PURE__ */ jsx(Filter, {}) });
|
|
58
|
+
};
|
|
59
|
+
const name = pluginPkg.strapi.name;
|
|
60
|
+
const index = {
|
|
61
|
+
register(app) {
|
|
62
|
+
app.customFields.register({
|
|
63
|
+
name: "filterButton",
|
|
64
|
+
pluginId,
|
|
65
|
+
// the custom field is provided by this plugin
|
|
66
|
+
type: "string",
|
|
67
|
+
// the value is stored as a string
|
|
68
|
+
intlLabel: {
|
|
69
|
+
id: "filter-button-button-label",
|
|
70
|
+
defaultMessage: "Filter Button"
|
|
71
|
+
},
|
|
72
|
+
intlDescription: {
|
|
73
|
+
id: "filter-button-button-description",
|
|
74
|
+
defaultMessage: "Filter Data"
|
|
75
|
+
},
|
|
76
|
+
icon: PluginIcon,
|
|
77
|
+
// don't forget to create/import your icon component
|
|
78
|
+
components: {
|
|
79
|
+
Input: async () => import("./ButtonComponent-ggy5X7sG.mjs").then((module) => ({
|
|
80
|
+
default: module.default
|
|
81
|
+
}))
|
|
82
|
+
},
|
|
83
|
+
options: {
|
|
84
|
+
// declare options here
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
app.registerPlugin({
|
|
88
|
+
id: pluginId,
|
|
89
|
+
initializer: Initializer,
|
|
90
|
+
isReady: false,
|
|
91
|
+
name
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
bootstrap(app) {
|
|
95
|
+
},
|
|
96
|
+
async registerTrads({ locales }) {
|
|
97
|
+
const importedTrads = await Promise.all(
|
|
98
|
+
locales.map((locale) => {
|
|
99
|
+
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-Byx4XI2L.mjs"), "./translations/fr.json": () => import("./fr-hkSxFuzl.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
|
|
100
|
+
return {
|
|
101
|
+
data: prefixPluginTranslations(data, pluginId),
|
|
102
|
+
locale
|
|
103
|
+
};
|
|
104
|
+
}).catch(() => {
|
|
105
|
+
return {
|
|
106
|
+
data: {},
|
|
107
|
+
locale
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
return Promise.resolve(importedTrads);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
export {
|
|
116
|
+
index as default
|
|
117
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const register = ({ strapi }) => {
|
|
4
|
+
strapi.customFields.register({
|
|
5
|
+
name: "filterButton",
|
|
6
|
+
plugin: "filter-button",
|
|
7
|
+
type: "string"
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
const bootstrap = ({ strapi }) => {
|
|
11
|
+
};
|
|
12
|
+
const index = {
|
|
13
|
+
register,
|
|
14
|
+
bootstrap
|
|
15
|
+
};
|
|
16
|
+
exports.default = index;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const register = ({ strapi }) => {
|
|
2
|
+
strapi.customFields.register({
|
|
3
|
+
name: "filterButton",
|
|
4
|
+
plugin: "filter-button",
|
|
5
|
+
type: "string"
|
|
6
|
+
});
|
|
7
|
+
};
|
|
8
|
+
const bootstrap = ({ strapi }) => {
|
|
9
|
+
};
|
|
10
|
+
const index = {
|
|
11
|
+
register,
|
|
12
|
+
bootstrap
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
index as default
|
|
16
|
+
};
|
package/package.json
CHANGED
|
@@ -1,38 +1,81 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "filter-button",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"private": false,
|
|
5
|
-
"description": "Custom filter button plugin for strapi",
|
|
6
|
-
"strapi": {
|
|
7
|
-
"name": "filter-button",
|
|
8
|
-
"description": "Custom filter button plugin for strapi",
|
|
9
|
-
"kind": "plugin",
|
|
10
|
-
"displayName": "Filter Button"
|
|
11
|
-
},
|
|
12
|
-
"repository": {
|
|
13
|
-
"type": "git",
|
|
14
|
-
"url": "https://github.com/kalpesh442266/Filter-Button"
|
|
15
|
-
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"filter-button",
|
|
18
|
-
"strapi custom field",
|
|
19
|
-
"strapi filter button field"
|
|
20
|
-
],
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
},
|
|
37
|
-
"
|
|
38
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "filter-button",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Custom filter button plugin for strapi",
|
|
6
|
+
"strapi": {
|
|
7
|
+
"name": "filter-button",
|
|
8
|
+
"description": "Custom filter button plugin for strapi",
|
|
9
|
+
"kind": "plugin",
|
|
10
|
+
"displayName": "Filter Button"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/kalpesh442266/Filter-Button"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"filter-button",
|
|
18
|
+
"strapi custom field",
|
|
19
|
+
"strapi filter button field"
|
|
20
|
+
],
|
|
21
|
+
"type": "commonjs",
|
|
22
|
+
"exports": {
|
|
23
|
+
"./package.json": "./package.json",
|
|
24
|
+
"./strapi-admin": {
|
|
25
|
+
"source": "./admin/src/index.js",
|
|
26
|
+
"import": "./dist/admin/index.mjs",
|
|
27
|
+
"require": "./dist/admin/index.js",
|
|
28
|
+
"default": "./dist/admin/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./strapi-server": {
|
|
31
|
+
"source": "./server/src/index.js",
|
|
32
|
+
"import": "./dist/server/index.mjs",
|
|
33
|
+
"require": "./dist/server/index.js",
|
|
34
|
+
"default": "./dist/server/index.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "strapi-plugin build",
|
|
42
|
+
"watch": "strapi-plugin watch",
|
|
43
|
+
"watch:link": "strapi-plugin watch:link",
|
|
44
|
+
"verify": "strapi-plugin verify"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@strapi/design-system": "^2.0.0-rc.14",
|
|
48
|
+
"@strapi/icons": "^2.0.0-rc.14",
|
|
49
|
+
"react-intl": "^6.6.2"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@strapi/sdk-plugin": "^6.0.0",
|
|
53
|
+
"@strapi/strapi": "^5.0.0",
|
|
54
|
+
"prettier": "^3.2.5",
|
|
55
|
+
"react": "^18.3.1",
|
|
56
|
+
"react-dom": "^18.3.1",
|
|
57
|
+
"react-router-dom": "^6.22.3",
|
|
58
|
+
"styled-components": "^6.1.8"
|
|
59
|
+
},
|
|
60
|
+
"author": {
|
|
61
|
+
"name": "Kalpesh Rane"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@strapi/sdk-plugin": "^6.0.0",
|
|
65
|
+
"@strapi/strapi": "^5.0.0",
|
|
66
|
+
"react": "^17.0.0 || ^18.0.0",
|
|
67
|
+
"react-dom": "^17.0.0 || ^18.0.0",
|
|
68
|
+
"react-router-dom": "^6.0.0",
|
|
69
|
+
"styled-components": "^6.0.0"
|
|
70
|
+
},
|
|
71
|
+
"maintainers": [
|
|
72
|
+
{
|
|
73
|
+
"name": "Kalpesh Rane"
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
"engines": {
|
|
77
|
+
"node": ">=18.0.0 <=22.x.x",
|
|
78
|
+
"npm": ">=6.0.0"
|
|
79
|
+
},
|
|
80
|
+
"license": "MIT"
|
|
81
|
+
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* HomePage
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
import { Box, Button } from '@strapi/design-system';
|
|
7
|
-
import React from 'react';
|
|
8
|
-
import { useHistory } from "react-router-dom";
|
|
9
|
-
import { useCMEditViewDataManager } from '@strapi/helper-plugin';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const ButtonComponent = ({ name }) => {
|
|
13
|
-
const history = useHistory();
|
|
14
|
-
const {
|
|
15
|
-
allLayoutData,
|
|
16
|
-
modifiedData
|
|
17
|
-
} = useCMEditViewDataManager();
|
|
18
|
-
|
|
19
|
-
const { uid } = allLayoutData.contentType;
|
|
20
|
-
const currentCollection = CONTENT_TYPES?.filter(data => { if (data?.from === uid && data?.attributeName === name) return data })[0]
|
|
21
|
-
|
|
22
|
-
const filterCards = () => {
|
|
23
|
-
history.push(`/content-manager/collectionType/${currentCollection?.to}?page=1&pageSize=10&sort=${currentCollection?.filterBy}:ASC&filters[$and][0][${currentCollection?.manyToMany ? currentCollection?.from?.split('.')[1] + 's' : currentCollection?.from?.split('.')[1]}][${currentCollection?.filterBy}][$eq]=${modifiedData?.title}`)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<>
|
|
28
|
-
<Box paddingTop={5} style={{ width: '100%' }}>
|
|
29
|
-
<Button style={{ margin: 'auto' }} size="L" variant="default" onClick={filterCards}>
|
|
30
|
-
{currentCollection?.buttonTitle || "View"}
|
|
31
|
-
</Button>
|
|
32
|
-
</Box>
|
|
33
|
-
</>
|
|
34
|
-
);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export default ButtonComponent;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* Initializer
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { useEffect, useRef } from 'react';
|
|
8
|
-
import PropTypes from 'prop-types';
|
|
9
|
-
import pluginId from '../../pluginId';
|
|
10
|
-
|
|
11
|
-
const Initializer = ({ setPlugin }) => {
|
|
12
|
-
const ref = useRef();
|
|
13
|
-
ref.current = setPlugin;
|
|
14
|
-
|
|
15
|
-
useEffect(() => {
|
|
16
|
-
ref.current(pluginId);
|
|
17
|
-
}, []);
|
|
18
|
-
|
|
19
|
-
return null;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
Initializer.propTypes = {
|
|
23
|
-
setPlugin: PropTypes.func.isRequired,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export default Initializer;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import styled from 'styled-components';
|
|
3
|
-
import { Icon } from '@strapi/design-system/Icon';
|
|
4
|
-
import { Flex } from '@strapi/design-system/Flex';
|
|
5
|
-
import Filter from '@strapi/icons/Filter';
|
|
6
|
-
|
|
7
|
-
const IconBox = styled(Flex)`
|
|
8
|
-
/* Hard code color values */
|
|
9
|
-
/* to stay consistent between themes */
|
|
10
|
-
background-color: #f0f0ff; /* primary100 */
|
|
11
|
-
border: 1px solid #d9d8ff; /* primary200 */
|
|
12
|
-
|
|
13
|
-
svg > path {
|
|
14
|
-
fill: #4945ff; /* primary600 */
|
|
15
|
-
}
|
|
16
|
-
`;
|
|
17
|
-
|
|
18
|
-
const PluginIcon = () => {
|
|
19
|
-
return (
|
|
20
|
-
<IconBox justifyContent="center" alignItems="center" width={7} height={6} hasRadius aria-hidden>
|
|
21
|
-
<Icon as={Filter} />
|
|
22
|
-
</IconBox>
|
|
23
|
-
);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export default PluginIcon;
|
package/admin/src/index.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { prefixPluginTranslations } from '@strapi/helper-plugin';
|
|
2
|
-
import pluginPkg from '../../package.json';
|
|
3
|
-
import pluginId from './pluginId';
|
|
4
|
-
import Initializer from './components/Initializer';
|
|
5
|
-
import PluginIcon from './components/PluginIcon';
|
|
6
|
-
|
|
7
|
-
const name = pluginPkg.strapi.name;
|
|
8
|
-
|
|
9
|
-
export default {
|
|
10
|
-
register(app) {
|
|
11
|
-
app.customFields.register({
|
|
12
|
-
name: "filterButton",
|
|
13
|
-
pluginId: pluginId, // the custom field is created by a color-picker plugin
|
|
14
|
-
type: "string", // the color will be stored as a string
|
|
15
|
-
|
|
16
|
-
intlLabel: {
|
|
17
|
-
id: "filter-button-button-label",
|
|
18
|
-
defaultMessage: "Filter Button",
|
|
19
|
-
},
|
|
20
|
-
intlDescription: {
|
|
21
|
-
id: "filter-button-button-description",
|
|
22
|
-
defaultMessage: "Filter Data",
|
|
23
|
-
},
|
|
24
|
-
icon: PluginIcon, // don't forget to create/import your icon component
|
|
25
|
-
components: {
|
|
26
|
-
Input: async () => import(/* webpackChunkName: "input-component" */ "./components/ButtonComponent/ButtonComponent.js"),
|
|
27
|
-
},
|
|
28
|
-
options: {
|
|
29
|
-
// declare options here
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
app.registerPlugin({
|
|
33
|
-
id: pluginId,
|
|
34
|
-
initializer: Initializer,
|
|
35
|
-
isReady: false,
|
|
36
|
-
name,
|
|
37
|
-
});
|
|
38
|
-
},
|
|
39
|
-
|
|
40
|
-
bootstrap(app) { },
|
|
41
|
-
async registerTrads({ locales }) {
|
|
42
|
-
const importedTrads = await Promise.all(
|
|
43
|
-
locales.map((locale) => {
|
|
44
|
-
return import(
|
|
45
|
-
/* webpackChunkName: "translation-[request]" */ `./translations/${locale}.json`
|
|
46
|
-
)
|
|
47
|
-
.then(({ default: data }) => {
|
|
48
|
-
return {
|
|
49
|
-
data: prefixPluginTranslations(data, pluginId),
|
|
50
|
-
locale,
|
|
51
|
-
};
|
|
52
|
-
})
|
|
53
|
-
.catch(() => {
|
|
54
|
-
return {
|
|
55
|
-
data: {},
|
|
56
|
-
locale,
|
|
57
|
-
};
|
|
58
|
-
});
|
|
59
|
-
})
|
|
60
|
-
);
|
|
61
|
-
|
|
62
|
-
return Promise.resolve(importedTrads);
|
|
63
|
-
},
|
|
64
|
-
};
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
* This component is the skeleton around the actual pages, and should only
|
|
4
|
-
* contain code that should be seen on all pages. (e.g. navigation bar)
|
|
5
|
-
*
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React from 'react';
|
|
9
|
-
import { Switch, Route } from 'react-router-dom';
|
|
10
|
-
import { NotFound } from '@strapi/helper-plugin';
|
|
11
|
-
import pluginId from '../../pluginId';
|
|
12
|
-
import HomePage from '../HomePage';
|
|
13
|
-
|
|
14
|
-
const App = () => {
|
|
15
|
-
return (
|
|
16
|
-
<div>
|
|
17
|
-
<Switch>
|
|
18
|
-
<Route path={`/plugins/${pluginId}`} component={HomePage} exact />
|
|
19
|
-
<Route component={NotFound} />
|
|
20
|
-
</Switch>
|
|
21
|
-
</div>
|
|
22
|
-
);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export default App;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* HomePage
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React from 'react';
|
|
8
|
-
// import PropTypes from 'prop-types';
|
|
9
|
-
import pluginId from '../../pluginId';
|
|
10
|
-
|
|
11
|
-
const HomePage = () => {
|
|
12
|
-
return (
|
|
13
|
-
<div>
|
|
14
|
-
<h1>{pluginId}'s HomePage</h1>
|
|
15
|
-
<p>Happy coding</p>
|
|
16
|
-
</div>
|
|
17
|
-
);
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export default HomePage;
|
package/admin/src/pluginId.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* axios with a custom config.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import axios from 'axios';
|
|
6
|
-
import { auth, wrapAxiosInstance } from '@strapi/helper-plugin';
|
|
7
|
-
|
|
8
|
-
const instance = axios.create({
|
|
9
|
-
baseURL: process.env.STRAPI_ADMIN_BACKEND_URL,
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
instance.interceptors.request.use(
|
|
13
|
-
async (config) => {
|
|
14
|
-
config.headers = {
|
|
15
|
-
Authorization: `Bearer ${auth.getToken()}`,
|
|
16
|
-
Accept: 'application/json',
|
|
17
|
-
'Content-Type': 'application/json',
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
return config;
|
|
21
|
-
},
|
|
22
|
-
(error) => {
|
|
23
|
-
Promise.reject(error);
|
|
24
|
-
}
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
instance.interceptors.response.use(
|
|
28
|
-
(response) => response,
|
|
29
|
-
(error) => {
|
|
30
|
-
// whatever you want to do with the error
|
|
31
|
-
if (error.response?.status === 401) {
|
|
32
|
-
auth.clearAppStorage();
|
|
33
|
-
window.location.reload();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const wrapper = wrapAxiosInstance(instance);
|
|
41
|
-
|
|
42
|
-
export default wrapper;
|
package/assets/demo.gif
DELETED
|
Binary file
|
package/server/bootstrap.js
DELETED
package/server/index.js
DELETED
package/server/register.js
DELETED
package/strapi-admin.js
DELETED
package/strapi-server.js
DELETED