+ |
+
+ {plugin.title}
+
+ {plugin.name}
+ |
+ {plugin.description} |
+ {plugin.author} |
+ {plugin.version} |
+
+ {allDeps.length === 0 ? (
+ {t('admin.noDependencies')}
+ ) : (
+
+ {allDeps.map(([name, constraint]) => {
+ const classes = [
+ 'mb-1',
+ 'badge',
+ `bg-${unsatisfied.includes(name) ? 'red' : 'green'}`,
+ ]
+ return (
+
+ {name}: {constraint}
+
+ )
+ })}
+
+ )}
+ |
+
+ {plugin.can_update ? (
+
+ ) : (
+
+ )}
+ |
+
+ )
+}
+
+export default Row
diff --git a/resources/assets/src/views/admin/PluginsMarket/index.tsx b/resources/assets/src/views/admin/PluginsMarket/index.tsx
new file mode 100644
index 00000000..bbd40deb
--- /dev/null
+++ b/resources/assets/src/views/admin/PluginsMarket/index.tsx
@@ -0,0 +1,162 @@
+import React, { useState, useEffect, useMemo } from 'react'
+import { hot } from 'react-hot-loader/root'
+import { enableMapSet } from 'immer'
+import { useImmer } from 'use-immer'
+import { t } from '@/scripts/i18n'
+import * as fetch from '@/scripts/net'
+import { toast, showModal } from '@/scripts/notify'
+import Loading from '@/components/Loading'
+import Pagination from '@/components/Pagination'
+import { Plugin } from './types'
+import Row from './Row'
+
+enableMapSet()
+
+const PluginsMarket: React.FC = () => {
+ const [plugins, setPlugins] = useImmer