first commit
This commit is contained in:
parent
d7c7674e6a
commit
14b75269bb
|
@ -0,0 +1,5 @@
|
||||||
|
node_modules
|
||||||
|
.DS_Store
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": true
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Frappe UI Starter
|
||||||
|
|
||||||
|
This template should help get you started developing custom frontend for Frappe
|
||||||
|
apps with Vue 3 and the Frappe UI package.
|
||||||
|
|
||||||
|
![Auth](https://user-images.githubusercontent.com/34810212/236846289-ac31c292-81ea-4456-be65-95773a4049be.png)
|
||||||
|
|
||||||
|
![Home](https://user-images.githubusercontent.com/34810212/236846299-fd534e2b-1c06-4f01-a4f2-91a27547cd55.png)
|
||||||
|
|
||||||
|
This boilerplate sets up Vue 3, Vue Router, TailwindCSS, and Frappe UI out of
|
||||||
|
the box. It also has basic authentication frontend.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
This template is meant to be cloned inside an existing Frappe App. Assuming your
|
||||||
|
apps name is `todo`. Clone this template in the root folder of your app using `degit`.
|
||||||
|
|
||||||
|
```
|
||||||
|
cd apps/todo
|
||||||
|
npx degit NagariaHussain/doppio_frappeui_starter frontend
|
||||||
|
cd frontend
|
||||||
|
yarn
|
||||||
|
yarn dev
|
||||||
|
```
|
||||||
|
|
||||||
|
In a development environment, you need to put the below key-value pair in your `site_config.json` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
"ignore_csrf": 1
|
||||||
|
```
|
||||||
|
|
||||||
|
This will prevent `CSRFToken` errors while using the vite dev server. In production environment, the `csrf_token` is attached to the `window` object in `index.html` for you.
|
||||||
|
|
||||||
|
The Vite dev server will start on the port `8080`. This can be changed from `vite.config.js`.
|
||||||
|
The development server is configured to proxy your frappe app (usually running on port `8000`). If you have a site named `todo.test`, open `http://todo.test:8080` in your browser. If you see a button named "Click to send 'ping' request", congratulations!
|
||||||
|
|
||||||
|
If you notice the browser URL is `/frontend`, this is the base URL where your frontend app will run in production.
|
||||||
|
To change this, open `src/router.js` and change the base URL passed to `createWebHistory`.
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [Vue 3](https://v3.vuejs.org/guide/introduction.html)
|
||||||
|
- [Vue Router](https://next.router.vuejs.org/guide/)
|
||||||
|
- [Frappe UI](https://github.com/frappe/frappe-ui)
|
||||||
|
- [TailwindCSS](https://tailwindcss.com/docs/utility-first)
|
||||||
|
- [Vite](https://vitejs.dev/guide/)
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" href="/favicon.png" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Frappe UI App</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<div id="modals"></div>
|
||||||
|
<div id="popovers"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
window.csrf_token = '{{ frappe.session.csrf_token }}'
|
||||||
|
</script>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"name": "frappe-ui-frontend",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build --base=/assets/playbook/frontend/ && yarn copy-html-entry",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"copy-html-entry": "cp ../playbook/public/frontend/index.html ../playbook/www/frontend.html"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"feather-icons": "^4.28.0",
|
||||||
|
"frappe-ui": "^0.1.3",
|
||||||
|
"vue": "^3.2.25",
|
||||||
|
"vue-router": "^4.0.12"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^2.0.0",
|
||||||
|
"autoprefixer": "^10.4.2",
|
||||||
|
"postcss": "^8.4.5",
|
||||||
|
"tailwindcss": "^3.0.15",
|
||||||
|
"vite": "^2.7.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 440 B |
|
@ -0,0 +1,5 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</template>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,152 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-Thin.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-Thin.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 100;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-ThinItalic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-ThinItalic.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-ExtraLight.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-ExtraLight.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 200;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-ExtraLightItalic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-ExtraLightItalic.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-Light.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-Light.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-LightItalic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-LightItalic.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-Regular.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-Regular.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 400;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-Italic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-Italic.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-Medium.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-Medium.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 500;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-MediumItalic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-MediumItalic.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-SemiBold.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-SemiBold.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 600;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-SemiBoldItalic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-SemiBoldItalic.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-Bold.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-Bold.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 700;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-BoldItalic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-BoldItalic.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-ExtraBold.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-ExtraBold.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 800;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-ExtraBoldItalic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-ExtraBoldItalic.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-Black.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-Black.woff?v=3.12') format('woff');
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Inter';
|
||||||
|
font-style: italic;
|
||||||
|
font-weight: 900;
|
||||||
|
font-display: swap;
|
||||||
|
src: url('Inter-BlackItalic.woff2?v=3.12') format('woff2'),
|
||||||
|
url('Inter-BlackItalic.woff?v=3.12') format('woff');
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import router from '@/router'
|
||||||
|
import { computed, reactive } from 'vue'
|
||||||
|
import { createResource } from 'frappe-ui'
|
||||||
|
|
||||||
|
import { userResource } from './user'
|
||||||
|
|
||||||
|
export function sessionUser() {
|
||||||
|
const cookies = new URLSearchParams(document.cookie.split('; ').join('&'))
|
||||||
|
let _sessionUser = cookies.get('user_id')
|
||||||
|
if (_sessionUser === 'Guest') {
|
||||||
|
_sessionUser = null
|
||||||
|
}
|
||||||
|
return _sessionUser
|
||||||
|
}
|
||||||
|
|
||||||
|
export const session = reactive({
|
||||||
|
login: createResource({
|
||||||
|
url: 'login',
|
||||||
|
makeParams({ email, password }) {
|
||||||
|
return {
|
||||||
|
usr: email,
|
||||||
|
pwd: password,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSuccess(data) {
|
||||||
|
userResource.reload()
|
||||||
|
session.user = sessionUser()
|
||||||
|
session.login.reset()
|
||||||
|
router.replace(data.default_route || '/')
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
logout: createResource({
|
||||||
|
url: 'logout',
|
||||||
|
onSuccess() {
|
||||||
|
userResource.reset()
|
||||||
|
session.user = sessionUser()
|
||||||
|
router.replace({ name: 'Login' })
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
user: sessionUser(),
|
||||||
|
isLoggedIn: computed(() => !!session.user),
|
||||||
|
})
|
|
@ -0,0 +1,12 @@
|
||||||
|
import router from '@/router'
|
||||||
|
import { createResource } from 'frappe-ui'
|
||||||
|
|
||||||
|
export const userResource = createResource({
|
||||||
|
url: 'frappe.auth.get_logged_user',
|
||||||
|
cache: 'User',
|
||||||
|
onError(error) {
|
||||||
|
if (error && error.exc_type === 'AuthenticationError') {
|
||||||
|
router.push({ name: 'LoginPage' })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
|
@ -0,0 +1,2 @@
|
||||||
|
@import './assets/Inter/inter.css';
|
||||||
|
@import 'frappe-ui/src/style.css';
|
|
@ -0,0 +1,27 @@
|
||||||
|
import './index.css'
|
||||||
|
|
||||||
|
import { createApp } from 'vue'
|
||||||
|
import router from './router'
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Input,
|
||||||
|
setConfig,
|
||||||
|
frappeRequest,
|
||||||
|
resourcesPlugin,
|
||||||
|
} from 'frappe-ui'
|
||||||
|
|
||||||
|
let app = createApp(App)
|
||||||
|
|
||||||
|
setConfig('resourceFetcher', frappeRequest)
|
||||||
|
|
||||||
|
app.use(router)
|
||||||
|
app.use(resourcesPlugin)
|
||||||
|
|
||||||
|
app.component('Button', Button)
|
||||||
|
app.component('Card', Card)
|
||||||
|
app.component('Input', Input)
|
||||||
|
|
||||||
|
app.mount('#app')
|
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<div class="mr-4 ml-4 mt-10">
|
||||||
|
<h1>Playbooks</h1>
|
||||||
|
<card>
|
||||||
|
<div class="flex flex-row justify-between">
|
||||||
|
<div class="flex flex-col justify-between">
|
||||||
|
<h4>Playbook Name</h4>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="playbook.playbookName"
|
||||||
|
style="width: 300px"
|
||||||
|
></Input>
|
||||||
|
<h4>Playbook Owner</h4>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="playbook.playbookOwner"
|
||||||
|
style="width: 300px"
|
||||||
|
></Input>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<h4>Informed Members</h4>
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
v-model="playbook.informedMember"
|
||||||
|
style="width: 300px"
|
||||||
|
></Input>
|
||||||
|
<h4>Playbook Access</h4>
|
||||||
|
<Input
|
||||||
|
type="dropdown"
|
||||||
|
v-model="playbook.playbookAccess"
|
||||||
|
style="width: 300px"
|
||||||
|
></Input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Dialog } from 'frappe-ui'
|
||||||
|
import { createResource } from 'frappe-ui'
|
||||||
|
import { session } from '../data/session'
|
||||||
|
|
||||||
|
const playbook = createResource({
|
||||||
|
playbookName: '',
|
||||||
|
playbookOwner: '',
|
||||||
|
informedMember: '',
|
||||||
|
playbookAccess: '',
|
||||||
|
playbookDescription: '',
|
||||||
|
department: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const showDialog = ref(false)
|
||||||
|
</script>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<template>
|
||||||
|
<div class="m-3 flex flex-row items-center justify-center">
|
||||||
|
<Card title="Login to your FrappeUI App!" class="w-full max-w-md mt-4">
|
||||||
|
<form class="flex flex-col space-y-2 w-full" @submit.prevent="submit">
|
||||||
|
<Input
|
||||||
|
required
|
||||||
|
name="email"
|
||||||
|
type="text"
|
||||||
|
placeholder="johndoe@email.com"
|
||||||
|
label="User ID"
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
required
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
placeholder="••••••"
|
||||||
|
label="Password"
|
||||||
|
/>
|
||||||
|
<Button :loading="session.login.loading" variant="solid"
|
||||||
|
>Login</Button
|
||||||
|
>
|
||||||
|
</form>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { session } from '../data/session'
|
||||||
|
|
||||||
|
function submit(e) {
|
||||||
|
let formData = new FormData(e.target)
|
||||||
|
session.login.submit({
|
||||||
|
email: formData.get('email'),
|
||||||
|
password: formData.get('password'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
|
import { session } from './data/session'
|
||||||
|
import { userResource } from '@/data/user'
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
name: 'Home',
|
||||||
|
component: () => import('@/pages/Home.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Login',
|
||||||
|
path: '/account/login',
|
||||||
|
component: () => import('@/pages/Login.vue'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
let router = createRouter({
|
||||||
|
history: createWebHistory('/frontend'),
|
||||||
|
routes,
|
||||||
|
})
|
||||||
|
|
||||||
|
router.beforeEach(async (to, from, next) => {
|
||||||
|
let isLoggedIn = session.isLoggedIn
|
||||||
|
try {
|
||||||
|
await userResource.promise
|
||||||
|
} catch (error) {
|
||||||
|
isLoggedIn = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to.name === 'Login' && isLoggedIn) {
|
||||||
|
next({ name: 'Home' })
|
||||||
|
} else if (to.name !== 'Login' && !isLoggedIn) {
|
||||||
|
next({ name: 'Login' })
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default router
|
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = {
|
||||||
|
presets: [require('frappe-ui/src/utils/tailwind.config')],
|
||||||
|
content: [
|
||||||
|
'./index.html',
|
||||||
|
'./src/**/*.{vue,js,ts,jsx,tsx}',
|
||||||
|
'./node_modules/frappe-ui/src/components/**/*.{vue,js,ts,jsx,tsx}',
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import path from 'path'
|
||||||
|
import frappeui from 'frappe-ui/vite'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [frappeui(), vue()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, 'src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: `../${path.basename(path.resolve('..'))}/public/frontend`,
|
||||||
|
emptyOutDir: true,
|
||||||
|
target: 'es2015',
|
||||||
|
},
|
||||||
|
optimizeDeps: {
|
||||||
|
include: ['frappe-ui > feather-icons', 'showdown', 'engine.io-client'],
|
||||||
|
},
|
||||||
|
})
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "playbook",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Playbook app",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"postinstall": "cd frontend && yarn install",
|
||||||
|
"dev": "cd frontend && yarn dev",
|
||||||
|
"build": "cd frontend && yarn build"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
|
@ -227,3 +227,5 @@ app_license = "mit"
|
||||||
# "Logging DocType Name": 30 # days to retain logs
|
# "Logging DocType Name": 30 # days to retain logs
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
website_route_rules = [{'from_route': '/frontend/<path:app_path>', 'to_route': 'frontend'},]
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"creation": "2024-03-11 19:09:41.379978",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "users",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "users",
|
||||||
|
"options": "members",
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"istable": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2024-03-13 11:46:53.301506",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Playbook",
|
||||||
|
"name": "informedusers",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": []
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2024, snehalatha and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class informedusers(Document):
|
||||||
|
pass
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Copyright (c) 2024, snehalatha and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
// frappe.ui.form.on("members", {
|
||||||
|
// refresh(frm) {
|
||||||
|
|
||||||
|
// },
|
||||||
|
// });
|
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_rename": 1,
|
||||||
|
"autoname": "field:employee_name",
|
||||||
|
"creation": "2024-03-11 18:21:48.198570",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"employee_details_section",
|
||||||
|
"employee_name",
|
||||||
|
"employee_id"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "employee_details_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Employee Details"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "employee_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Employee name",
|
||||||
|
"reqd": 1,
|
||||||
|
"unique": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "employee_id",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Employee Id",
|
||||||
|
"reqd": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"links": [],
|
||||||
|
"modified": "2024-03-11 18:24:08.999807",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Playbook",
|
||||||
|
"name": "members",
|
||||||
|
"naming_rule": "By fieldname",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
|
"track_changes": 1,
|
||||||
|
"track_seen": 1
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2024, snehalatha and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class members(Document):
|
||||||
|
pass
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2024, snehalatha and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class Testmembers(FrappeTestCase):
|
||||||
|
pass
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Copyright (c) 2024, snehalatha and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
// frappe.ui.form.on("playbooks", {
|
||||||
|
// refresh(frm) {
|
||||||
|
|
||||||
|
// },
|
||||||
|
// });
|
|
@ -0,0 +1,126 @@
|
||||||
|
{
|
||||||
|
"actions": [],
|
||||||
|
"allow_guest_to_view": 1,
|
||||||
|
"allow_rename": 1,
|
||||||
|
"autoname": "field:playbook_name",
|
||||||
|
"creation": "2024-03-01 15:53:25.422486",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"section_break_cmct",
|
||||||
|
"playbook_owner",
|
||||||
|
"informed_members",
|
||||||
|
"ispublished",
|
||||||
|
"column_break_ingm",
|
||||||
|
"playbook_name",
|
||||||
|
"access",
|
||||||
|
"route",
|
||||||
|
"amended_from",
|
||||||
|
"section_break_zfjq",
|
||||||
|
"playbook_description"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_cmct",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": ".employee_name",
|
||||||
|
"fieldname": "playbook_owner",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Playbook owner",
|
||||||
|
"options": "members",
|
||||||
|
"reqd": 1,
|
||||||
|
"unique": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": ".",
|
||||||
|
"fieldname": "informed_members",
|
||||||
|
"fieldtype": "Table MultiSelect",
|
||||||
|
"label": "Informed members",
|
||||||
|
"options": "informedusers",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "playbook_description",
|
||||||
|
"fieldtype": "HTML Editor",
|
||||||
|
"label": "Playbook Description"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_ingm",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "playbook_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Playbook name",
|
||||||
|
"reqd": 1,
|
||||||
|
"unique": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "access",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Team with access",
|
||||||
|
"options": "Public\nPrivate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "amended_from",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Amended From",
|
||||||
|
"no_copy": 1,
|
||||||
|
"options": "playbooks",
|
||||||
|
"print_hide": 1,
|
||||||
|
"read_only": 1,
|
||||||
|
"search_index": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "ispublished",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "isPublished"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "route",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "route"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_zfjq",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"has_web_view": 1,
|
||||||
|
"index_web_pages_for_search": 1,
|
||||||
|
"is_published_field": "ispublished",
|
||||||
|
"links": [],
|
||||||
|
"modified": "2024-03-15 10:42:25.917745",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Playbook",
|
||||||
|
"name": "playbooks",
|
||||||
|
"naming_rule": "By fieldname",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"route": "playbook",
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "DESC",
|
||||||
|
"states": [],
|
||||||
|
"track_changes": 1,
|
||||||
|
"track_seen": 1,
|
||||||
|
"track_views": 1
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2024, snehalatha and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.website.website_generator import WebsiteGenerator
|
||||||
|
|
||||||
|
|
||||||
|
class playbooks(WebsiteGenerator):
|
||||||
|
pass
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% extends "templates/web.html" %}
|
||||||
|
|
||||||
|
{% block page_content %}
|
||||||
|
<div>
|
||||||
|
<h3>{{ title }}</h3>
|
||||||
|
<h4>by : {{ doc.playbook_owner }}</h4>
|
||||||
|
<h4>informed users</h4>
|
||||||
|
{% for users in doc.informed_members %}
|
||||||
|
<p>{{ users.users }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<!-- this is a sample default web page template -->
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div>
|
||||||
|
<a href="{{ doc.route }}">{{ doc.title or doc.name }}</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- this is a sample default list template -->
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Copyright (c) 2024, snehalatha and Contributors
|
||||||
|
# See license.txt
|
||||||
|
|
||||||
|
# import frappe
|
||||||
|
from frappe.tests.utils import FrappeTestCase
|
||||||
|
|
||||||
|
|
||||||
|
class Testplaybooks(FrappeTestCase):
|
||||||
|
pass
|
|
@ -0,0 +1,3 @@
|
||||||
|
frappe.ready(function() {
|
||||||
|
// bind events here
|
||||||
|
})
|
|
@ -0,0 +1,115 @@
|
||||||
|
{
|
||||||
|
"allow_comments": 0,
|
||||||
|
"allow_delete": 0,
|
||||||
|
"allow_edit": 0,
|
||||||
|
"allow_incomplete": 0,
|
||||||
|
"allow_multiple": 0,
|
||||||
|
"allow_print": 0,
|
||||||
|
"anonymous": 1,
|
||||||
|
"apply_document_permissions": 0,
|
||||||
|
"button_label": "Submit",
|
||||||
|
"condition_json": "[]",
|
||||||
|
"creation": "2024-03-14 11:16:14.149153",
|
||||||
|
"doc_type": "playbooks",
|
||||||
|
"docstatus": 0,
|
||||||
|
"doctype": "Web Form",
|
||||||
|
"idx": 0,
|
||||||
|
"introduction_text": "<div class=\"ql-editor read-mode\"><p>Fill the details</p></div>",
|
||||||
|
"is_standard": 1,
|
||||||
|
"list_columns": [],
|
||||||
|
"login_required": 0,
|
||||||
|
"max_attachment_size": 0,
|
||||||
|
"modified": "2024-03-14 11:22:04.441886",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "Playbook",
|
||||||
|
"name": "playbook",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"published": 1,
|
||||||
|
"route": "playbookfill",
|
||||||
|
"show_attachments": 0,
|
||||||
|
"show_list": 0,
|
||||||
|
"show_sidebar": 0,
|
||||||
|
"title": "playbook",
|
||||||
|
"web_form_fields": [
|
||||||
|
{
|
||||||
|
"allow_read_on_all_link_options": 0,
|
||||||
|
"fieldname": "section_break_cmct",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"max_length": 0,
|
||||||
|
"max_value": 0,
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"show_in_filter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_read_on_all_link_options": 0,
|
||||||
|
"fieldname": "playbook_owner",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "Playbook owner",
|
||||||
|
"mandatory_depends_on": "",
|
||||||
|
"max_length": 0,
|
||||||
|
"max_value": 0,
|
||||||
|
"options": "members",
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 0,
|
||||||
|
"reqd": 1,
|
||||||
|
"show_in_filter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_read_on_all_link_options": 0,
|
||||||
|
"fieldname": "column_break_ingm",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "",
|
||||||
|
"max_length": 0,
|
||||||
|
"max_value": 0,
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"show_in_filter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_read_on_all_link_options": 0,
|
||||||
|
"fieldname": "playbook_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "Playbook name",
|
||||||
|
"max_length": 0,
|
||||||
|
"max_value": 0,
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 0,
|
||||||
|
"reqd": 1,
|
||||||
|
"show_in_filter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_read_on_all_link_options": 0,
|
||||||
|
"fieldname": "access",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "Team with access",
|
||||||
|
"max_length": 0,
|
||||||
|
"max_value": 0,
|
||||||
|
"options": "Public\nPrivate",
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"show_in_filter": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"allow_read_on_all_link_options": 0,
|
||||||
|
"fieldname": "section_break_zfjq",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 0,
|
||||||
|
"label": "",
|
||||||
|
"max_length": 0,
|
||||||
|
"max_value": 0,
|
||||||
|
"precision": "",
|
||||||
|
"read_only": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"show_in_filter": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def get_context(context):
|
||||||
|
# do your magic here
|
||||||
|
pass
|
Loading…
Reference in New Issue