add documentation urls
start implementing disable app modal
This commit is contained in:
parent
b09cec5a8d
commit
66fac852f5
2 changed files with 63 additions and 2 deletions
|
@ -6,24 +6,28 @@ export const appAccessList = [
|
||||||
image: '/assets/wekan.svg',
|
image: '/assets/wekan.svg',
|
||||||
label: 'Wekan',
|
label: 'Wekan',
|
||||||
defaultSubdomain: 'wekan.{domain}',
|
defaultSubdomain: 'wekan.{domain}',
|
||||||
|
documentationUrl: 'https://github.com/wekan/wekan/wiki',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'wordpress',
|
name: 'wordpress',
|
||||||
image: '/assets/wordpress.svg',
|
image: '/assets/wordpress.svg',
|
||||||
label: 'Wordpress',
|
label: 'Wordpress',
|
||||||
defaultSubdomain: 'www.{domain}',
|
defaultSubdomain: 'www.{domain}',
|
||||||
|
documentationUrl: 'https://wordpress.org/support/',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'nextcloud',
|
name: 'nextcloud',
|
||||||
image: '/assets/nextcloud.svg',
|
image: '/assets/nextcloud.svg',
|
||||||
label: 'Nextcloud',
|
label: 'Nextcloud',
|
||||||
defaultSubdomain: 'files.{domain}',
|
defaultSubdomain: 'files.{domain}',
|
||||||
|
documentationUrl: 'https://docs.nextcloud.com/server/latest/user_manual/en/',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'zulip',
|
name: 'zulip',
|
||||||
image: '/assets/zulip.svg',
|
image: '/assets/zulip.svg',
|
||||||
label: 'Zulip',
|
label: 'Zulip',
|
||||||
defaultSubdomain: 'zulip.{domain}',
|
defaultSubdomain: 'zulip.{domain}',
|
||||||
|
documentationUrl: 'https://docs.zulip.com/help/',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { XCircleIcon } from '@heroicons/react/outline';
|
import { XCircleIcon } from '@heroicons/react/outline';
|
||||||
import { useApps } from 'src/services/apps';
|
import { useApps } from 'src/services/apps';
|
||||||
import { Tabs } from 'src/components';
|
import { Modal, Tabs } from 'src/components';
|
||||||
import { appAccessList } from 'src/components/UserModal/consts';
|
import { appAccessList } from 'src/components/UserModal/consts';
|
||||||
import { AdvancedTab, GeneralTab } from './components';
|
import { AdvancedTab, GeneralTab } from './components';
|
||||||
|
|
||||||
export const AppSingle: React.FC = () => {
|
export const AppSingle: React.FC = () => {
|
||||||
|
const [disableApp, setDisableApp] = useState(false);
|
||||||
|
const [removeAppData, setRemoveAppData] = useState(false);
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
const appSlug = params.slug;
|
const appSlug = params.slug;
|
||||||
const { app, loadApp } = useApps();
|
const { app, loadApp } = useApps();
|
||||||
|
@ -23,6 +25,11 @@ export const AppSingle: React.FC = () => {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const appImageSrc = _.find(appAccessList, { name: appSlug })?.image;
|
const appImageSrc = _.find(appAccessList, { name: appSlug })?.image;
|
||||||
|
const appDocumentationUrl = _.find(appAccessList, { name: appSlug })?.documentationUrl;
|
||||||
|
|
||||||
|
const openDocumentationInNewTab = () => {
|
||||||
|
window.open(appDocumentationUrl, '_blank', 'noopener,noreferrer');
|
||||||
|
};
|
||||||
|
|
||||||
const handleAutomaticUpdatesChange = () => {
|
const handleAutomaticUpdatesChange = () => {
|
||||||
app.automaticUpdates = !app.automaticUpdates;
|
app.automaticUpdates = !app.automaticUpdates;
|
||||||
|
@ -36,6 +43,10 @@ export const AppSingle: React.FC = () => {
|
||||||
{ name: 'Advanced Configuration', component: <AdvancedTab /> },
|
{ name: 'Advanced Configuration', component: <AdvancedTab /> },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const onDisableApp = () => {
|
||||||
|
// TODO: implement
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-7xl mx-auto py-4 sm:px-6 lg:px-8 overflow-hidden lg:flex lg:flex-row">
|
<div className="max-w-7xl mx-auto py-4 sm:px-6 lg:px-8 overflow-hidden lg:flex lg:flex-row">
|
||||||
<div
|
<div
|
||||||
|
@ -51,6 +62,7 @@ export const AppSingle: React.FC = () => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="mb-3 inline-flex items-center px-4 py-2 shadow-sm text-sm font-medium rounded-md text-yellow-900 bg-yellow-300 hover:bg-yellow-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 justify-center"
|
className="mb-3 inline-flex items-center px-4 py-2 shadow-sm text-sm font-medium rounded-md text-yellow-900 bg-yellow-300 hover:bg-yellow-400 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 justify-center"
|
||||||
|
onClick={() => setDisableApp(true)}
|
||||||
>
|
>
|
||||||
<XCircleIcon className="-ml-0.5 mr-2 h-4 w-4 text-yellow-900" aria-hidden="true" />
|
<XCircleIcon className="-ml-0.5 mr-2 h-4 w-4 text-yellow-900" aria-hidden="true" />
|
||||||
Disable App
|
Disable App
|
||||||
|
@ -58,6 +70,7 @@ export const AppSingle: React.FC = () => {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="inline-flex items-center px-4 py-2 border border-gray-200 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 justify-center"
|
className="inline-flex items-center px-4 py-2 border border-gray-200 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500 justify-center"
|
||||||
|
onClick={openDocumentationInNewTab}
|
||||||
>
|
>
|
||||||
View manual
|
View manual
|
||||||
</button>
|
</button>
|
||||||
|
@ -71,6 +84,50 @@ export const AppSingle: React.FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{disableApp && (
|
||||||
|
<Modal onClose={() => setDisableApp(false)} open={disableApp} onSave={onDisableApp} useCancelButton>
|
||||||
|
<div className="bg-white px-4">
|
||||||
|
<div className="space-y-10 divide-y divide-gray-200">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg leading-6 font-medium text-gray-900">Disable app</h3>
|
||||||
|
</div>
|
||||||
|
<div className="px-4 py-5 sm:p-6">
|
||||||
|
Are you sure you want to disable {app.name}? The app will get uninstalled and none of your users will
|
||||||
|
be able to access the app.
|
||||||
|
</div>
|
||||||
|
<fieldset className="space-y-5 -mt-4">
|
||||||
|
<legend className="sr-only">Remove app data</legend>
|
||||||
|
<div className="relative flex items-start">
|
||||||
|
<div className="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
id="comments"
|
||||||
|
aria-describedby="comments-description"
|
||||||
|
name="disableAppData"
|
||||||
|
type="checkbox"
|
||||||
|
checked={removeAppData}
|
||||||
|
onChange={() => setRemoveAppData(!removeAppData)}
|
||||||
|
className="focus:ring-primary-500 h-4 w-4 text-primary-600 border-gray-300 rounded"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="ml-3 text-sm">
|
||||||
|
<label htmlFor="comments" className="font-medium text-gray-700">
|
||||||
|
Remove app data
|
||||||
|
</label>
|
||||||
|
<p id="comments-description" className="text-gray-500">
|
||||||
|
{removeAppData
|
||||||
|
? `The app's data will be removed. After this operation is done you will not be able to access the app, nor the app data. If you re-install the app, it will have none of the data it had before.`
|
||||||
|
: `The app's data does not get removed. If you install the app again, you will be able to access the data again.`}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue