diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..3944512 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +webpack.config.* \ No newline at end of file diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..7d8f360 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,19 @@ +{ + "parser": "babel-eslint", + "extends": ["eslint:recommended", "plugin:react/recommended"], + "env": { + "commonjs": true, + "es6": true, + "node": true, + "browser": false + }, + "globals": { + "strapi": true, + "alert": true, + "window": true + }, + "rules": { + "no-unused-vars": "warn", + "react/prop-types": "warn" + } +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..725a7fb --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +node_modules +.cache +.tmp +build \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..65fc2a7 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "printWidth": 120, + "singleQuote": true, + "useTabs": false, + "tabWidth": 2, + "semi": true, + "bracketSpacing": true, + "trailingComma": "all", + "arrowParens": "always" +} diff --git a/admin/src/index.js b/admin/src/index.js index 474ec55..9af60c2 100644 --- a/admin/src/index.js +++ b/admin/src/index.js @@ -1,12 +1,11 @@ -import pluginPkg from "../../package.json"; -import pluginId from "./pluginId"; -import Initializer from "./containers/Initializer"; -import lifecycles from "./lifecycles"; -import trads from "./translations"; +import pluginPkg from '../../package.json'; +import pluginId from './pluginId'; +import Initializer from './containers/Initializer'; +import lifecycles from './lifecycles'; +import trads from './translations'; export default (strapi) => { - const pluginDescription = - pluginPkg.strapi.description || pluginPkg.description; + const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; const plugin = { blockerComponent: null, diff --git a/admin/src/pluginId.js b/admin/src/pluginId.js index 1b059dd..85ad709 100644 --- a/admin/src/pluginId.js +++ b/admin/src/pluginId.js @@ -1,7 +1,4 @@ const pluginPkg = require('../../package.json'); -const pluginId = pluginPkg.name.replace( - /^strapi-plugin-/i, - '' -); +const pluginId = pluginPkg.name.replace(/^strapi-plugin-/i, ''); module.exports = pluginId; diff --git a/admin/src/utils/getTrad.js b/admin/src/utils/getTrad.js index a2b8632..d0a071b 100644 --- a/admin/src/utils/getTrad.js +++ b/admin/src/utils/getTrad.js @@ -1,5 +1,5 @@ import pluginId from '../pluginId'; -const getTrad = id => `${pluginId}.${id}`; +const getTrad = (id) => `${pluginId}.${id}`; export default getTrad; diff --git a/controllers/image-api.js b/controllers/image-api.js index 97e0893..030bdfb 100644 --- a/controllers/image-api.js +++ b/controllers/image-api.js @@ -1,9 +1,9 @@ -"use strict"; -const axios = require("axios"); -const _ = require("lodash"); -const FileType = require("file-type"); -const { v4: uuidv4 } = require("uuid"); -const pluginId = require("../admin/src/pluginId"); +'use strict'; +const axios = require('axios'); +const _ = require('lodash'); +const FileType = require('file-type'); +const { v4: uuidv4 } = require('uuid'); +const pluginId = require('../admin/src/pluginId'); /** * image-api.js controller @@ -20,62 +20,51 @@ module.exports = { searchUnsplashImages: async (ctx) => { const { pageNumber, query, pageCount } = ctx.request.body; const { providerOptions } = strapi.plugins[pluginId].config; - if (!providerOptions || !providerOptions["unsplash"]) { + if (!providerOptions || !providerOptions['unsplash']) { return; } - const { accessKey } = providerOptions["unsplash"]; + const { accessKey } = providerOptions['unsplash']; if (!accessKey) { - throw new Error("Access Key must be provided"); + throw new Error('Access Key must be provided'); } const result = await axios - .get( - `https://api.unsplash.com/search/photos?page=${pageNumber}&query=${query}&pageCount=${pageCount}`, - { - headers: { - Authorization: `Client-ID ${accessKey}`, - }, - } - ) + .get(`https://api.unsplash.com/search/photos?page=${pageNumber}&query=${query}&pageCount=${pageCount}`, { + headers: { + Authorization: `Client-ID ${accessKey}`, + }, + }) .catch(({ message }) => { - alert("failed to get image " + message); + alert('failed to get image ' + message); }); const { data } = result; return data; }, importUnsplashImage: async (ctx) => { - const { - id, - fileName = uuidv4(), - altText = null, - caption = null, - } = ctx.request.body; + const { id, fileName = uuidv4(), altText = null, caption = null } = ctx.request.body; if (!id || !fileName) { // throw error return; } const { providerOptions } = strapi.plugins[pluginId].config; - if (!providerOptions || !providerOptions["unsplash"]) { + if (!providerOptions || !providerOptions['unsplash']) { return; } - const { accessKey, appName = "" } = providerOptions["unsplash"]; + const { accessKey, appName = '' } = providerOptions['unsplash']; if (!accessKey) { - throw new Error("Access Key must be provided"); + throw new Error('Access Key must be provided'); } - const response = await axios.get( - `https://api.unsplash.com/photos/${id}/download`, - { - headers: { - authorization: `Client-ID ${accessKey}`, - }, - } - ); + const response = await axios.get(`https://api.unsplash.com/photos/${id}/download`, { + headers: { + authorization: `Client-ID ${accessKey}`, + }, + }); const getImageUrl = response.data.url; const imageResponse = await axios.get(getImageUrl, { - responseType: "arraybuffer", + responseType: 'arraybuffer', }); const readBuffer = Buffer.from(imageResponse.data); - const { ext, mime } = await FileType.fromBuffer(readBuffer); - const { optimize } = strapi.plugins.upload.services["image-manipulation"]; + const { mime } = await FileType.fromBuffer(readBuffer); + const { optimize } = strapi.plugins.upload.services['image-manipulation']; const { buffer, info } = await optimize(readBuffer); const metas = {}; const fileInfo = { alternativeText: altText, caption }; @@ -85,15 +74,13 @@ module.exports = { type: mime, }, fileInfo, - metas + metas, ); const fileData = _.assign(formattedFile, info, { buffer, }); - const result = await strapi.plugins.upload.services.upload.uploadFileAndPersist( - fileData - ); + const result = await strapi.plugins.upload.services.upload.uploadFileAndPersist(fileData); const { url } = result; ctx.send({ url, diff --git a/example/extensions/content-manager/admin/src/components/WysiwygWithErrors/index.js b/example/extensions/content-manager/admin/src/components/WysiwygWithErrors/index.js index d592f37..d482acf 100644 --- a/example/extensions/content-manager/admin/src/components/WysiwygWithErrors/index.js +++ b/example/extensions/content-manager/admin/src/components/WysiwygWithErrors/index.js @@ -4,17 +4,17 @@ * */ -import React from "react"; -import PropTypes from "prop-types"; -import { isEmpty, isFunction } from "lodash"; -import cn from "classnames"; +import React from 'react'; +import PropTypes from 'prop-types'; +import { isEmpty, isFunction } from 'lodash'; +import cn from 'classnames'; -import { Description, ErrorMessage, Label } from "@buffetjs/styles"; -import { Error } from "@buffetjs/core"; +import { Description, ErrorMessage, Label } from '@buffetjs/styles'; +import { Error } from '@buffetjs/core'; -import Wysiwyg from "../Wysiwyg"; -import Wrapper from "./Wrapper"; -import { ImageApiPanel } from "strapi-plugin-image-api/build"; +import Wysiwyg from '../Wysiwyg'; +import Wrapper from './Wrapper'; +import { ImageApiPanel } from 'strapi-plugin-image-api/build'; // eslint-disable-next-line react/prefer-stateless-function class WysiwygWithErrors extends React.Component { @@ -42,27 +42,14 @@ class WysiwygWithErrors extends React.Component { } = this.props; return ( - + {({ canCheck, onBlur, error, dispatch }) => { const hasError = error && error !== null; return ( - + - + { if (!canCheck) { dispatch({ - type: "SET_CHECK", + type: 'SET_CHECK', }); } dispatch({ - type: "SET_ERROR", + type: 'SET_ERROR', error: null, }); onChange(e); @@ -91,9 +78,7 @@ class WysiwygWithErrors extends React.Component { tabIndex={tabIndex} value={value} /> - {!hasError && inputDescription && ( - {inputDescription} - )} + {!hasError && inputDescription && {inputDescription}} {hasError && {error}} ); @@ -105,20 +90,20 @@ class WysiwygWithErrors extends React.Component { WysiwygWithErrors.defaultProps = { autoFocus: false, - className: "", + className: '', deactivateErrorHighlight: false, didCheckErrors: false, disabled: false, error: null, - inputClassName: "", - inputDescription: "", + inputClassName: '', + inputDescription: '', inputStyle: {}, - label: "", + label: '', onBlur: false, - placeholder: "", + placeholder: '', resetProps: false, style: {}, - tabIndex: "0", + tabIndex: '0', validations: {}, value: null, }; diff --git a/example/extensions/users-permissions/config/jwt.js b/example/extensions/users-permissions/config/jwt.js index c65d1b6..caab8da 100644 --- a/example/extensions/users-permissions/config/jwt.js +++ b/example/extensions/users-permissions/config/jwt.js @@ -1,3 +1,3 @@ module.exports = { - jwtSecret: process.env.JWT_SECRET || '0528903e-1e80-411a-95df-cd2af6d2eb7a' -}; \ No newline at end of file + jwtSecret: process.env.JWT_SECRET || '0528903e-1e80-411a-95df-cd2af6d2eb7a', +}; diff --git a/index.js b/index.js index e36170c..823588e 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,3 @@ -import ImageApiPanel from "./src/components/ImageApi/ImageApiPanel"; +import ImageApiPanel from './src/components/ImageApi/ImageApiPanel'; export { ImageApiPanel }; diff --git a/package.json b/package.json index 7fe1dcb..0af2580 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,17 @@ "version": "0.0.0", "description": "This is the description of the plugin.", "main": "./index.js", + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "**/*.{js,jsx,ts,tsx}": [ + "npx prettier --write", + "eslint *.js --fix-dry-run" + ] + }, "strapi": { "name": "Image Api", "icon": "plug", @@ -12,7 +23,8 @@ "prepublish": "npm run build", "start": "webpack --watch", "build": "webpack", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "format": "prettier --config .prettierrc \"**/*.{js,html,md}\" --write" }, "author": { "name": "Kwinten", @@ -37,9 +49,17 @@ "@babel/preset-react": "^7.10.1", "@buffetjs/core": "^3.1.1", "@buffetjs/custom": "^3.1.1", + "babel-eslint": "^10.1.0", "babel-loader": "^8.1.0", "css-loader": "^3.5.3", + "eslint": "^7.2.0", + "eslint-plugin-import": "^2.21.2", + "eslint-plugin-jsx-a11y": "^6.2.3", + "eslint-plugin-react": "^7.20.0", "file-loader": "^6.0.0", + "husky": "^4.2.5", + "lint-staged": "^10.2.11", + "prettier": "^2.0.5", "react": "^16.13.1", "react-dom": "^16.13.1", "strapi-helper-plugin": "^3.0.0", diff --git a/services/image-api.js b/services/image-api.js index 5b4a84f..607648d 100644 --- a/services/image-api.js +++ b/services/image-api.js @@ -1,4 +1,4 @@ -"use strict"; +'use strict'; /** * image-api.js service diff --git a/src/components/ImageApi/ImageApiModal.js b/src/components/ImageApi/ImageApiModal.js index 4a9d44e..ea8f2eb 100644 --- a/src/components/ImageApi/ImageApiModal.js +++ b/src/components/ImageApi/ImageApiModal.js @@ -1,14 +1,9 @@ -import React from "react"; -import { - Modal, - ModalBody, - ModalFooter, - HeaderModalTitle, -} from "strapi-helper-plugin"; -import styled from "styled-components"; -import { Inputs } from "@buffetjs/custom"; -import { Button } from "@buffetjs/core"; -import { Container } from "reactstrap"; +import React from 'react'; +import { Modal, ModalBody, ModalFooter, HeaderModalTitle } from 'strapi-helper-plugin'; +import styled from 'styled-components'; +import { Inputs } from '@buffetjs/custom'; +import { Button } from '@buffetjs/core'; +import { Container } from 'reactstrap'; const StyledImg = styled.img` flex: 1 1 100%; @@ -37,9 +32,9 @@ const Wrapper = styled(ContainerFluid)` const ModalHeaderWrapper = styled.div` height: 59px; line-height: 59px; - background-color: "#fafafa"; - color: "#333740"; - font-size: "13px"; + background-color: '#fafafa'; + color: '#333740'; + font-size: '13px'; font-weight: 600; `; @@ -53,18 +48,10 @@ const ModalHeader = ({ children }) => { ); }; -const ImageApiModal = ({ - isOpen, - setIsOpen, - targetImage, - setFileName, - setCaption, - setAltText, - handleSubmit, -}) => { +const ImageApiModal = ({ isOpen, setIsOpen, targetImage, setFileName, setCaption, setAltText, handleSubmit }) => { const handleToggle = () => { // eslint-disable-next-line no-alert - const confirm = window.confirm("Confirm to close without save?"); + const confirm = window.confirm('Confirm to close without save?'); if (!confirm) { return; @@ -79,24 +66,17 @@ const ImageApiModal = ({ Details -
+
- {targetImage && targetImage.src ? ( - - ) : null} + {targetImage && targetImage.src ? : null}
- +
- +
- -
diff --git a/src/components/ImageApi/ImageApiPanel.js b/src/components/ImageApi/ImageApiPanel.js index 911513c..5cb389e 100644 --- a/src/components/ImageApi/ImageApiPanel.js +++ b/src/components/ImageApi/ImageApiPanel.js @@ -1,10 +1,10 @@ -import React, { useState } from "react"; -import styled from "styled-components"; -import { GlobalPagination, InputsIndex as Input } from "strapi-helper-plugin"; -import ImageApiModal from "./ImageApiModal"; -import { v4 as uuidv4 } from "uuid"; -import { Button } from "@buffetjs/core"; -import axios from "axios"; +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { GlobalPagination, InputsIndex as Input } from 'strapi-helper-plugin'; +import ImageApiModal from './ImageApiModal'; +import { v4 as uuidv4 } from 'uuid'; +import { Button } from '@buffetjs/core'; +import axios from 'axios'; const ImageApiSearchContainer = styled.div` border: 1px solid #e3e9f3; @@ -61,7 +61,7 @@ const ImageApiPanel = ({ editor, onEditorChange }) => { _limit: 10, }); const [targetImage, setTargetImage] = useState({}); - const [query, setQuery] = useState(""); + const [query, setQuery] = useState(''); const [focused, setFocused] = useState(true); const [imageList, setImageList] = useState([]); @@ -85,25 +85,15 @@ const ImageApiPanel = ({ editor, onEditorChange }) => { pageCount, }) .catch(({ message }) => { - alert("Failed to get images due to " + message); + alert('Failed to get images due to ' + message); }); setImageList(data); }; - const onImageClicked = async ({ - id, - description, - userName, - userProfileUrl, - src, - }) => { + const onImageClicked = async ({ id, description, userName, userProfileUrl, src }) => { setIsOpen(true); const fileName = - description && - description.split(" ").length <= 10 && - description.length <= 100 - ? description - : uuidv4(); + description && description.split(' ').length <= 10 && description.length <= 100 ? description : uuidv4(); setTargetImage({ id, src, userName, userProfileUrl, fileName }); }; const setFileName = (event) => { @@ -116,7 +106,7 @@ const ImageApiPanel = ({ editor, onEditorChange }) => { setTargetImage({ ...targetImage, altText: event.target.value }); }; const onImageImported = (content) => { - const newValue = editor.value ? editor.value : "" + content; + const newValue = editor.value ? editor.value : '' + content; onEditorChange({ target: { name: editor.name, value: newValue } }); }; @@ -154,13 +144,7 @@ const ImageApiPanel = ({ editor, onEditorChange }) => { />