Compare commits
9 Commits
feat/curre
...
chore/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b715ef840 | ||
|
|
24105dbaaf | ||
|
|
e3846634b5 | ||
|
|
fd52c23636 | ||
|
|
20a1421576 | ||
|
|
74e52c3e87 | ||
|
|
1857bb0518 | ||
|
|
a729b5eb12 | ||
|
|
04f45fe385 |
@@ -4,7 +4,7 @@ services:
|
|||||||
image: akhilrex/hammond
|
image: akhilrex/hammond
|
||||||
container_name: hammond
|
container_name: hammond
|
||||||
environment:
|
environment:
|
||||||
- JWT_SECRET = somethingverystrong
|
- JWT_SECRET=somethingverystrong
|
||||||
volumes:
|
volumes:
|
||||||
- /path/to/config:/config
|
- /path/to/config:/config
|
||||||
- /path/to/data:/assets
|
- /path/to/data:/assets
|
||||||
|
|||||||
@@ -94,17 +94,17 @@ func userLogin(c *gin.Context) {
|
|||||||
user, err := db.FindOneUser(&db.User{Email: loginRequest.Email})
|
user, err := db.FindOneUser(&db.User{Email: loginRequest.Email})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Not Registered email or invalid password")))
|
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("not Registered email or invalid password")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.CheckPassword(loginRequest.Password) != nil {
|
if user.CheckPassword(loginRequest.Password) != nil {
|
||||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Not Registered email or invalid password")))
|
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("not Registered email or invalid password")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.IsDisabled {
|
if user.IsDisabled {
|
||||||
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("Your user has been disabled by the admin. Please contact them to get it re-enabled.")))
|
c.JSON(http.StatusForbidden, common.NewError("login", errors.New("your user has been disabled by the admin. Please contact them to get it re-enabled")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
UpdateContextUserModel(c, user.ID)
|
UpdateContextUserModel(c, user.ID)
|
||||||
@@ -170,16 +170,16 @@ func changePassword(c *gin.Context) {
|
|||||||
user, err := service.GetUserById(c.GetString("userId"))
|
user, err := service.GetUserById(c.GetString("userId"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("Not Registered email or invalid password")))
|
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("not Registered email or invalid password")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.CheckPassword(request.OldPassword) != nil {
|
if user.CheckPassword(request.OldPassword) != nil {
|
||||||
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("Incorrect old password")))
|
c.JSON(http.StatusForbidden, common.NewError("changePassword", errors.New("incorrect old password")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user.SetPassword(request.NewPassword)
|
user.SetPassword(request.NewPassword)
|
||||||
success, err := service.UpdatePassword(user.ID, request.NewPassword)
|
success, _ := service.UpdatePassword(user.ID, request.NewPassword)
|
||||||
c.JSON(http.StatusOK, success)
|
c.JSON(http.StatusOK, success)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ func stripBearerPrefixFromTokenString(tok string) (string, error) {
|
|||||||
// Extract token from Authorization header
|
// Extract token from Authorization header
|
||||||
// Uses PostExtractionFilter to strip "TOKEN " prefix from header
|
// Uses PostExtractionFilter to strip "TOKEN " prefix from header
|
||||||
var AuthorizationHeaderExtractor = &request.PostExtractionFilter{
|
var AuthorizationHeaderExtractor = &request.PostExtractionFilter{
|
||||||
request.HeaderExtractor{"Authorization"},
|
Extractor: request.HeaderExtractor{"Authorization"},
|
||||||
stripBearerPrefixFromTokenString,
|
Filter: stripBearerPrefixFromTokenString,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extractor for OAuth2 access tokens. Looks in 'Authorization'
|
// Extractor for OAuth2 access tokens. Looks in 'Authorization'
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func migrate(c *gin.Context) {
|
|||||||
canMigrate, _, _ := db.CanMigrate(request.Url)
|
canMigrate, _, _ := db.CanMigrate(request.Url)
|
||||||
|
|
||||||
if !canMigrate {
|
if !canMigrate {
|
||||||
c.JSON(http.StatusBadRequest, fmt.Errorf("cannot migrate database. please check connection string."))
|
c.JSON(http.StatusBadRequest, fmt.Errorf("cannot migrate database. please check connection string"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ func deleteVehicle(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !canDelete {
|
if !canDelete {
|
||||||
c.JSON(http.StatusUnprocessableEntity, common.NewError("shareVehicle", errors.New("You are not allowed to delete this vehicle.")))
|
c.JSON(http.StatusUnprocessableEntity, common.NewError("shareVehicle", errors.New("you are not allowed to delete this vehicle")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = service.DeleteVehicle(searchByIdQuery.Id)
|
err = service.DeleteVehicle(searchByIdQuery.Id)
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ func UnshareVehicle(vehicleId, userId string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if mapping.IsOwner {
|
if mapping.IsOwner {
|
||||||
return fmt.Errorf("Cannot unshare owner")
|
return fmt.Errorf("cannot unshare owner")
|
||||||
}
|
}
|
||||||
result := DB.Where("id=?", mapping.ID).Delete(&UserVehicle{})
|
result := DB.Where("id=?", mapping.ID).Delete(&UserVehicle{})
|
||||||
return result.Error
|
return result.Error
|
||||||
@@ -332,8 +332,7 @@ func UnlockMissedJobs() {
|
|||||||
if (job.Date == time.Time{}) {
|
if (job.Date == time.Time{}) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var duration time.Duration
|
var duration = time.Duration(job.Duration)
|
||||||
duration = time.Duration(job.Duration)
|
|
||||||
d := job.Date.Add(time.Minute * duration)
|
d := job.Date.Add(time.Minute * duration)
|
||||||
if d.Before(time.Now()) {
|
if d.Before(time.Now()) {
|
||||||
fmt.Println(job.Name + " is unlocked")
|
fmt.Println(job.Name + " is unlocked")
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package service
|
|||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -126,14 +125,14 @@ func CreateBackup() (string, error) {
|
|||||||
tarballFilePath := path.Join(folder, backupFileName)
|
tarballFilePath := path.Join(folder, backupFileName)
|
||||||
file, err := os.Create(tarballFilePath)
|
file, err := os.Create(tarballFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New(fmt.Sprintf("Could not create tarball file '%s', got error '%s'", tarballFilePath, err.Error()))
|
return "", fmt.Errorf("could not create tarball file '%s', got error '%s'", tarballFilePath, err.Error())
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
dbPath := path.Join(configPath, "hammond.db")
|
dbPath := path.Join(configPath, "hammond.db")
|
||||||
_, err = os.Stat(dbPath)
|
_, err = os.Stat(dbPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.New(fmt.Sprintf("Could not find db file '%s', got error '%s'", dbPath, err.Error()))
|
return "", fmt.Errorf("could not find db file '%s', got error '%s'", dbPath, err.Error())
|
||||||
}
|
}
|
||||||
gzipWriter := gzip.NewWriter(file)
|
gzipWriter := gzip.NewWriter(file)
|
||||||
defer gzipWriter.Close()
|
defer gzipWriter.Close()
|
||||||
@@ -151,13 +150,13 @@ func CreateBackup() (string, error) {
|
|||||||
func addFileToTarWriter(filePath string, tarWriter *tar.Writer) error {
|
func addFileToTarWriter(filePath string, tarWriter *tar.Writer) error {
|
||||||
file, err := os.Open(filePath)
|
file, err := os.Open(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("Could not open file '%s', got error '%s'", filePath, err.Error()))
|
return fmt.Errorf("could not open file '%s', got error '%s'", filePath, err.Error())
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
stat, err := file.Stat()
|
stat, err := file.Stat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("Could not get stat for file '%s', got error '%s'", filePath, err.Error()))
|
return fmt.Errorf("could not get stat for file '%s', got error '%s'", filePath, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
header := &tar.Header{
|
header := &tar.Header{
|
||||||
@@ -169,12 +168,12 @@ func addFileToTarWriter(filePath string, tarWriter *tar.Writer) error {
|
|||||||
|
|
||||||
err = tarWriter.WriteHeader(header)
|
err = tarWriter.WriteHeader(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("Could not write header for file '%s', got error '%s'", filePath, err.Error()))
|
return fmt.Errorf("could not write header for file '%s', got error '%s'", filePath, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = io.Copy(tarWriter, file)
|
_, err = io.Copy(tarWriter, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(fmt.Sprintf("Could not copy the file '%s' data to the tarball, got error '%s'", filePath, err.Error()))
|
return fmt.Errorf("could not copy the file '%s' data to the tarball, got error '%s'", filePath, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/akhilrex/hammond/db"
|
"github.com/akhilrex/hammond/db"
|
||||||
@@ -15,6 +16,9 @@ func GetMileageByVehicleId(vehicleId string, since time.Time) (mileage []models.
|
|||||||
|
|
||||||
fillups := make([]db.Fillup, len(*data))
|
fillups := make([]db.Fillup, len(*data))
|
||||||
copy(fillups, *data)
|
copy(fillups, *data)
|
||||||
|
sort.Slice(fillups, func(i, j int) bool {
|
||||||
|
return fillups[i].OdoReading > fillups[j].OdoReading
|
||||||
|
})
|
||||||
|
|
||||||
var mileages []models.MileageModel
|
var mileages []models.MileageModel
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 895 B |
@@ -5,6 +5,7 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
<link rel="shortcut icon" href="<%= webpackConfig.output.publicPath %>hammond.png" />
|
<link rel="shortcut icon" href="<%= webpackConfig.output.publicPath %>hammond.png" />
|
||||||
|
<link rel="apple-touch-icon" href="<%= webpackConfig.output.publicPath %>touch-icon.png" />
|
||||||
<title><%= webpackConfig.name %></title>
|
<title><%= webpackConfig.name %></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
BIN
ui/public/touch-icon.png
Normal file
BIN
ui/public/touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -21,27 +21,13 @@ export default {
|
|||||||
email: '',
|
email: '',
|
||||||
password: '',
|
password: '',
|
||||||
distanceUnit: 1,
|
distanceUnit: 1,
|
||||||
currency: '',
|
currency: 'INR',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters('auth', ['isInitialized']),
|
...mapGetters('auth', ['isInitialized']),
|
||||||
...mapState('vehicles', ['currencyMasters', 'distanceUnitMasters']),
|
...mapState('vehicles', ['currencyMasters', 'distanceUnitMasters']),
|
||||||
filteredCurrencyMasters() {
|
|
||||||
return this.currencyMasters.filter((option) => {
|
|
||||||
return (
|
|
||||||
option.namePlural
|
|
||||||
.toString()
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(this.registerModel.currency.toLowerCase()) >= 0 ||
|
|
||||||
option.code
|
|
||||||
.toString()
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(this.registerModel.currency.toLowerCase()) >= 0
|
|
||||||
)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
store.dispatch('vehicles/fetchMasters').then((data) => {})
|
store.dispatch('vehicles/fetchMasters').then((data) => {})
|
||||||
@@ -153,9 +139,6 @@ export default {
|
|||||||
})
|
})
|
||||||
.finally(() => (this.isWorking = false))
|
.finally(() => (this.isWorking = false))
|
||||||
},
|
},
|
||||||
formatCurrency(option) {
|
|
||||||
return `${option.namePlural} (${option.code})`
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -165,10 +148,15 @@ export default {
|
|||||||
<div v-if="!migrationMode" class="box">
|
<div v-if="!migrationMode" class="box">
|
||||||
<h1 class="title">Migrate from Clarkson</h1>
|
<h1 class="title">Migrate from Clarkson</h1>
|
||||||
<p>
|
<p>
|
||||||
If you have an existing Clarkson deployment and you want to migrate your data from that, press the following button.
|
If you have an existing Clarkson deployment and you want to migrate your data from that,
|
||||||
|
press the following button.
|
||||||
</p>
|
</p>
|
||||||
<br />
|
<br />
|
||||||
<b-field> <b-button type="is-primary" @click="migrationMode = 'clarkson'">Migrate from Clarkson</b-button></b-field>
|
<b-field>
|
||||||
|
<b-button type="is-primary" @click="migrationMode = 'clarkson'"
|
||||||
|
>Migrate from Clarkson</b-button
|
||||||
|
></b-field
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!migrationMode" class="box">
|
<div v-if="!migrationMode" class="box">
|
||||||
<h1 class="title">Fresh Install</h1>
|
<h1 class="title">Fresh Install</h1>
|
||||||
@@ -182,12 +170,21 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="migrationMode === 'clarkson'" class="box content">
|
<div v-if="migrationMode === 'clarkson'" class="box content">
|
||||||
<h1 class="title">Migrate from Clarkson</h1>
|
<h1 class="title">Migrate from Clarkson</h1>
|
||||||
<p>You need to make sure that this deployment of Hammond can access the MySQL database used by Clarkson.</p>
|
|
||||||
<p>If that is not directly possible, you can make a copy of that database somewhere accessible from this instance.</p>
|
|
||||||
<p>Once that is done, enter the connection string to the MySQL instance in the following format.</p>
|
|
||||||
<p
|
<p
|
||||||
>All the users imported from Clarkson will have their username as their email in Clarkson database and pasword set to
|
>You need to make sure that this deployment of Hammond can access the MySQL database used by
|
||||||
<span class="" style="font-weight:bold">hammond</span></p
|
Clarkson.</p
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
>If that is not directly possible, you can make a copy of that database somewhere accessible
|
||||||
|
from this instance.</p
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
>Once that is done, enter the connection string to the MySQL instance in the following
|
||||||
|
format.</p
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
>All the users imported from Clarkson will have their username as their email in Clarkson
|
||||||
|
database and pasword set to <span class="" style="font-weight:bold">hammond</span></p
|
||||||
>
|
>
|
||||||
<code>
|
<code>
|
||||||
user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
|
user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local
|
||||||
@@ -203,8 +200,15 @@ export default {
|
|||||||
</b-field>
|
</b-field>
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<b-button v-if="!testSuccess" type="is-primary" :disabled="isWorking" @click="testConnection">Test Connection</b-button
|
<b-button
|
||||||
><b-button v-if="testSuccess" type="is-success" :disabled="isWorking" @click="migrate">Migrate</b-button>
|
v-if="!testSuccess"
|
||||||
|
type="is-primary"
|
||||||
|
:disabled="isWorking"
|
||||||
|
@click="testConnection"
|
||||||
|
>Test Connection</b-button
|
||||||
|
><b-button v-if="testSuccess" type="is-success" :disabled="isWorking" @click="migrate"
|
||||||
|
>Migrate</b-button
|
||||||
|
>
|
||||||
<b-button type="is-danger is-light" @click="resetMigrationMode">Cancel</b-button>
|
<b-button type="is-danger is-light" @click="resetMigrationMode">Cancel</b-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -218,22 +222,28 @@ export default {
|
|||||||
<b-input v-model="registerModel.email" type="email" required></b-input>
|
<b-input v-model="registerModel.email" type="email" required></b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
<b-field label="Your Password">
|
<b-field label="Your Password">
|
||||||
<b-input v-model="registerModel.password" type="password" required minlength="8" password-reveal></b-input>
|
<b-input
|
||||||
|
v-model="registerModel.password"
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
minlength="8"
|
||||||
|
password-reveal
|
||||||
|
></b-input>
|
||||||
</b-field>
|
</b-field>
|
||||||
<b-field label="Currency">
|
<b-field label="Currency">
|
||||||
<b-autocomplete
|
<b-select v-model="registerModel.currency" placeholder="Currency" required expanded>
|
||||||
v-model="registerModel.currency"
|
<option v-for="option in currencyMasters" :key="option.code" :value="option.code">
|
||||||
:custom-formatter="formatCurrency"
|
{{ `${option.namePlural} (${option.code})` }}
|
||||||
placeholder="Currency"
|
</option>
|
||||||
:data="filteredCurrencyMasters"
|
</b-select>
|
||||||
:keep-first="true"
|
|
||||||
:open-on-focus="true"
|
|
||||||
required
|
|
||||||
@select="(option) => (selected = option)"
|
|
||||||
></b-autocomplete>
|
|
||||||
</b-field>
|
</b-field>
|
||||||
<b-field label="Distance Unit">
|
<b-field label="Distance Unit">
|
||||||
<b-select v-model.number="registerModel.distanceUnit" placeholder="Distance Unit" required expanded>
|
<b-select
|
||||||
|
v-model.number="registerModel.distanceUnit"
|
||||||
|
placeholder="Distance Unit"
|
||||||
|
required
|
||||||
|
expanded
|
||||||
|
>
|
||||||
<option v-for="(option, key) in distanceUnitMasters" :key="key" :value="key">
|
<option v-for="(option, key) in distanceUnitMasters" :key="key" :value="key">
|
||||||
{{ `${option.long} (${option.short})` }}
|
{{ `${option.long} (${option.short})` }}
|
||||||
</option>
|
</option>
|
||||||
|
|||||||
@@ -44,20 +44,6 @@ export default {
|
|||||||
|
|
||||||
return this.changePassModel.new === this.changePassModel.renew
|
return this.changePassModel.new === this.changePassModel.renew
|
||||||
},
|
},
|
||||||
filteredCurrencyMasters() {
|
|
||||||
return this.currencyMasters.filter((option) => {
|
|
||||||
return (
|
|
||||||
option.namePlural
|
|
||||||
.toString()
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(this.settingsModel.currency.toLowerCase()) >= 0 ||
|
|
||||||
option.code
|
|
||||||
.toString()
|
|
||||||
.toLowerCase()
|
|
||||||
.indexOf(this.settingsModel.currency.toLowerCase()) >= 0
|
|
||||||
)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
changePassword() {
|
changePassword() {
|
||||||
@@ -123,9 +109,6 @@ export default {
|
|||||||
this.tryingToSave = false
|
this.tryingToSave = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
formatCurrency(option) {
|
|
||||||
return `${option.namePlural} (${option.code})`
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -140,16 +123,11 @@ export default {
|
|||||||
These will be used as default values whenever you create a new fillup or expense.
|
These will be used as default values whenever you create a new fillup or expense.
|
||||||
</h1>
|
</h1>
|
||||||
<b-field label="Currency">
|
<b-field label="Currency">
|
||||||
<b-autocomplete
|
<b-select v-model="settingsModel.currency" placeholder="Currency" required expanded>
|
||||||
v-model="settingsModel.currency"
|
<option v-for="option in currencyMasters" :key="option.code" :value="option.code">
|
||||||
:custom-formatter="formatCurrency"
|
{{ `${option.namePlural} (${option.code})` }}
|
||||||
placeholder="Currency"
|
</option>
|
||||||
:data="filteredCurrencyMasters"
|
</b-select>
|
||||||
:keep-first="true"
|
|
||||||
:open-on-focus="true"
|
|
||||||
required
|
|
||||||
@select="(option) => (selected = option)"
|
|
||||||
></b-autocomplete>
|
|
||||||
</b-field>
|
</b-field>
|
||||||
<b-field label="Distance Unit">
|
<b-field label="Distance Unit">
|
||||||
<b-select v-model.number="settingsModel.distanceUnit" placeholder="Distance Unit" required expanded>
|
<b-select v-model.number="settingsModel.distanceUnit" placeholder="Distance Unit" required expanded>
|
||||||
|
|||||||
Reference in New Issue
Block a user