Merge dev to main (#69)

* Log (failed) attempt to notify a user with viewer role

* Remove https:// prefix from BASE_URL docker env var

* Fix cloud heartbeat name

* Polishing telegram

* Update docker-compose.yml

* Update plugin README  (#48)

* Update README and screenshot, remove plop for build info since version is now displayed prominently

* Sign build

Co-authored-by: Michael Derynck <michael.derynck@grafana.com>

* Build actions (#38)

* Drone, github action changes

* Minor version updates

* Update frontend dependencies

* Re-enable unit test

Co-authored-by: Michael Derynck <michael.derynck@grafana.com>

* Revert stylelint version (#52)

* Revert stylelint version

* Build plugin as well as lint

* Build in previous step

Co-authored-by: Michael Derynck <michael.derynck@grafana.com>

* Update screenshot (#53)

Co-authored-by: Michael Derynck <michael.derynck@grafana.com>

* oncall images for docs (#55)

* Update README.md

* Top menu fix

* Fix db encoding

* Add api key docs

* Reverting utf8 fix

* bug fixes

* fix for link for OSS version

* Fixing utf8 and docker compose

* 8080 -> 8000 port for consistency

* makeReq

* Fixing images

* Fixing port

* Fixing port

* Fixing port

* Fixing port

* Fixing port

* Fixing port

* Fixing port

* Fixing port

* Replace symlink with file for CHANGELOG.MD (#68)

Co-authored-by: Michael Derynck <michael.derynck@grafana.com>

Co-authored-by: Matias Bordese <mbordese@gmail.com>
Co-authored-by: Matvey Kukuy <Matvey-Kuk@users.noreply.github.com>
Co-authored-by: Innokentii Konstantinov <innokenty.konstantinov@grafana.com>
Co-authored-by: Matvey Kukuy <matvey@amixr.io>
Co-authored-by: Michael Derynck <michael.derynck@grafana.com>
Co-authored-by: Alyssa Wada <101596687+alyssawada@users.noreply.github.com>
Co-authored-by: Yulia Shanyrova <yulia.shanyrova@grafana.com>
This commit is contained in:
Michael Derynck 2022-06-14 09:14:45 -06:00 committed by GitHub
parent 66e8cf2cbc
commit 846b898bb9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 74 additions and 58 deletions

View file

@ -1,3 +1,5 @@
RUNSERVER_PORT=8080
SLACK_CLIENT_OAUTH_ID=
SLACK_CLIENT_OAUTH_SECRET=
SLACK_API_TOKEN=
@ -19,13 +21,13 @@ SENDGRID_FROM_EMAIL=
DJANGO_SETTINGS_MODULE=settings.dev
SECRET_KEY=jkashdkjashdkjh
BASE_URL=http://localhost:8000
BASE_URL=http://localhost:8080
FEATURE_TELEGRAM_INTEGRATION_ENABLED=True
FEATURE_SLACK_INTEGRATION_ENABLED=True
FEATURE_EXTRA_MESSAGING_BACKENDS_ENABLED=
SLACK_INSTALL_RETURN_REDIRECT_HOST=http://localhost:8000
SLACK_INSTALL_RETURN_REDIRECT_HOST=http://localhost:8080
SOCIAL_AUTH_REDIRECT_IS_HTTPS=False
GRAFANA_INCIDENT_STATIC_API_KEY=

View file

@ -64,7 +64,7 @@ python manage.py createsuperuser
3. Launch the backend:
```bash
# Http server:
python manage.py runserver
python manage.py runserver 8080
# Worker for background tasks (run it in the parallel terminal, don't forget to export .env there)
python manage.py start_celery
@ -73,7 +73,7 @@ python manage.py start_celery
celery -A engine beat -l info
```
4. All set! Check out internal API endpoints at http://localhost:8000/.
4. All set! Check out internal API endpoints at http://localhost:8080/.
### Frontend setup
@ -102,7 +102,7 @@ python manage.py issue_invite_for_the_frontend --override
6. Some configuration fields will appear be available. Fill them out and click Initialize OnCall
```
OnCall API URL:
http://host.docker.internal:8000
http://host.docker.internal:8080
Invitation Token (Single use token to connect Grafana instance):
Response from the invite generator command (check above)
@ -226,6 +226,7 @@ pytest --ds=settings.dev
- Set Settings to settings/dev.py
5. Create a new Django Server run configuration to Run/Debug the engine
- Use a plugin such as EnvFile to load the .env file
- Change port from 8000 to 8080
## Update drone build
The .drone.yml build file must be signed when changes are made to it. Follow these steps:

View file

@ -1,6 +1,6 @@
<img width="400px" src="docs/img/logo.png">
Developer-friendly, incident response with brilliant Slack integration.
Developer-friendly incident response with brilliant Slack integration.
<img width="60%" src="screenshot.png">
@ -20,7 +20,7 @@ curl https://github.com/grafana/oncall/blob/dev/docker-compose.yml -o docker-com
2. Set variables:
```bash
echo "DOMAIN=http://localhost
echo "DOMAIN=http://localhost:8080
SECRET_KEY=my_random_secret_must_be_more_than_32_characters_long
RABBITMQ_PASSWORD=rabbitmq_secret_pw
MYSQL_PASSWORD=mysql_secret_pw

View file

@ -7,7 +7,7 @@ services:
platform: linux/x86_64
mem_limit: 500m
cpus: 0.5
command: --default-authentication-plugin=mysql_native_password
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
restart: always
ports:
- 3306:3306

View file

@ -92,13 +92,15 @@ services:
depends_on:
mysql:
condition: service_healthy
rabbitmq:
condition: service_started
mysql:
image: mysql:5.7
platform: linux/x86_64
mem_limit: 500m
cpus: 0.5
command: --default-authentication-plugin=mysql_native_password
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
restart: always
ports:
- 3306:3306

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

View file

@ -21,15 +21,12 @@ To authorize, use the **Authorization** header:
```shell
# With shell, you can just pass the correct header with each request
curl "api_endpoint_here" --header "Authorization: meowmeowmeow"
curl "api_endpoint_here" --header "Authorization: "api_key_here""
```
Note that `meowmeowmeow` is a valid key for test purposes.
Replace `meowmeowmeow` with your API key in production.
Grafana OnCall uses API keys to allow access to the API. You can request a new OnCall API key in OnCall -> Settings page.
Grafana OnCall uses API keys to allow access to the API. You can request a new OnCall API key in the API section.
An API key is specific to a user and a Grafana stack. If you want to switch to a different team configuration, request a different API key.
An API key is specific to a user and a Grafana stack. If you want to switch to a different stack configuration, request a different API key.
## Pagination

View file

@ -17,7 +17,7 @@ We prepared three environments for OSS users:
## Production Environment
TBD
We prepared the helm chart for production environment: https://github.com/grafana/oncall/helm
## Slack Setup
@ -32,7 +32,7 @@ Grafana OnCall Slack integration use a lot of Slack API features:
# Choose the unique prefix instead of pretty-turkey-83
# Localtunnel will generate an url, e.g. https://pretty-turkey-83.loca.lt
# it is referred as <ONCALL_ENGINE_PUBLIC_URL> below
lt --port 8000 -s pretty-turkey-83 --print-requests
lt --port 8080 -s pretty-turkey-83 --print-requests
```
3. If you use localtunnel, open your external URL and click "Continue" to allow requests to bypass the warning page.

View file

@ -114,8 +114,8 @@ class LiveSetting(models.Model):
),
"SEND_ANONYMOUS_USAGE_STATS": (
"Grafana OnCall will send anonymous, but uniquely-identifiable usage analytics to Grafana Labs."
" These statistics are sent to https://stats.grafana.org/. For more information on what's sent, look at"
" https://github.com/grafana/oncall/blob/dev/engine/apps/oss_installation/usage_stats.py#L29"
" These statistics are sent to https://stats.grafana.org/. For more information on what's sent, look at the "
"<a href='https://github.com/grafana/oncall/blob/dev/engine/apps/oss_installation/usage_stats.py#L29'> source code</a>."
),
"GRAFANA_CLOUD_ONCALL_TOKEN": "Secret token for Grafana Cloud OnCall instance.",
"GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED": "Enable hearbeat integration with Grafana Cloud OnCall.",

View file

@ -226,9 +226,7 @@ USE_TZ = True
# https://docs.djangoproject.com/en/2.1/howto/static-files/
STATIC_URL = "/static/"
STATICFILES_DIRS = [
"./static",
]
STATIC_ROOT = "./static/"
CELERY_BROKER_URL = "amqp://rabbitmq:rabbitmq@localhost:5672"

View file

@ -18,4 +18,4 @@ post-buffering=1
logger=stdio
log-format=source=engine:uwsgi status=%(status) method=%(method) path=%(uri) latency=%(secs) google_trace_id=%(var.HTTP_X_CLOUD_TRACE_CONTEXT) protocol=%(proto) resp_size=%(size) req_body_size=%(cl)
log-encoder=format ${strftime:%%Y-%%m-%%d %%H:%%M:%%S} ${msgnl}
log-encoder=format ${strftime:%%Y-%%m-%%d %%H:%%M:%%S} ${msgnl}

View file

@ -1 +0,0 @@
../CHANGELOG.md

View file

@ -0,0 +1,5 @@
# Change Log
## 0.0.71 (2022-06-06)
- Initial Release

View file

@ -100,7 +100,9 @@ const DefaultPageLayout: FC<DefaultPageLayoutProps> = observer((props) => {
currentTeam &&
currentUser &&
store.isUserActionAllowed(UserAction.UpdateOwnSettings) &&
(!currentUser.verified_phone_number || !currentUser.slack_user_identity) &&
(!currentUser.verified_phone_number ||
!currentUser.slack_user_identity ||
currentUser.cloud_connection_status !== 3) &&
!getItem(AlertID.CONNECTIVITY_WARNING)
) && (
<Alert
@ -119,7 +121,9 @@ const DefaultPageLayout: FC<DefaultPageLayoutProps> = observer((props) => {
{'. '}
</>
)}
{!currentUser.verified_phone_number && 'Your phone number is not verified. '}
{currentUser.cloud_connection_status !== 3 &&
!currentUser.verified_phone_number &&
'Your phone number is not verified. '}
{currentTeam.slack_team_identity &&
!currentUser.slack_user_identity &&
'Your slack account is not connected. '}

View file

@ -35,11 +35,10 @@ const cx = cn.bind(styles);
interface Props extends PluginConfigPageProps<AppPluginMeta<OnCallAppSettings>> {}
export const PluginConfigPage = (props: Props) => {
const grafanaUrlDefault = getItem('grafanaUrl') || window.location.origin;
const { plugin } = props;
const [onCallApiUrl, setOnCallApiUrl] = useState<string>(getItem('onCallApiUrl'));
const [onCallInvitationToken, setOnCallInvitationToken] = useState<string>();
const [grafanaUrl, setGrafanaUrl] = useState<string>(grafanaUrlDefault);
const [grafanaUrl, setGrafanaUrl] = useState<string>(getItem('grafanaUrl'));
const [pluginConfigLoading, setPluginConfigLoading] = useState<boolean>(true);
const [pluginStatusOk, setPluginStatusOk] = useState<boolean>();
const [pluginStatusMessage, setPluginStatusMessage] = useState<string>();
@ -298,10 +297,10 @@ Seek for such a line: “Your invite token: <<LONG TOKEN>> , use it in the Graf
label="OnCall backend URL"
description={
<Text>
It should be rechable from Grafana. Possible options: <br />
http://host.docker.internal:8000 (if you run backend in the docker locally)
It should be reachable from Grafana. Possible options: <br />
http://host.docker.internal:8080 (if you run backend in the docker locally)
<br />
http://localhost:8000 <br />
http://localhost:8080 <br />
...
</Text>
}

View file

@ -48,7 +48,7 @@ const CloudPhoneSettings = observer((props: CloudPhoneSettingsProps) => {
}, []);
const handleLinkClick = (link: string) => {
window.location.replace(link);
window.open(link, '_blank');
};
const syncUser = async () => {

View file

@ -30,12 +30,19 @@
background: var(--highlighted-row-bg);
}
/* This is for Grafana 8, remove later */
@media (max-width: 1540px) {
.page-header__tabs > ul > li > a > div {
display: none;
}
}
@media (max-width: 1540px) {
.page-header__tabs > div > div > a > div {
display: none;
}
}
@media (max-width: 1300px) {
.sidemenu {
position: fixed !important;

View file

@ -69,10 +69,6 @@ const CloudPage = observer((props: CloudPageProps) => {
setApiKeyError(false);
}, []);
const saveKeyAndConnect = () => {
setShowConfirmationModal(true);
};
const disconnectCloudOncall = () => {
setCloudIsConnected(false);
store.cloudStore.disconnectToCloud();
@ -105,7 +101,7 @@ const CloudPage = observer((props: CloudPageProps) => {
};
const handleLinkClick = (link: string) => {
window.location.replace(link);
window.open(link, '_blank');
};
const renderButtons = (user: Cloud) => {
@ -130,10 +126,9 @@ const CloudPage = observer((props: CloudPageProps) => {
return (
<Button
variant="secondary"
icon="external-link-alt"
size="sm"
className={cx('table-button')}
onClick={() => handleLinkClick(user?.cloud_data?.link)}
onClick={() => getLocationSrv().update({ query: { page: 'users', p: page, id: user.id } })}
>
Configure notifications
</Button>
@ -343,7 +338,7 @@ const CloudPage = observer((props: CloudPageProps) => {
>
<Input id="cloudApiKey" onChange={handleChangeCloudApiKey} />
</Field>
<Button variant="primary" onClick={saveKeyAndConnect} disabled={!cloudApiKey} size="md">
<Button variant="primary" onClick={connectToCloud} disabled={!cloudApiKey} size="md">
Save key and connect
</Button>
</VerticalGroup>
@ -387,23 +382,6 @@ const CloudPage = observer((props: CloudPageProps) => {
) : (
DisconnectedBlock
)}
{showConfirmationModal && (
<Modal
isOpen
title="Are you sure you want to connect to cloud?"
onDismiss={() => setShowConfirmationModal(false)}
>
<HorizontalGroup>
<Button variant="primary" onClick={connectToCloud}>
Continue
</Button>
<Button variant="secondary" onClick={() => setShowConfirmationModal(false)}>
Cancel
</Button>
</HorizontalGroup>
</Modal>
)}
</VerticalGroup>
</div>
);

View file

@ -22,3 +22,8 @@
.description-style > a {
color: var(--primary-text-link);
}
.description-style {
word-wrap: break-word;
word-break: break-word;
}

View file

@ -14,7 +14,9 @@ import {
} from '@grafana/ui';
import cn from 'classnames/bind';
import { omit } from 'lodash-es';
import { observe } from 'mobx';
import { observer } from 'mobx-react';
import { Lambda } from 'mobx/lib/internal';
import { AlignType } from 'rc-table/lib/interface';
import { Redirect } from 'react-router-dom';
@ -46,6 +48,23 @@ class LiveSettings extends React.Component<LiveSettingsProps, LiveSettingsState>
hideValues: true,
};
disposer: Lambda;
constructor(props: LiveSettingsProps) {
super(props);
const { store } = props;
this.disposer = observe(store.userStore, (change) => {
if (change.name === 'currentUserPk') {
this.update();
}
});
}
componentWillUnmount() {
this.disposer();
}
componentDidMount() {
this.update();
}

View file

@ -1,4 +1,4 @@
import plugin from '../../package.json'; // eslint-disable-line
export const APP_TITLE = 'Grafana OnCall';
export const APP_SUBTITLE = `Incident Response (${plugin?.version})`;
export const APP_SUBTITLE = `Developer-friendly incident response (${plugin?.version})`;