Added single user fetch to user api
This commit is contained in:
parent
cd66b5bba5
commit
0a3d759733
12 changed files with 127 additions and 37 deletions
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
<flag v-if="column.showFlag" :tooltip-text="getCellValue(item, column)" :iso="getCellValue(item, column)"></flag>
|
<flag v-if="column.showFlag" :tooltip-text="getCellValue(item, column)" :iso="getCellValue(item, column)"></flag>
|
||||||
<span v-else-if="column.iconResolver == null">{{ getCellValue(item, column) }}</span>
|
<span v-else-if="column.iconResolver == null">{{ getCellValue(item, column) }}</span>
|
||||||
|
<span v-else-if="column.badgeResolver">{{ getCellValue(item, column) }}</span>
|
||||||
<component v-else
|
<component v-else
|
||||||
:is="getCellValue(item, column)"
|
:is="getCellValue(item, column)"
|
||||||
weight="regular"
|
weight="regular"
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@
|
||||||
<div v-if="toast.title" class="toast__title">{{ toast.title }}</div>
|
<div v-if="toast.title" class="toast__title">{{ toast.title }}</div>
|
||||||
<div class="toast__message">{{ toast.message }}</div>
|
<div class="toast__message">{{ toast.message }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="toast.count > 1" class="toast__badge">
|
||||||
|
{{ toast.count }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
</teleport>
|
</teleport>
|
||||||
|
|
@ -49,8 +52,40 @@ export default {
|
||||||
* @param {string} options.variant - Toast variant: 'success', 'error', 'warning', 'info'
|
* @param {string} options.variant - Toast variant: 'success', 'error', 'warning', 'info'
|
||||||
* @param {number} options.duration - Auto-dismiss duration in ms (0 = no auto-dismiss)
|
* @param {number} options.duration - Auto-dismiss duration in ms (0 = no auto-dismiss)
|
||||||
* @param {string} options.icon - Icon name (optional)
|
* @param {string} options.icon - Icon name (optional)
|
||||||
|
* @param {boolean} options.stack - Whether to stack identical toasts (default: true)
|
||||||
*/
|
*/
|
||||||
addToast(options = {}) {
|
addToast(options = {}) {
|
||||||
|
const shouldStack = options.stack !== undefined ? options.stack : true;
|
||||||
|
|
||||||
|
// Check if an identical toast already exists
|
||||||
|
if (shouldStack) {
|
||||||
|
const existingToast = this.toasts.find(t =>
|
||||||
|
t.message === options.message &&
|
||||||
|
t.title === (options.title || null) &&
|
||||||
|
t.variant === this.mapVariant(options.variant || 'primary')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingToast) {
|
||||||
|
// Increment count and reset timer
|
||||||
|
existingToast.count = (existingToast.count || 1) + 1;
|
||||||
|
|
||||||
|
// Clear existing timeout
|
||||||
|
if (existingToast.timeoutId) {
|
||||||
|
clearTimeout(existingToast.timeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set new timeout
|
||||||
|
const duration = options.duration !== undefined ? options.duration : 5000;
|
||||||
|
if (duration > 0) {
|
||||||
|
existingToast.timeoutId = setTimeout(() => {
|
||||||
|
this.removeToast(existingToast.id);
|
||||||
|
}, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingToast.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const toast = {
|
const toast = {
|
||||||
id: this.nextId++,
|
id: this.nextId++,
|
||||||
message: options.message || 'Notification',
|
message: options.message || 'Notification',
|
||||||
|
|
@ -58,13 +93,15 @@ export default {
|
||||||
variant: this.mapVariant(options.variant || 'primary' ),
|
variant: this.mapVariant(options.variant || 'primary' ),
|
||||||
duration: options.duration !== undefined ? options.duration : 5000,
|
duration: options.duration !== undefined ? options.duration : 5000,
|
||||||
icon: options.icon ? `Ph${options.icon.charAt(0).toUpperCase() + options.icon.slice(1)}` : null,
|
icon: options.icon ? `Ph${options.icon.charAt(0).toUpperCase() + options.icon.slice(1)}` : null,
|
||||||
|
count: 1,
|
||||||
|
timeoutId: null
|
||||||
};
|
};
|
||||||
|
|
||||||
this.toasts.push(toast)
|
this.toasts.push(toast)
|
||||||
|
|
||||||
// Auto-dismiss if duration is set
|
// Auto-dismiss if duration is set
|
||||||
if (toast.duration > 0) {
|
if (toast.duration > 0) {
|
||||||
setTimeout(() => {
|
toast.timeoutId = setTimeout(() => {
|
||||||
this.removeToast(toast.id)
|
this.removeToast(toast.id)
|
||||||
}, toast.duration)
|
}, toast.duration)
|
||||||
}
|
}
|
||||||
|
|
@ -94,6 +131,10 @@ export default {
|
||||||
removeToast(id) {
|
removeToast(id) {
|
||||||
const index = this.toasts.findIndex(toast => toast.id === id)
|
const index = this.toasts.findIndex(toast => toast.id === id)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
|
// Clear timeout if exists
|
||||||
|
if (this.toasts[index].timeoutId) {
|
||||||
|
clearTimeout(this.toasts[index].timeoutId);
|
||||||
|
}
|
||||||
this.toasts.splice(index, 1)
|
this.toasts.splice(index, 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -102,6 +143,12 @@ export default {
|
||||||
* Remove all toasts
|
* Remove all toasts
|
||||||
*/
|
*/
|
||||||
clearToasts() {
|
clearToasts() {
|
||||||
|
// Clear all timeouts
|
||||||
|
this.toasts.forEach(toast => {
|
||||||
|
if (toast.timeoutId) {
|
||||||
|
clearTimeout(toast.timeoutId);
|
||||||
|
}
|
||||||
|
});
|
||||||
this.toasts = []
|
this.toasts = []
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -150,12 +197,11 @@ export default {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toast:hover {
|
.toast:hover {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
|
|
||||||
box-shadow: 0 0.5rem 0.9rem rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0.5rem 0.9rem rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,22 +243,50 @@ export default {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toast__badge {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 2.4rem;
|
||||||
|
height: 2.4rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #002F54;
|
||||||
|
color: #5AF0B4;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.toast-primary {
|
.toast-primary {
|
||||||
background-color: #5AF0B4;
|
background-color: #5AF0B4;
|
||||||
color: #002F54;
|
color: #002F54;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toast-primary .toast__badge {
|
||||||
|
background-color: #002F54;
|
||||||
|
color: #5AF0B4;
|
||||||
|
}
|
||||||
|
|
||||||
.toast--secondary {
|
.toast--secondary {
|
||||||
color: #002F54;
|
color: #002F54;
|
||||||
background-color: #c3cfdf;
|
background-color: #c3cfdf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toast--secondary .toast__badge {
|
||||||
|
background-color: #002F54;
|
||||||
|
color: #c3cfdf;
|
||||||
|
}
|
||||||
|
|
||||||
.toast--exception{
|
.toast--exception{
|
||||||
background-color: #BC2B72;
|
background-color: #BC2B72;
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toast--exception .toast__badge {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #BC2B72;
|
||||||
|
}
|
||||||
|
|
||||||
/* Transition animations */
|
/* Transition animations */
|
||||||
.toast-enter-active {
|
.toast-enter-active {
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@
|
||||||
{{ premise.hs_code }}
|
{{ premise.hs_code }}
|
||||||
</div>
|
</div>
|
||||||
<div class="edit-calculation-cell-line edit-calculation-cell-subline"
|
<div class="edit-calculation-cell-line edit-calculation-cell-subline"
|
||||||
v-if="premise.tariff_rate">
|
v-if="(premise.tariff_rate ?? null) !== null">
|
||||||
Tariff rate:
|
Tariff rate:
|
||||||
{{ toPercent(premise.tariff_rate) }} %
|
{{ toPercent(premise.tariff_rate) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ import ModalDialog from "@/components/UI/ModalDialog.vue";
|
||||||
import {mapStores} from "pinia";
|
import {mapStores} from "pinia";
|
||||||
import {useValidityPeriodStore} from "@/store/validityPeriod.js";
|
import {useValidityPeriodStore} from "@/store/validityPeriod.js";
|
||||||
import AutosuggestSearchbar from "@/components/UI/AutoSuggestSearchBar.vue";
|
import AutosuggestSearchbar from "@/components/UI/AutoSuggestSearchBar.vue";
|
||||||
import DataTable from "@/components/UI/DataTable.vue";
|
|
||||||
import TableView from "@/components/UI/TableView.vue";
|
import TableView from "@/components/UI/TableView.vue";
|
||||||
import RadioOption from "@/components/UI/RadioOption.vue";
|
import RadioOption from "@/components/UI/RadioOption.vue";
|
||||||
import {useMatrixRateStore} from "@/store/matrixRate.js";
|
import {useMatrixRateStore} from "@/store/matrixRate.js";
|
||||||
|
|
@ -80,7 +79,7 @@ export default {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
StagedRates,
|
StagedRates,
|
||||||
RadioOption, TableView, DataTable, AutosuggestSearchbar, ModalDialog, Tooltip, IconButton, Dropdown
|
RadioOption, TableView, AutosuggestSearchbar, ModalDialog, Tooltip, IconButton, Dropdown
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useValidityPeriodStore, useMatrixRateStore, useContainerRateStore),
|
...mapStores(useValidityPeriodStore, useMatrixRateStore, useContainerRateStore),
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,7 @@ public class SecurityConfig {
|
||||||
|
|
||||||
} else if (identifyBy.equals("workday") && workdayId != null && !workdayId.isEmpty()) {
|
} else if (identifyBy.equals("workday") && workdayId != null && !workdayId.isEmpty()) {
|
||||||
log.debug("Fetch user by workday id {}", workdayId);
|
log.debug("Fetch user by workday id {}", workdayId);
|
||||||
user = userRepository.getByWorkdayId(workdayId);
|
user = userRepository.getByWorkdayId(workdayId).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* REST Controller for managing user-related operations.
|
* REST Controller for managing user-related operations.
|
||||||
|
|
@ -51,6 +52,22 @@ public class UserController {
|
||||||
.body(users.toList());
|
.body(users.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a single user by its workday id.
|
||||||
|
*
|
||||||
|
* @param workdayId The workday id of the user to retrieve.
|
||||||
|
* @return A ResponseEntity containing the user, along with pagination headers.
|
||||||
|
*/
|
||||||
|
@GetMapping({"/{workdayId}/", "/{workdayId}"})
|
||||||
|
@PreAuthorize("hasRole('RIGHT-MANAGEMENT')")
|
||||||
|
public ResponseEntity<Optional<UserDTO>> getUser(@PathVariable String workdayId) {
|
||||||
|
|
||||||
|
Optional<UserDTO> users = userService.getUser(workdayId);
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.body(users);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the details of an existing user or creates a new one if it does not exist.
|
* Updates the details of an existing user or creates a new one if it does not exist.
|
||||||
* Users are identified by its workday id. If a group from the group membership does not exist
|
* Users are identified by its workday id. If a group from the group membership does not exist
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,6 @@ public class UserDTO {
|
||||||
@JsonProperty("workday_id")
|
@JsonProperty("workday_id")
|
||||||
private String workdayId;
|
private String workdayId;
|
||||||
|
|
||||||
@JsonProperty("is_active")
|
|
||||||
private boolean isActive;
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Size(min = 1)
|
@Size(min = 1)
|
||||||
@JsonProperty("groups")
|
@JsonProperty("groups")
|
||||||
|
|
@ -65,14 +62,6 @@ public class UserDTO {
|
||||||
this.workdayId = workdayId;
|
this.workdayId = workdayId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isActive() {
|
|
||||||
return isActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setActive(boolean active) {
|
|
||||||
isActive = active;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getGroups() {
|
public List<String> getGroups() {
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import java.sql.Statement;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public class UserRepository {
|
public class UserRepository {
|
||||||
|
|
@ -145,12 +146,12 @@ public class UserRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public User getByWorkdayId(String workdayId) {
|
public Optional<User> getByWorkdayId(String workdayId) {
|
||||||
List<User> results = jdbcTemplate.query("SELECT * FROM sys_user WHERE workday_id = ?",
|
List<User> results = jdbcTemplate.query("SELECT * FROM sys_user WHERE workday_id = ?",
|
||||||
new UserMapper(),
|
new UserMapper(),
|
||||||
workdayId);
|
workdayId);
|
||||||
|
|
||||||
return results.isEmpty() ? null : results.getFirst();
|
return results.isEmpty() ? Optional.empty() : Optional.of(results.getFirst());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ public class UserTransformer {
|
||||||
public UserDTO toUserDTO(User entity) {
|
public UserDTO toUserDTO(User entity) {
|
||||||
UserDTO dto = new UserDTO();
|
UserDTO dto = new UserDTO();
|
||||||
|
|
||||||
dto.setActive(entity.getActive());
|
|
||||||
dto.setEmail(entity.getEmail());
|
dto.setEmail(entity.getEmail());
|
||||||
dto.setFirstName(entity.getFirstName());
|
dto.setFirstName(entity.getFirstName());
|
||||||
dto.setLastName(entity.getLastName());
|
dto.setLastName(entity.getLastName());
|
||||||
|
|
@ -25,7 +24,7 @@ public class UserTransformer {
|
||||||
public User fromUserDTO(UserDTO dto) {
|
public User fromUserDTO(UserDTO dto) {
|
||||||
User entity = new User();
|
User entity = new User();
|
||||||
|
|
||||||
entity.setActive(dto.isActive());
|
entity.setActive(true);
|
||||||
entity.setEmail(dto.getEmail());
|
entity.setEmail(dto.getEmail());
|
||||||
entity.setFirstName(dto.getFirstName());
|
entity.setFirstName(dto.getFirstName());
|
||||||
entity.setLastName(dto.getLastName());
|
entity.setLastName(dto.getLastName());
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service class responsible for handling business logic related to users.
|
* Service class responsible for handling business logic related to users.
|
||||||
* Provides methods to retrieve and update user information.
|
* Provides methods to retrieve and update user information.
|
||||||
|
|
@ -38,6 +40,16 @@ public class UserService {
|
||||||
return SearchQueryResult.map(userRepository.listUsers(new SearchQueryPagination(page, limit)), userTransformer::toUserDTO);
|
return SearchQueryResult.map(userRepository.listUsers(new SearchQueryPagination(page, limit)), userTransformer::toUserDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a single user by its workday id.
|
||||||
|
*
|
||||||
|
* @param workdayId The workday id of the user to retrieve.
|
||||||
|
* @return A ResponseEntity containing the user, along with pagination headers.
|
||||||
|
*/
|
||||||
|
public Optional<UserDTO> getUser(String workdayId) {
|
||||||
|
return userRepository.getByWorkdayId(workdayId).map(userTransformer::toUserDTO);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an existing user's information.
|
* Updates an existing user's information.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,6 @@ spring.sql.init.mode=never
|
||||||
lcc.allowed_cors=
|
lcc.allowed_cors=
|
||||||
lcc.allowed_oauth_token_cors=*
|
lcc.allowed_oauth_token_cors=*
|
||||||
|
|
||||||
logging.level.org.springframework.ws=DEBUG
|
|
||||||
logging.level.org.springframework.oxm=DEBUG
|
|
||||||
|
|
||||||
lcc.auth.identify.by=workday
|
lcc.auth.identify.by=workday
|
||||||
lcc.auth.claim.workday=employeeid
|
lcc.auth.claim.workday=employeeid
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('none', 'no rights');
|
VALUES ('none', 'no rights');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('basic', 'Login, generate reports');
|
VALUES ('basic', 'can generate reports');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('calculation', 'Login, generate reports, do calculations');
|
VALUES ('calculation', 'can generate reports, do calculations');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('freight', 'Login, generate reports, edit freight rates');
|
VALUES ('freight', 'manage freight rates');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('packaging', 'Login, generate reports, edit packaging data');
|
VALUES ('packaging', 'manage packaging data');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('material', 'Login, generate reports, edit material data');
|
VALUES ('material', 'manage material data');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('super',
|
VALUES ('super',
|
||||||
'Login, generate reports, do calculations, edit freight rates, edit packaging data');
|
'can generate reports, do calculations, manage freight rates, manage packaging data, manage material data, manage general system settings');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('service', 'Register API Tokens');
|
VALUES ('service', 'register external applications');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('right-management',
|
VALUES ('right-management',
|
||||||
'Add/Remove users, groups, etc.');
|
'add users, manage user groups');
|
||||||
Loading…
Add table
Reference in a new issue