1
0
Fork 0
mirror of https://github.com/pawelmalak/flame.git synced 2025-07-23 21:29:37 +02:00

fix integrations

This commit is contained in:
François Darveau 2021-12-08 17:33:30 -05:00
parent e5154576b4
commit e7cd4d7705
21 changed files with 125 additions and 63 deletions

View file

@ -42,7 +42,7 @@ export const AppCard = (props: Props): JSX.Element => {
<div className={classes.Apps}> <div className={classes.Apps}>
{category.apps.map((app: App) => { {category.apps.map((app: App) => {
const redirectUrl = urlParser(app.url)[1]; const [displayUrl, redirectUrl] = urlParser(app.url);
let iconEl: JSX.Element = <Fragment></Fragment>; let iconEl: JSX.Element = <Fragment></Fragment>;
@ -89,8 +89,11 @@ export const AppCard = (props: Props): JSX.Element => {
rel="noreferrer" rel="noreferrer"
key={`app-${app.id}`} key={`app-${app.id}`}
> >
{app.icon && iconEl} {app.icon && iconEl}
{app.name} <div className={classes.AppCardDetails}>
<h5>{app.name}</h5>
<span>{displayUrl}</span>
</div>
</a> </a>
); );
})} })}

View file

@ -1,6 +1,8 @@
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Category } from '../../../interfaces'; import { Category } from '../../../interfaces';
import { State } from '../../../store/reducers';
import { Message } from '../../UI'; import { Message } from '../../UI';
import { AppCard } from '../AppCard/AppCard'; import { AppCard } from '../AppCard/AppCard';
import classes from './AppGrid.module.css'; import classes from './AppGrid.module.css';
@ -20,6 +22,10 @@ export const AppGrid = (props: Props): JSX.Element => {
fromHomepage = false, fromHomepage = false,
} = props; } = props;
const {
config: { config }
} = useSelector((state: State) => state);
let apps: JSX.Element; let apps: JSX.Element;
if (categories.length) { if (categories.length) {
@ -28,7 +34,7 @@ export const AppGrid = (props: Props): JSX.Element => {
} else { } else {
apps = ( apps = (
<div className={classes.AppGrid}> <div className={classes.AppGrid}>
{categories.map( {categories.filter((category : Category) => !config.hideEmptyCategories || category.apps.length > 0).map(
(category: Category): JSX.Element => ( (category: Category): JSX.Element => (
<AppCard <AppCard
category={category} category={category}

View file

@ -30,16 +30,9 @@ export const Apps = (props: Props): JSX.Element => {
// Get Redux action creators // Get Redux action creators
const dispatch = useDispatch(); const dispatch = useDispatch();
const { getCategories, setEditCategory, setEditApp } = const { setEditCategory, setEditApp } =
bindActionCreators(actionCreators, dispatch); bindActionCreators(actionCreators, dispatch);
// Load categories if array is empty
useEffect(() => {
if (!categories.length) {
getCategories();
}
}, []);
// Form // Form
const [modalIsOpen, setModalIsOpen] = useState(false); const [modalIsOpen, setModalIsOpen] = useState(false);
const [formContentType, setFormContentType] = useState(ContentType.category); const [formContentType, setFormContentType] = useState(ContentType.category);

View file

@ -1,6 +1,8 @@
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Category } from '../../../interfaces'; import { Category } from '../../../interfaces';
import { State } from '../../../store/reducers';
import { Message } from '../../UI'; import { Message } from '../../UI';
import { BookmarkCard } from '../BookmarkCard/BookmarkCard'; import { BookmarkCard } from '../BookmarkCard/BookmarkCard';
import classes from './BookmarkGrid.module.css'; import classes from './BookmarkGrid.module.css';
@ -20,6 +22,10 @@ export const BookmarkGrid = (props: Props): JSX.Element => {
fromHomepage = false, fromHomepage = false,
} = props; } = props;
const {
config: { config }
} = useSelector((state: State) => state);
let bookmarks: JSX.Element; let bookmarks: JSX.Element;
if (categories.length) { if (categories.length) {
@ -28,7 +34,7 @@ export const BookmarkGrid = (props: Props): JSX.Element => {
} else { } else {
bookmarks = ( bookmarks = (
<div className={classes.BookmarkGrid}> <div className={classes.BookmarkGrid}>
{categories.map( {categories.filter((category : Category) => !config.hideEmptyCategories || category.apps.length > 0).map(
(category: Category): JSX.Element => ( (category: Category): JSX.Element => (
<BookmarkCard <BookmarkCard
category={category} category={category}

View file

@ -30,16 +30,9 @@ export const Bookmarks = (props: Props): JSX.Element => {
// Get Redux action creators // Get Redux action creators
const dispatch = useDispatch(); const dispatch = useDispatch();
const { getCategories, setEditCategory, setEditBookmark } = const { setEditCategory, setEditBookmark } =
bindActionCreators(actionCreators, dispatch); bindActionCreators(actionCreators, dispatch);
// Load categories if array is empty
useEffect(() => {
if (!categories.length) {
getCategories();
}
}, []);
// Form // Form
const [modalIsOpen, setModalIsOpen] = useState(false); const [modalIsOpen, setModalIsOpen] = useState(false);
const [formContentType, setFormContentType] = useState(ContentType.category); const [formContentType, setFormContentType] = useState(ContentType.category);

View file

@ -283,7 +283,7 @@ export const UISettings = (): JSX.Element => {
</select> </select>
</InputGroup> </InputGroup>
{/* HIDE CATEGORIES */} {/* HIDE BOOKMARKS */}
<InputGroup> <InputGroup>
<label htmlFor="hideBookmarks">Hide bookmarks</label> <label htmlFor="hideBookmarks">Hide bookmarks</label>
<select <select
@ -297,6 +297,20 @@ export const UISettings = (): JSX.Element => {
</select> </select>
</InputGroup> </InputGroup>
{/* HIDE EMPTY CATEGORIES */}
<InputGroup>
<label htmlFor="hideEmptyCategories">Hide empty categories</label>
<select
id="hideEmptyCategories"
name="hideEmptyCategories"
value={formData.hideEmptyCategories ? 1 : 0}
onChange={(e) => inputChangeHandler(e, { isBool: true })}
>
<option value={1}>True</option>
<option value={0}>False</option>
</select>
</InputGroup>
<Button>Save changes</Button> <Button>Save changes</Button>
</form> </form>
); );

View file

@ -16,6 +16,7 @@ export interface Config {
searchSameTab: boolean; searchSameTab: boolean;
hideApps: boolean; hideApps: boolean;
hideBookmarks: boolean; hideBookmarks: boolean;
hideEmptyCategories: boolean;
hideSearch: boolean; hideSearch: boolean;
defaultSearchProvider: string; defaultSearchProvider: string;
dockerApps: boolean; dockerApps: boolean;

View file

@ -23,6 +23,7 @@ export interface OtherSettingsForm {
hideHeader: boolean; hideHeader: boolean;
hideApps: boolean; hideApps: boolean;
hideBookmarks: boolean; hideBookmarks: boolean;
hideEmptyCategories: boolean;
useOrdering: string; useOrdering: string;
appsSameTab: boolean; appsSameTab: boolean;
bookmarksSameTab: boolean; bookmarksSameTab: boolean;

View file

@ -5,8 +5,6 @@ import { Action } from '../actions';
import { categoriesReducer, CategoriesState } from './category'; import { categoriesReducer, CategoriesState } from './category';
interface AppsState extends CategoriesState { interface AppsState extends CategoriesState {
loading: boolean;
errors: string | undefined;
categories: Category[]; categories: Category[];
categoryInEdit: Category | null; categoryInEdit: Category | null;
appInEdit: App | null; appInEdit: App | null;

View file

@ -5,8 +5,6 @@ import { Action } from '../actions';
import { categoriesReducer, CategoriesState } from './category'; import { categoriesReducer, CategoriesState } from './category';
interface BookmarksState extends CategoriesState { interface BookmarksState extends CategoriesState {
loading: boolean;
errors: string | undefined;
categories: Category[]; categories: Category[];
categoryInEdit: Category | null; categoryInEdit: Category | null;
bookmarkInEdit: Bookmark | null; bookmarkInEdit: Bookmark | null;

View file

@ -16,6 +16,7 @@ export const configTemplate: Config = {
searchSameTab: false, searchSameTab: false,
hideApps: false, hideApps: false,
hideBookmarks: false, hideBookmarks: false,
hideEmptyCategories: true,
hideSearch: false, hideSearch: false,
defaultSearchProvider: 'l', defaultSearchProvider: 'l',
dockerApps: false, dockerApps: false,

View file

@ -8,6 +8,7 @@ export const otherSettingsTemplate: OtherSettingsForm = {
hideHeader: false, hideHeader: false,
hideApps: false, hideApps: false,
hideBookmarks: false, hideBookmarks: false,
hideEmptyCategories: true,
useOrdering: 'createdAt', useOrdering: 'createdAt',
appsSameTab: false, appsSameTab: false,
bookmarksSameTab: false, bookmarksSameTab: false,

View file

@ -115,7 +115,7 @@ const useDocker = async (apps) => {
const icons = labels['flame.icon'] ? labels['flame.icon'].split(';') : []; const icons = labels['flame.icon'] ? labels['flame.icon'].split(';') : [];
for (let i = 0; i < names.length; i++) { for (let i = 0; i < names.length; i++) {
const category = categoriesLabels[i] ? categories.find(category => category.name.toUpperCase() === categoriesLabels[i].toUpperCase()) : dockerDefaultCategory; let category = categoriesLabels[i] ? categories.find(category => category.name.toUpperCase() === categoriesLabels[i].toUpperCase()) : dockerDefaultCategory;
if (!category) { if (!category) {
category = await createNewCategory(categoriesLabels[i]); category = await createNewCategory(categoriesLabels[i]);
if (category) { if (category) {
@ -129,7 +129,7 @@ const useDocker = async (apps) => {
name: names[i] || names[0], name: names[i] || names[0],
url: urls[i] || urls[0], url: urls[i] || urls[0],
icon: icons[i] || 'docker', icon: icons[i] || 'docker',
category: category.id, categoryId: category.id,
orderId: orders[i] || 500, orderId: orders[i] || 500,
}); });
} }
@ -141,7 +141,6 @@ const useDocker = async (apps) => {
await app.update({ isPinned: false }); await app.update({ isPinned: false });
} }
} }
for (const item of dockerApps) { for (const item of dockerApps) {
// If app already exists, update it // If app already exists, update it
if (apps.some((app) => app.name === item.name)) { if (apps.some((app) => app.name === item.name)) {

View file

@ -67,7 +67,7 @@ const useKubernetes = async (apps) => {
const icons = annotations['flame.pawelmalak/icon'] ? annotations['flame.pawelmalak/icon'].split(';') : []; const icons = annotations['flame.pawelmalak/icon'] ? annotations['flame.pawelmalak/icon'].split(';') : [];
for (let i = 0; i < names.length; i++) { for (let i = 0; i < names.length; i++) {
const category = categoriesLabels[i] ? categories.find(category => category.name.toUpperCase() === categoriesLabels[i].toUpperCase()) : kubernetesDefaultCategory; let category = categoriesLabels[i] ? categories.find(category => category.name.toUpperCase() === categoriesLabels[i].toUpperCase()) : kubernetesDefaultCategory;
if (!category) { if (!category) {
category = await createNewCategory(categoriesLabels[i]); category = await createNewCategory(categoriesLabels[i]);
if (category) { if (category) {
@ -81,7 +81,7 @@ const useKubernetes = async (apps) => {
name: names[i] || names[0], name: names[i] || names[0],
url: urls[i] || urls[0], url: urls[i] || urls[0],
icon: icons[i] || 'kubernetes', icon: icons[i] || 'kubernetes',
category: category.id, categoryId: category.id,
orderId: orders[i] || 500, orderId: orders[i] || 500,
}); });
} }

View file

@ -10,12 +10,11 @@ const { useKubernetes, useDocker } = require('./docker');
// @access Public // @access Public
const getAllApps = asyncWrapper(async (req, res, next) => { const getAllApps = asyncWrapper(async (req, res, next) => {
const { const {
useOrdering: orderType, useOrdering: orderType
dockerApps: useDockerAPI,
kubernetesApps: useKubernetesAPI,
} = await loadConfig(); } = await loadConfig();
let apps = await loadIntegrationsApps(); // Load apps to create/update apps from integrations (Docker, Kubernetes, etc.)
await initIntegrationsApps();
// apps visibility // apps visibility
const where = req.isAuthenticated ? {} : { isPublic: true }; const where = req.isAuthenticated ? {} : { isPublic: true };
@ -44,26 +43,4 @@ const getAllApps = asyncWrapper(async (req, res, next) => {
}); });
}); });
const loadIntegrationsApps = asyncWrapper(async () => { module.exports = getAllApps;
const {
dockerApps: useDockerAPI,
kubernetesApps: useKubernetesAPI,
} = await loadConfig();
let apps;
if (useDockerAPI) {
await useDocker(apps);
}
if (useKubernetesAPI) {
await useKubernetes(apps);
}
return apps;
});
module.exports = {
getAllApps,
loadIntegrationsApps
}

View file

@ -0,0 +1,42 @@
const asyncWrapper = require('../../middleware/asyncWrapper');
const App = require('../../models/App');
const { Sequelize } = require('sequelize');
const loadConfig = require('../../utils/loadConfig');
const { useKubernetes, useDocker } = require('./docker');
// @desc Get all apps
// @route GET /api/integrationsApps
// @access Public
const getIntegrationsApps = asyncWrapper(async (req, res, next) => {
const {
useOrdering: orderType,
dockerApps: useDockerAPI,
kubernetesApps: useKubernetesAPI,
} = await loadConfig();
let apps;
if (useDockerAPI) {
await useDocker(apps);
}
if (useKubernetesAPI) {
await useKubernetes(apps);
}
if (process.env.NODE_ENV === 'production') {
// Set header to fetch containers info every time
return res.status(200).setHeader('Cache-Control', 'no-store').json({
success: true,
data: apps,
});
}
res.status(200).json({
success: true,
data: apps,
});
});
module.exports = getIntegrationsApps;

View file

@ -4,5 +4,5 @@ module.exports = {
deleteApp: require('./deleteApp'), deleteApp: require('./deleteApp'),
updateApp: require('./updateApp'), updateApp: require('./updateApp'),
reorderApps: require('./reorderApps'), reorderApps: require('./reorderApps'),
getAllApps: require('./getAllApps').getAllApps, getAllApps: require('./getAllApps'),
}; };

View file

@ -4,7 +4,7 @@ const App = require('../../models/App');
const Bookmark = require('../../models/Bookmark'); const Bookmark = require('../../models/Bookmark');
const { Sequelize } = require('sequelize'); const { Sequelize } = require('sequelize');
const loadConfig = require('../../utils/loadConfig'); const loadConfig = require('../../utils/loadConfig');
const loadIntegrationsApps = require('../apps/getAllApps').loadIntegrationsApps; const initIntegrationsApps = require('../../utils/init/initIntegrationsApps');
// @desc Get all categories // @desc Get all categories
// @route GET /api/categories // @route GET /api/categories
@ -12,8 +12,8 @@ const loadIntegrationsApps = require('../apps/getAllApps').loadIntegrationsApps;
const getAllCategories = asyncWrapper(async (req, res, next) => { const getAllCategories = asyncWrapper(async (req, res, next) => {
const { useOrdering: orderType } = await loadConfig(); const { useOrdering: orderType } = await loadConfig();
// Load apps to create apps from integrations (Docker, Kubernetes, etc.) // Load apps to create/update apps from integrations (Docker, Kubernetes, etc.)
await loadIntegrationsApps(); await initIntegrationsApps();
let categories; let categories;
let output; let output;

View file

@ -13,6 +13,7 @@ const Sockets = require('./Sockets');
// Utils // Utils
const initApp = require('./utils/init'); const initApp = require('./utils/init');
const initIntegrationsApps = require('./utils/init/initIntegrationsApps');
const Logger = require('./utils/Logger'); const Logger = require('./utils/Logger');
const logger = new Logger(); const logger = new Logger();
@ -22,7 +23,10 @@ const logger = new Logger();
// Init app // Init app
await initApp(); await initApp();
await connectDB(); await connectDB();
await associateModels(); await associateModels();
// Load apps to create/update apps from integrations (Docker, Kubernetes, etc.)
await initIntegrationsApps();
// Create server for Express API and WebSockets // Create server for Express API and WebSockets
const server = http.createServer(); const server = http.createServer();

View file

@ -0,0 +1,24 @@
const { useKubernetes, useDocker } = require('../../controllers/apps/docker');
const asyncWrapper = require('../../middleware/asyncWrapper');
const loadConfig = require('../loadConfig');
const loadIntegrationsApps = asyncWrapper(async () => {
const {
dockerApps: useDockerAPI,
kubernetesApps: useKubernetesAPI,
} = await loadConfig();
let apps;
if (useDockerAPI) {
await useDocker(apps);
}
if (useKubernetesAPI) {
await useKubernetes(apps);
}
return apps;
});
module.exports = loadIntegrationsApps;

View file

@ -14,6 +14,7 @@
"searchSameTab": false, "searchSameTab": false,
"hideApps": false, "hideApps": false,
"hideBookmarks": false, "hideBookmarks": false,
"hideEmptyCategories": true,
"hideSearch": false, "hideSearch": false,
"defaultSearchProvider": "l", "defaultSearchProvider": "l",
"dockerApps": false, "dockerApps": false,