0

Hide disabled features (#2473)

* Hide/show on notify and fediverse feature disable/enable

* Update browser tests to enable features for testing

* Hide/show features in mobile action menu

* Do not show fediauth option if fediverse features are not enabled.

* Force showing tabs when in Storybook
This commit is contained in:
Gabe Kangas 2022-12-29 16:26:04 -08:00 committed by GitHub
parent 0eba1685b3
commit 533d33847c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 110 additions and 70 deletions

View File

@ -9,8 +9,8 @@ describe(`Basic tests`, () => {
// Offline banner // Offline banner
it('Has correct offline banner values', () => { it('Has correct offline banner values', () => {
cy.contains( cy.contains(
'This stream is offline. Be notified the next time New Owncast Server goes live.' 'This stream is offline. You can be notified the next time New Owncast Server goes live or follow streamer@testing.biz on the Fediverse.'
).should('be.visible'); ).should('exist');
}); });
// Verify the tags show up // Verify the tags show up

View File

@ -1,4 +1,5 @@
import { setup } from '../../support/setup.js'; import { setup } from '../../support/setup.js';
import fetchData from '../../support/fetchData.js';
setup(); setup();
@ -81,45 +82,3 @@ describe(`Live tests`, () => {
cy.visit('http://localhost:8080'); cy.visit('http://localhost:8080');
}); });
}); });
async function fetchData(url, options) {
const ADMIN_USERNAME = 'admin';
const ADMIN_STREAMKEY = 'abc123';
const { data, method = 'GET', auth = true } = options || {};
// eslint-disable-next-line no-undef
const requestOptions = {
method,
};
if (data) {
requestOptions.body = JSON.stringify(data);
}
if (auth && ADMIN_USERNAME && ADMIN_STREAMKEY) {
const encoded = btoa(`${ADMIN_USERNAME}:${ADMIN_STREAMKEY}`);
requestOptions.headers = {
Authorization: `Basic ${encoded}`,
};
requestOptions.mode = 'cors';
requestOptions.credentials = 'include';
}
try {
const response = await fetch(url, requestOptions);
const json = await response.json();
if (!response.ok) {
const message =
json.message || `An error has occurred: ${response.status}`;
throw new Error(message);
}
return json;
} catch (error) {
console.error(error);
return error;
// console.log(error)
// throw new Error(error)
}
}

View File

@ -1,5 +0,0 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@ -15,6 +15,21 @@
// Import commands.js using ES2015 syntax: // Import commands.js using ES2015 syntax:
import './commands'; import './commands';
import fetchData from './fetchData.js';
// Alternatively you can use CommonJS syntax: // Alternatively you can use CommonJS syntax:
// require('./commands') // require('./commands')
// Put Owncast in a state where it's ready to be tested.
// Set server URL
fetchData('http://localhost:8080/api/admin/config/serverurl', {
method: 'POST',
data: { value: 'https://testing.biz' },
});
// Enable Fediverse features.
fetchData('http://localhost:8080/api/admin/config/federation/enable', {
method: 'POST',
data: { value: true },
});

View File

@ -0,0 +1,43 @@
async function fetchData(url, options) {
const ADMIN_USERNAME = 'admin';
const ADMIN_STREAMKEY = 'abc123';
const { data, method = 'GET', auth = true } = options || {};
// eslint-disable-next-line no-undef
const requestOptions = {
method,
};
if (data) {
requestOptions.body = JSON.stringify(data);
}
if (auth && ADMIN_USERNAME && ADMIN_STREAMKEY) {
const encoded = btoa(`${ADMIN_USERNAME}:${ADMIN_STREAMKEY}`);
requestOptions.headers = {
Authorization: `Basic ${encoded}`,
};
requestOptions.mode = 'cors';
requestOptions.credentials = 'include';
}
try {
const response = await fetch(url, requestOptions);
const json = await response.json();
if (!response.ok) {
const message =
json.message || `An error has occurred: ${response.status}`;
throw new Error(message);
}
return json;
} catch (error) {
console.error(error);
return error;
// console.log(error)
// throw new Error(error)
}
}
export default fetchData;

View File

@ -21,7 +21,7 @@ const Example = () => {
return ( return (
<div> <div>
<AuthModal /> <AuthModal forceTabs />
</div> </div>
); );
}; };

View File

@ -12,18 +12,26 @@ import {
currentUserAtom, currentUserAtom,
chatAuthenticatedAtom, chatAuthenticatedAtom,
accessTokenAtom, accessTokenAtom,
clientConfigStateAtom,
} from '../../stores/ClientConfigStore'; } from '../../stores/ClientConfigStore';
import { ClientConfig } from '../../../interfaces/client-config.model';
export const AuthModal: FC = () => { export type AuthModalProps = {
forceTabs?: boolean;
};
export const AuthModal: FC<AuthModalProps> = ({ forceTabs }) => {
const authenticated = useRecoilValue<boolean>(chatAuthenticatedAtom); const authenticated = useRecoilValue<boolean>(chatAuthenticatedAtom);
const accessToken = useRecoilValue<string>(accessTokenAtom); const accessToken = useRecoilValue<string>(accessTokenAtom);
const currentUser = useRecoilValue(currentUserAtom); const currentUser = useRecoilValue(currentUserAtom);
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
if (!currentUser) { if (!currentUser) {
return null; return null;
} }
const { displayName } = currentUser; const { displayName } = currentUser;
const { federation } = clientConfig;
const federationEnabled = true; const { enabled: fediverseEnabled } = federation;
const indieAuthTabTitle = ( const indieAuthTabTitle = (
<span className={styles.tabContent}> <span className={styles.tabContent}>
@ -67,7 +75,7 @@ export const AuthModal: FC = () => {
items={items} items={items}
type="card" type="card"
size="small" size="small"
renderTabBar={federationEnabled ? null : () => null} renderTabBar={fediverseEnabled || forceTabs ? null : () => null}
/> />
</div> </div>
); );

View File

@ -3,6 +3,7 @@ import { Layout, Tabs, Skeleton } from 'antd';
import { FC, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import { LOCAL_STORAGE_KEYS, getLocalStorage, setLocalStorage } from '../../../utils/localStorage'; import { LOCAL_STORAGE_KEYS, getLocalStorage, setLocalStorage } from '../../../utils/localStorage';
import isPushNotificationSupported from '../../../utils/browserPushNotifications';
import { import {
clientConfigStateAtom, clientConfigStateAtom,
@ -66,16 +67,17 @@ const DesktopContent = ({
socialHandles, socialHandles,
extraPageContent, extraPageContent,
setShowFollowModal, setShowFollowModal,
supportFediverseFeatures,
}) => { }) => {
const aboutTabContent = <CustomPageContent content={extraPageContent} />; const aboutTabContent = <CustomPageContent content={extraPageContent} />;
const followersTabContent = ( const followersTabContent = (
<FollowerCollection name={name} onFollowButtonClick={() => setShowFollowModal(true)} /> <FollowerCollection name={name} onFollowButtonClick={() => setShowFollowModal(true)} />
); );
const items = [ const items = [{ label: 'About', key: '2', children: aboutTabContent }];
{ label: 'About', key: '2', children: aboutTabContent }, if (supportFediverseFeatures) {
{ label: 'Followers', key: '3', children: followersTabContent }, items.push({ label: 'Followers', key: '3', children: followersTabContent });
]; }
return ( return (
<> <>
@ -91,7 +93,7 @@ const DesktopContent = ({
</div> </div>
<div className={styles.lowerSection}> <div className={styles.lowerSection}>
<Tabs defaultActiveKey="0" items={items} /> {items.length > 1 ? <Tabs defaultActiveKey="0" items={items} /> : aboutTabContent}
</div> </div>
</> </>
); );
@ -111,6 +113,8 @@ const MobileContent = ({
setExternalActionToDisplay, setExternalActionToDisplay,
setShowNotifyPopup, setShowNotifyPopup,
setShowFollowModal, setShowFollowModal,
supportFediverseFeatures,
supportsBrowserNotifications,
}) => { }) => {
if (!currentUser) { if (!currentUser) {
return null; return null;
@ -153,8 +157,8 @@ const MobileContent = ({
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start' }}> <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start' }}>
<DefaultTabBar {...props} style={{ width: '85%' }} /> <DefaultTabBar {...props} style={{ width: '85%' }} />
<ActionButtonMenu <ActionButtonMenu
showFollowItem showFollowItem={supportFediverseFeatures}
showNotifyItem showNotifyItem={supportsBrowserNotifications}
actions={actions} actions={actions}
externalActionSelected={setExternalActionToDisplay} externalActionSelected={setExternalActionToDisplay}
notifyItemSelected={() => setShowNotifyPopup(true)} notifyItemSelected={() => setShowNotifyPopup(true)}
@ -217,11 +221,14 @@ export const Content: FC = () => {
const [showNotifyReminder, setShowNotifyReminder] = useState(false); const [showNotifyReminder, setShowNotifyReminder] = useState(false);
const [showNotifyModal, setShowNotifyModal] = useState(false); const [showNotifyModal, setShowNotifyModal] = useState(false);
const [showFollowModal, setShowFollowModal] = useState(false); const [showFollowModal, setShowFollowModal] = useState(false);
const { account: fediverseAccount } = federation; const { account: fediverseAccount, enabled: fediverseEnabled } = federation;
const { browser: browserNotifications } = notifications; const { browser: browserNotifications } = notifications;
const { enabled: browserNotificationsEnabled } = browserNotifications; const { enabled: browserNotificationsEnabled } = browserNotifications;
const [externalActionToDisplay, setExternalActionToDisplay] = useState<ExternalAction>(null); const [externalActionToDisplay, setExternalActionToDisplay] = useState<ExternalAction>(null);
const [supportsBrowserNotifications, setSupportsBrowserNotifications] = useState(false);
const supportFediverseFeatures = fediverseEnabled;
const externalActionSelected = (action: ExternalAction) => { const externalActionSelected = (action: ExternalAction) => {
const { openExternally, url } = action; const { openExternally, url } = action;
if (openExternally) { if (openExternally) {
@ -277,6 +284,12 @@ export const Content: FC = () => {
}; };
}, []); }, []);
useEffect(() => {
// isPushNotificationSupported relies on `navigator` so that needs to be
// fired from this useEffect.
setSupportsBrowserNotifications(isPushNotificationSupported() && browserNotificationsEnabled);
}, [browserNotificationsEnabled]);
const showChat = !chatDisabled && isChatAvailable && isChatVisible; const showChat = !chatDisabled && isChatAvailable && isChatVisible;
return ( return (
@ -312,7 +325,10 @@ export const Content: FC = () => {
{!isMobile && ( {!isMobile && (
<ActionButtonRow> <ActionButtonRow>
{externalActionButtons} {externalActionButtons}
{supportFediverseFeatures && (
<FollowButton size="small" onClick={() => setShowFollowModal(true)} /> <FollowButton size="small" onClick={() => setShowFollowModal(true)} />
)}
{supportsBrowserNotifications && (
<NotifyReminderPopup <NotifyReminderPopup
open={showNotifyReminder} open={showNotifyReminder}
notificationClicked={() => setShowNotifyModal(true)} notificationClicked={() => setShowNotifyModal(true)}
@ -320,6 +336,7 @@ export const Content: FC = () => {
> >
<NotifyButton onClick={() => setShowNotifyModal(true)} /> <NotifyButton onClick={() => setShowNotifyModal(true)} />
</NotifyReminderPopup> </NotifyReminderPopup>
)}
</ActionButtonRow> </ActionButtonRow>
)} )}
@ -348,6 +365,8 @@ export const Content: FC = () => {
setExternalActionToDisplay={externalActionSelected} setExternalActionToDisplay={externalActionSelected}
setShowNotifyPopup={setShowNotifyModal} setShowNotifyPopup={setShowNotifyModal}
setShowFollowModal={setShowFollowModal} setShowFollowModal={setShowFollowModal}
supportFediverseFeatures={supportFediverseFeatures}
supportsBrowserNotifications={supportsBrowserNotifications}
/> />
) : ( ) : (
<DesktopContent <DesktopContent
@ -358,6 +377,7 @@ export const Content: FC = () => {
socialHandles={socialHandles} socialHandles={socialHandles}
extraPageContent={extraPageContent} extraPageContent={extraPageContent}
setShowFollowModal={setShowFollowModal} setShowFollowModal={setShowFollowModal}
supportFediverseFeatures={supportFediverseFeatures}
/> />
)} )}
<Footer version={version} /> <Footer version={version} />